keyboard.dart 3.8 KB

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