diff --git a/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md b/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md index ed0f257ad0..67b14cb9e7 100644 --- a/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md +++ b/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md @@ -16,7 +16,7 @@ Widget build(BuildContext context) { alignment: Alignment.topCenter, child: AppFlowyEditor( editorState: EditorState.empty(), - keyEventHandlers: const [], + shortcutEvents: const [], ), ), ); @@ -27,19 +27,26 @@ At this point, nothing magic will happen after typing `_xxx_`. ![Before](./images/customizing_a_shortcut_event_before.gif) -To implement our shortcut event we will create a function to handle an underscore input. +To implement our shortcut event we will create a `ShortcutEvent` instance to handle an underscore input. + +We need to define `key` and `command` in a ShortCutEvent object to customize hotkeys. We recommend using the description of your event as a key. For example, if the underscore `_` is defined to make text italic, the key can be 'Underscore to italic'. + +> The command, made up of a single keyword such as `underscore` or a combination of keywords using the `+` sign in between to concatenate, is a condition that triggers a user-defined function. To see which keywords are available to define a command, please refer to [key_mapping.dart](../lib/src/service/shortcut_event/key_mapping.dart). +> If more than one commands trigger the same handler, then we use ',' to split them. For example, using CTRL and A or CMD and A to 'select all', we describe it as `cmd+a,ctrl+a`(case-insensitive). ```dart import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) { - // Since we only need to handle the input of an 'underscore' character, - // all inputs except `underscore` will be ignored immediately. - if (event.logicalKey != LogicalKeyboardKey.underscore) { - return KeyEventResult.ignored; - } +ShortcutEvent underscoreToItalicEvent = ShortcutEvent( + key: 'Underscore to italic', + command: 'underscore', + handler: _underscoreToItalicHandler, +); + +ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) { + }; ``` @@ -49,9 +56,7 @@ If so, we will continue. ```dart // ... -FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) { - // ... - +ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) { // Obtain the selection and selected nodes of the current document through the 'selectionService' // to determine whether the selection is collapsed and whether the selected node is a text node. final selectionService = editorState.service.selectionService; @@ -70,7 +75,7 @@ Look for the position of the previous underscore and ```dart // ... -FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) { +ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) { // ... final textNode = textNodes.first; @@ -111,8 +116,8 @@ Widget build(BuildContext context) { alignment: Alignment.topCenter, child: AppFlowyEditor( editorState: EditorState.empty(), - keyEventHandlers: [ - underscoreToItalicHandler, + shortcutEvents: [ + _underscoreToItalicHandler, ], ), ), diff --git a/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic_key_event_handler.dart b/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic_key_event_handler.dart index 13ee27af05..c55bfa56bb 100644 --- a/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic_key_event_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic_key_event_handler.dart @@ -1,20 +1,13 @@ import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; ShortcutEvent underscoreToItalicEvent = ShortcutEvent( key: 'Underscore to italic', - command: 'shift+underscore', + command: 'underscore', handler: _underscoreToItalicHandler, ); ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) { - // Since we only need to handler the input of `underscore`. - // All inputs except `underscore` will be ignored directly. - if (event.logicalKey != LogicalKeyboardKey.underscore) { - return KeyEventResult.ignored; - } - // Obtaining the selection and selected nodes of the current document through `selectionService`, // and determine whether it is a single selection and whether the selected node is a text node. final selectionService = editorState.service.selectionService; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event.dart index 444f797ecd..ae64b1635c 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event.dart @@ -14,7 +14,7 @@ class ShortcutEvent { String? linuxCommand, }) { updateCommand( - command, + command: command, windowsCommand: windowsCommand, macOSCommand: macOSCommand, linuxCommand: linuxCommand, @@ -46,35 +46,43 @@ class ShortcutEvent { final ShortcutEventHandler handler; - List keybindings = []; + List get keybindings => _keybindings; + List _keybindings = []; - void updateCommand( - String command, { + void updateCommand({ + String? command, String? windowsCommand, String? macOSCommand, String? linuxCommand, }) { + var matched = false; if (Platform.isWindows && windowsCommand != null && windowsCommand.isNotEmpty) { this.command = windowsCommand; + matched = true; } else if (Platform.isMacOS && macOSCommand != null && macOSCommand.isNotEmpty) { this.command = macOSCommand; + matched = true; } else if (Platform.isLinux && linuxCommand != null && linuxCommand.isNotEmpty) { this.command = linuxCommand; - } else { + matched = true; + } else if (command != null && command.isNotEmpty) { this.command = command; + matched = true; } - keybindings = this - .command - .split(',') - .map((e) => Keybinding.parse(e)) - .toList(growable: false); + if (matched) { + _keybindings = this + .command + .split(',') + .map((e) => Keybinding.parse(e)) + .toList(growable: false); + } } ShortcutEvent copyWith({ diff --git a/frontend/app_flowy/packages/appflowy_editor/test/service/shortcut_event/shortcut_event_test.dart b/frontend/app_flowy/packages/appflowy_editor/test/service/shortcut_event/shortcut_event_test.dart index 1a479ad086..93a0a7bb84 100644 --- a/frontend/app_flowy/packages/appflowy_editor/test/service/shortcut_event/shortcut_event_test.dart +++ b/frontend/app_flowy/packages/appflowy_editor/test/service/shortcut_event/shortcut_event_test.dart @@ -21,7 +21,7 @@ void main() async { return KeyEventResult.handled; }, ); - shortcutEvent.updateCommand('cmd+shift+alt+ctrl+b'); + shortcutEvent.updateCommand(command: 'cmd+shift+alt+ctrl+b'); expect(shortcutEvent.keybindings.length, 1); expect(shortcutEvent.keybindings.first.isMetaPressed, true); expect(shortcutEvent.keybindings.first.isShiftPressed, true); @@ -57,15 +57,26 @@ void main() async { await editor.updateSelection( Selection.single(path: [1], startOffset: text.length), ); + for (final event in builtInShortcutEvents) { if (event.key == 'Move cursor begin') { - event.updateCommand('alt+arrow left'); + event.updateCommand( + windowsCommand: 'alt+arrow left', + macOSCommand: 'alt+arrow left', + ); } } - await editor.pressLogicKey( - LogicalKeyboardKey.arrowLeft, - isAltPressed: true, - ); + if (Platform.isWindows || Platform.isMacOS) { + await editor.pressLogicKey( + LogicalKeyboardKey.arrowLeft, + isAltPressed: true, + ); + } else { + await editor.pressLogicKey( + LogicalKeyboardKey.arrowLeft, + isMetaPressed: true, + ); + } expect( editor.documentSelection, Selection.single(path: [1], startOffset: 0),