keyboard.dart 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import 'package:flutter/foundation.dart';
  2. import 'package:flutter/services.dart';
  3. /* --------------------------------- Typedef -------------------------------- */
  4. enum InputShortcut {
  5. CUT,
  6. COPY,
  7. PASTE,
  8. SELECT_ALL,
  9. SAVE,
  10. }
  11. typedef CursorMoveCallback = void Function(
  12. LogicalKeyboardKey key,
  13. bool wordModifier,
  14. bool lineModifier,
  15. bool shift,
  16. );
  17. typedef InputShortcutCallback = void Function(
  18. InputShortcut? shortcut,
  19. );
  20. typedef OnDeleteCallback = void Function(
  21. bool forward,
  22. );
  23. /* -------------------------------- Listener -------------------------------- */
  24. class KeyboardListener {
  25. KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete);
  26. final CursorMoveCallback onCursorMove;
  27. final InputShortcutCallback onShortcut;
  28. final OnDeleteCallback onDelete;
  29. static final Set<LogicalKeyboardKey> _moveKeys = {
  30. LogicalKeyboardKey.arrowUp,
  31. LogicalKeyboardKey.arrowDown,
  32. LogicalKeyboardKey.arrowLeft,
  33. LogicalKeyboardKey.arrowRight,
  34. };
  35. static final Set<LogicalKeyboardKey> _shortcutKeys = {
  36. LogicalKeyboardKey.keyA,
  37. LogicalKeyboardKey.keyC,
  38. LogicalKeyboardKey.keyV,
  39. LogicalKeyboardKey.keyX,
  40. LogicalKeyboardKey.keyS,
  41. LogicalKeyboardKey.delete,
  42. LogicalKeyboardKey.backspace,
  43. };
  44. static final Set<LogicalKeyboardKey> _nonModifierKeys = {
  45. ..._moveKeys,
  46. ..._shortcutKeys,
  47. };
  48. static final Set<LogicalKeyboardKey> _winModifierKeys = {
  49. LogicalKeyboardKey.control,
  50. LogicalKeyboardKey.alt,
  51. LogicalKeyboardKey.shift,
  52. };
  53. static final Set<LogicalKeyboardKey> _osxModifierKeys = {
  54. LogicalKeyboardKey.meta,
  55. LogicalKeyboardKey.alt,
  56. LogicalKeyboardKey.shift,
  57. };
  58. static final Set<LogicalKeyboardKey> _interestingKeys = {
  59. ..._winModifierKeys,
  60. ..._osxModifierKeys,
  61. ..._nonModifierKeys,
  62. };
  63. static final Map<LogicalKeyboardKey, InputShortcut> _keyToShortcut = {
  64. LogicalKeyboardKey.keyX: InputShortcut.CUT,
  65. LogicalKeyboardKey.keyC: InputShortcut.COPY,
  66. LogicalKeyboardKey.keyV: InputShortcut.PASTE,
  67. LogicalKeyboardKey.keyA: InputShortcut.SELECT_ALL,
  68. LogicalKeyboardKey.keyS: InputShortcut.SAVE,
  69. };
  70. bool handleRawKeyEvent(RawKeyEvent event) {
  71. if (kIsWeb) {
  72. // On web platform, we should ignore the key because it's processed already.
  73. return false;
  74. }
  75. if (event is! RawKeyDownEvent) {
  76. return false;
  77. }
  78. final keysPressed = LogicalKeyboardKey.collapseSynonyms(RawKeyboard.instance.keysPressed);
  79. final key = event.logicalKey;
  80. final isMacOS = event.data is RawKeyEventDataMacOs;
  81. final modifierKeys = isMacOS ? _osxModifierKeys : _winModifierKeys;
  82. // If any one of below cases is hitten:
  83. // 1. None of the nonModifierKeys is pressed
  84. // 2. Press the key except the keys that trigger shortcut
  85. // We will skip this event
  86. if (!_nonModifierKeys.contains(key) ||
  87. keysPressed.difference(modifierKeys).length > 1 ||
  88. keysPressed.difference(_interestingKeys).isNotEmpty) {
  89. return false;
  90. }
  91. if (_isCursorMoveAction(key)) {
  92. onCursorMove(
  93. key,
  94. isMacOS ? event.isAltPressed : event.isControlPressed,
  95. isMacOS ? event.isMetaPressed : event.isAltPressed,
  96. event.isShiftPressed,
  97. );
  98. return true;
  99. } else if (_isShortcutAction(event, key)) {
  100. onShortcut(_keyToShortcut[key]);
  101. return true;
  102. } else if (LogicalKeyboardKey.delete == key) {
  103. onDelete(true);
  104. return true;
  105. } else if (LogicalKeyboardKey.backspace == key) {
  106. onDelete(false);
  107. return true;
  108. }
  109. return false;
  110. }
  111. // Helper
  112. bool _isCursorMoveAction(LogicalKeyboardKey key) => _moveKeys.contains(key);
  113. bool _isShortcutAction(RawKeyEvent event, LogicalKeyboardKey key) {
  114. if (!_shortcutKeys.contains(key)) {
  115. return false;
  116. }
  117. if (event.data is RawKeyEventDataMacOs) {
  118. return event.isMetaPressed;
  119. } else {
  120. return event.isControlPressed;
  121. }
  122. }
  123. }