1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | /// @docImport 'app.dart'; |
6 | library; |
7 | |
8 | import 'package:flutter/foundation.dart'; |
9 | import 'package:flutter/painting.dart'; |
10 | import 'package:flutter/services.dart'; |
11 | |
12 | import 'actions.dart'; |
13 | import 'focus_traversal.dart'; |
14 | import 'framework.dart'; |
15 | import 'scrollable_helpers.dart'; |
16 | import 'shortcuts.dart'; |
17 | import 'text_editing_intents.dart'; |
18 | |
19 | /// A widget with the shortcuts used for the default text editing behavior. |
20 | /// |
21 | /// This default behavior can be overridden by placing a [Shortcuts] widget |
22 | /// lower in the widget tree than this. See the [Action] class for an example |
23 | /// of remapping an [Intent] to a custom [Action]. |
24 | /// |
25 | /// The [Shortcuts] widget usually takes precedence over system keybindings. |
26 | /// Proceed with caution if the shortcut you wish to override is also used by |
27 | /// the system. For example, overriding [LogicalKeyboardKey.backspace] could |
28 | /// cause CJK input methods to discard more text than they should when the |
29 | /// backspace key is pressed during text composition on iOS. |
30 | /// |
31 | /// {@macro flutter.widgets.editableText.shortcutsAndTextInput} |
32 | /// |
33 | /// {@tool snippet} |
34 | /// |
35 | /// This example shows how to use an additional [Shortcuts] widget to override |
36 | /// some default text editing keyboard shortcuts to have new behavior. Instead |
37 | /// of moving the cursor, alt + up/down will change the focused widget. |
38 | /// |
39 | /// ```dart |
40 | /// @override |
41 | /// Widget build(BuildContext context) { |
42 | /// // If using WidgetsApp or its descendants MaterialApp or CupertinoApp, |
43 | /// // then DefaultTextEditingShortcuts is already being inserted into the |
44 | /// // widget tree. |
45 | /// return const DefaultTextEditingShortcuts( |
46 | /// child: Center( |
47 | /// child: Shortcuts( |
48 | /// shortcuts: <ShortcutActivator, Intent>{ |
49 | /// SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): NextFocusIntent(), |
50 | /// SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): PreviousFocusIntent(), |
51 | /// }, |
52 | /// child: Column( |
53 | /// children: <Widget>[ |
54 | /// TextField( |
55 | /// decoration: InputDecoration( |
56 | /// hintText: 'alt + down moves to the next field.', |
57 | /// ), |
58 | /// ), |
59 | /// TextField( |
60 | /// decoration: InputDecoration( |
61 | /// hintText: 'And alt + up moves to the previous.', |
62 | /// ), |
63 | /// ), |
64 | /// ], |
65 | /// ), |
66 | /// ), |
67 | /// ), |
68 | /// ); |
69 | /// } |
70 | /// ``` |
71 | /// {@end-tool} |
72 | /// |
73 | /// {@tool snippet} |
74 | /// |
75 | /// This example shows how to use an additional [Shortcuts] widget to override |
76 | /// default text editing shortcuts to have completely custom behavior defined by |
77 | /// a custom Intent and Action. Here, the up/down arrow keys increment/decrement |
78 | /// a counter instead of moving the cursor. |
79 | /// |
80 | /// ```dart |
81 | /// class IncrementCounterIntent extends Intent {} |
82 | /// class DecrementCounterIntent extends Intent {} |
83 | /// |
84 | /// class MyWidget extends StatefulWidget { |
85 | /// const MyWidget({ super.key }); |
86 | /// |
87 | /// @override |
88 | /// MyWidgetState createState() => MyWidgetState(); |
89 | /// } |
90 | /// |
91 | /// class MyWidgetState extends State<MyWidget> { |
92 | /// |
93 | /// int _counter = 0; |
94 | /// |
95 | /// @override |
96 | /// Widget build(BuildContext context) { |
97 | /// // If using WidgetsApp or its descendants MaterialApp or CupertinoApp, |
98 | /// // then DefaultTextEditingShortcuts is already being inserted into the |
99 | /// // widget tree. |
100 | /// return DefaultTextEditingShortcuts( |
101 | /// child: Center( |
102 | /// child: Column( |
103 | /// mainAxisAlignment: MainAxisAlignment.center, |
104 | /// children: <Widget>[ |
105 | /// const Text( |
106 | /// 'You have pushed the button this many times:', |
107 | /// ), |
108 | /// Text( |
109 | /// '$_counter', |
110 | /// style: Theme.of(context).textTheme.headlineMedium, |
111 | /// ), |
112 | /// Shortcuts( |
113 | /// shortcuts: <ShortcutActivator, Intent>{ |
114 | /// const SingleActivator(LogicalKeyboardKey.arrowUp): IncrementCounterIntent(), |
115 | /// const SingleActivator(LogicalKeyboardKey.arrowDown): DecrementCounterIntent(), |
116 | /// }, |
117 | /// child: Actions( |
118 | /// actions: <Type, Action<Intent>>{ |
119 | /// IncrementCounterIntent: CallbackAction<IncrementCounterIntent>( |
120 | /// onInvoke: (IncrementCounterIntent intent) { |
121 | /// setState(() { |
122 | /// _counter++; |
123 | /// }); |
124 | /// return null; |
125 | /// }, |
126 | /// ), |
127 | /// DecrementCounterIntent: CallbackAction<DecrementCounterIntent>( |
128 | /// onInvoke: (DecrementCounterIntent intent) { |
129 | /// setState(() { |
130 | /// _counter--; |
131 | /// }); |
132 | /// return null; |
133 | /// }, |
134 | /// ), |
135 | /// }, |
136 | /// child: const TextField( |
137 | /// maxLines: 2, |
138 | /// decoration: InputDecoration( |
139 | /// hintText: 'Up/down increment/decrement here.', |
140 | /// ), |
141 | /// ), |
142 | /// ), |
143 | /// ), |
144 | /// const TextField( |
145 | /// maxLines: 2, |
146 | /// decoration: InputDecoration( |
147 | /// hintText: 'Up/down behave normally here.', |
148 | /// ), |
149 | /// ), |
150 | /// ], |
151 | /// ), |
152 | /// ), |
153 | /// ); |
154 | /// } |
155 | /// } |
156 | /// ``` |
157 | /// {@end-tool} |
158 | /// |
159 | /// See also: |
160 | /// |
161 | /// * [WidgetsApp], which creates a DefaultTextEditingShortcuts. |
162 | class DefaultTextEditingShortcuts extends StatelessWidget { |
163 | /// Creates a [DefaultTextEditingShortcuts] widget that provides the default text editing |
164 | /// shortcuts on the current platform. |
165 | const DefaultTextEditingShortcuts({ |
166 | super.key, |
167 | required this.child, |
168 | }); |
169 | |
170 | /// {@macro flutter.widgets.ProxyWidget.child} |
171 | final Widget child; |
172 | |
173 | // These shortcuts are shared between all platforms except Apple platforms, |
174 | // because they use different modifier keys as the line/word modifier. |
175 | static final Map<ShortcutActivator, Intent> _commonShortcuts = <ShortcutActivator, Intent>{ |
176 | // Delete Shortcuts. |
177 | for (final bool pressShift in const <bool>[true, false]) |
178 | ...<SingleActivator, Intent>{ |
179 | SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift): const DeleteCharacterIntent(forward: false), |
180 | SingleActivator(LogicalKeyboardKey.backspace, control: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: false), |
181 | SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: pressShift): const DeleteToLineBreakIntent(forward: false), |
182 | SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): const DeleteCharacterIntent(forward: true), |
183 | SingleActivator(LogicalKeyboardKey.delete, control: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: true), |
184 | SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: pressShift): const DeleteToLineBreakIntent(forward: true), |
185 | }, |
186 | |
187 | // Arrow: Move selection. |
188 | const SingleActivator(LogicalKeyboardKey.arrowLeft): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), |
189 | const SingleActivator(LogicalKeyboardKey.arrowRight): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), |
190 | const SingleActivator(LogicalKeyboardKey.arrowUp): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), |
191 | const SingleActivator(LogicalKeyboardKey.arrowDown): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), |
192 | |
193 | // Shift + Arrow: Extend selection. |
194 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: false), |
195 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: false), |
196 | const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), |
197 | const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), |
198 | |
199 | const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), |
200 | const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), |
201 | const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), |
202 | const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), |
203 | |
204 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false), |
205 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false), |
206 | const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: false), |
207 | const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: false), |
208 | |
209 | const SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: true), |
210 | const SingleActivator(LogicalKeyboardKey.arrowRight, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: true), |
211 | |
212 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: false), |
213 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: false), |
214 | |
215 | const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, control: true): const ExtendSelectionToNextParagraphBoundaryIntent(forward: false, collapseSelection: false), |
216 | const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, control: true): const ExtendSelectionToNextParagraphBoundaryIntent(forward: true, collapseSelection: false), |
217 | |
218 | // Page Up / Down: Move selection by page. |
219 | const SingleActivator(LogicalKeyboardKey.pageUp): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: true), |
220 | const SingleActivator(LogicalKeyboardKey.pageDown): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: true), |
221 | |
222 | // Shift + Page Up / Down: Extend selection by page. |
223 | const SingleActivator(LogicalKeyboardKey.pageUp, shift: true): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: false), |
224 | const SingleActivator(LogicalKeyboardKey.pageDown, shift: true): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: false), |
225 | |
226 | const SingleActivator(LogicalKeyboardKey.keyX, control: true): const CopySelectionTextIntent.cut(SelectionChangedCause.keyboard), |
227 | const SingleActivator(LogicalKeyboardKey.keyC, control: true): CopySelectionTextIntent.copy, |
228 | const SingleActivator(LogicalKeyboardKey.keyV, control: true): const PasteTextIntent(SelectionChangedCause.keyboard), |
229 | const SingleActivator(LogicalKeyboardKey.keyA, control: true): const SelectAllTextIntent(SelectionChangedCause.keyboard), |
230 | const SingleActivator(LogicalKeyboardKey.keyZ, control: true): const UndoTextIntent(SelectionChangedCause.keyboard), |
231 | const SingleActivator(LogicalKeyboardKey.keyZ, shift: true, control: true): const RedoTextIntent(SelectionChangedCause.keyboard), |
232 | // These keys should go to the IME when a field is focused, not to other |
233 | // Shortcuts. |
234 | const SingleActivator(LogicalKeyboardKey.space): const DoNothingAndStopPropagationTextIntent(), |
235 | const SingleActivator(LogicalKeyboardKey.enter): const DoNothingAndStopPropagationTextIntent(), |
236 | }; |
237 | |
238 | // The following key combinations have no effect on text editing on this |
239 | // platform: |
240 | // * End |
241 | // * Home |
242 | // * Meta + X |
243 | // * Meta + C |
244 | // * Meta + V |
245 | // * Meta + A |
246 | // * Meta + shift? + Z |
247 | // * Meta + shift? + arrow down |
248 | // * Meta + shift? + arrow left |
249 | // * Meta + shift? + arrow right |
250 | // * Meta + shift? + arrow up |
251 | // * Shift + end |
252 | // * Shift + home |
253 | // * Meta + shift? + delete |
254 | // * Meta + shift? + backspace |
255 | static final Map<ShortcutActivator, Intent> _androidShortcuts = _commonShortcuts; |
256 | |
257 | static final Map<ShortcutActivator, Intent> _fuchsiaShortcuts = _androidShortcuts; |
258 | |
259 | static final Map<ShortcutActivator, Intent> _linuxNumpadShortcuts = <ShortcutActivator, Intent>{ |
260 | // When numLock is on, numpad keys shortcuts require shift to be pressed too. |
261 | const SingleActivator(LogicalKeyboardKey.numpad6, shift: true, numLock: LockState.locked): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: false), |
262 | const SingleActivator(LogicalKeyboardKey.numpad4, shift: true, numLock: LockState.locked): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: false), |
263 | const SingleActivator(LogicalKeyboardKey.numpad8, shift: true, numLock: LockState.locked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), |
264 | const SingleActivator(LogicalKeyboardKey.numpad2, shift: true, numLock: LockState.locked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), |
265 | |
266 | const SingleActivator(LogicalKeyboardKey.numpad6, shift: true, control: true, numLock: LockState.locked): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: false), |
267 | const SingleActivator(LogicalKeyboardKey.numpad4, shift: true, control: true, numLock: LockState.locked): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: false), |
268 | const SingleActivator(LogicalKeyboardKey.numpad8, shift: true, control: true, numLock: LockState.locked): const ExtendSelectionToNextParagraphBoundaryIntent(forward: false, collapseSelection: false), |
269 | const SingleActivator(LogicalKeyboardKey.numpad2, shift: true, control: true, numLock: LockState.locked): const ExtendSelectionToNextParagraphBoundaryIntent(forward: true, collapseSelection: false), |
270 | |
271 | const SingleActivator(LogicalKeyboardKey.numpad9, shift: true, numLock: LockState.locked): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: false), |
272 | const SingleActivator(LogicalKeyboardKey.numpad3, shift: true, numLock: LockState.locked): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: false), |
273 | |
274 | const SingleActivator(LogicalKeyboardKey.numpad7, shift: true, numLock: LockState.locked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), |
275 | const SingleActivator(LogicalKeyboardKey.numpad1, shift: true, numLock: LockState.locked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), |
276 | |
277 | const SingleActivator(LogicalKeyboardKey.numpadDecimal, shift: true, numLock: LockState.locked): const DeleteCharacterIntent(forward: true), |
278 | const SingleActivator(LogicalKeyboardKey.numpadDecimal, shift: true, control: true, numLock: LockState.locked): const DeleteToNextWordBoundaryIntent(forward: true), |
279 | |
280 | // When numLock is off, numpad keys shortcuts require shift not to be pressed. |
281 | const SingleActivator(LogicalKeyboardKey.numpad6, numLock: LockState.unlocked): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), |
282 | const SingleActivator(LogicalKeyboardKey.numpad4, numLock: LockState.unlocked): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), |
283 | const SingleActivator(LogicalKeyboardKey.numpad8, numLock: LockState.unlocked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), |
284 | const SingleActivator(LogicalKeyboardKey.numpad2, numLock: LockState.unlocked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), |
285 | |
286 | const SingleActivator(LogicalKeyboardKey.numpad6, control: true, numLock: LockState.unlocked): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: true), |
287 | const SingleActivator(LogicalKeyboardKey.numpad4, control: true, numLock: LockState.unlocked): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: true), |
288 | const SingleActivator(LogicalKeyboardKey.numpad8, control: true, numLock: LockState.unlocked): const ExtendSelectionToNextParagraphBoundaryIntent(forward: false, collapseSelection: true), |
289 | const SingleActivator(LogicalKeyboardKey.numpad2, control: true, numLock: LockState.unlocked): const ExtendSelectionToNextParagraphBoundaryIntent(forward: true, collapseSelection: true), |
290 | |
291 | const SingleActivator(LogicalKeyboardKey.numpad9, numLock: LockState.unlocked): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: true), |
292 | const SingleActivator(LogicalKeyboardKey.numpad3, numLock: LockState.unlocked): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: true), |
293 | |
294 | const SingleActivator(LogicalKeyboardKey.numpad7, numLock: LockState.unlocked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), |
295 | const SingleActivator(LogicalKeyboardKey.numpad1, numLock: LockState.unlocked): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), |
296 | |
297 | const SingleActivator(LogicalKeyboardKey.numpadDecimal, numLock: LockState.unlocked): const DeleteCharacterIntent(forward: true), |
298 | const SingleActivator(LogicalKeyboardKey.numpadDecimal, control: true, numLock: LockState.unlocked): const DeleteToNextWordBoundaryIntent(forward: true), |
299 | }; |
300 | |
301 | static final Map<ShortcutActivator, Intent> _linuxShortcuts = <ShortcutActivator, Intent>{ |
302 | ..._commonShortcuts, |
303 | ..._linuxNumpadShortcuts, |
304 | const SingleActivator(LogicalKeyboardKey.home): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), |
305 | const SingleActivator(LogicalKeyboardKey.end): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), |
306 | const SingleActivator(LogicalKeyboardKey.home, shift: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false), |
307 | const SingleActivator(LogicalKeyboardKey.end, shift: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false), |
308 | // The following key combinations have no effect on text editing on this |
309 | // platform: |
310 | // * Control + shift? + end |
311 | // * Control + shift? + home |
312 | // * Meta + X |
313 | // * Meta + C |
314 | // * Meta + V |
315 | // * Meta + A |
316 | // * Meta + shift? + Z |
317 | // * Meta + shift? + arrow down |
318 | // * Meta + shift? + arrow left |
319 | // * Meta + shift? + arrow right |
320 | // * Meta + shift? + arrow up |
321 | // * Meta + shift? + delete |
322 | // * Meta + shift? + backspace |
323 | }; |
324 | |
325 | // macOS document shortcuts: https://support.apple.com/en-us/HT201236. |
326 | // The macOS shortcuts uses different word/line modifiers than most other |
327 | // platforms. |
328 | static final Map<ShortcutActivator, Intent> _macShortcuts = <ShortcutActivator, Intent>{ |
329 | for (final bool pressShift in const <bool>[true, false]) |
330 | ...<SingleActivator, Intent>{ |
331 | SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift): const DeleteCharacterIntent(forward: false), |
332 | SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: false), |
333 | SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: pressShift): const DeleteToLineBreakIntent(forward: false), |
334 | SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): const DeleteCharacterIntent(forward: true), |
335 | SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: true), |
336 | SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: pressShift): const DeleteToLineBreakIntent(forward: true), |
337 | }, |
338 | |
339 | const SingleActivator(LogicalKeyboardKey.arrowLeft): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), |
340 | const SingleActivator(LogicalKeyboardKey.arrowRight): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), |
341 | const SingleActivator(LogicalKeyboardKey.arrowUp): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), |
342 | const SingleActivator(LogicalKeyboardKey.arrowDown): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), |
343 | |
344 | // Shift + Arrow: Extend selection. |
345 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: false), |
346 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: false), |
347 | const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), |
348 | const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), |
349 | |
350 | const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: true), |
351 | const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: true), |
352 | const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), |
353 | const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), |
354 | |
355 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): const ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: false), |
356 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): const ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: true), |
357 | const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): const ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent(forward: false), |
358 | const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): const ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent(forward: true), |
359 | |
360 | const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), |
361 | const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), |
362 | const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), |
363 | const SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), |
364 | |
365 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): const ExpandSelectionToLineBreakIntent(forward: false), |
366 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): const ExpandSelectionToLineBreakIntent(forward: true), |
367 | const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): const ExpandSelectionToDocumentBoundaryIntent(forward: false), |
368 | const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): const ExpandSelectionToDocumentBoundaryIntent(forward: true), |
369 | |
370 | const SingleActivator(LogicalKeyboardKey.keyT, control: true): const TransposeCharactersIntent(), |
371 | |
372 | const SingleActivator(LogicalKeyboardKey.home): const ScrollToDocumentBoundaryIntent(forward: false), |
373 | const SingleActivator(LogicalKeyboardKey.end): const ScrollToDocumentBoundaryIntent(forward: true), |
374 | const SingleActivator(LogicalKeyboardKey.home, shift: true): const ExpandSelectionToDocumentBoundaryIntent(forward: false), |
375 | const SingleActivator(LogicalKeyboardKey.end, shift: true): const ExpandSelectionToDocumentBoundaryIntent(forward: true), |
376 | |
377 | const SingleActivator(LogicalKeyboardKey.pageUp): const ScrollIntent(direction: AxisDirection.up, type: ScrollIncrementType.page), |
378 | const SingleActivator(LogicalKeyboardKey.pageDown): const ScrollIntent(direction: AxisDirection.down, type: ScrollIncrementType.page), |
379 | const SingleActivator(LogicalKeyboardKey.pageUp, shift: true): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: false), |
380 | const SingleActivator(LogicalKeyboardKey.pageDown, shift: true): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: false), |
381 | |
382 | const SingleActivator(LogicalKeyboardKey.keyX, meta: true): const CopySelectionTextIntent.cut(SelectionChangedCause.keyboard), |
383 | const SingleActivator(LogicalKeyboardKey.keyC, meta: true): CopySelectionTextIntent.copy, |
384 | const SingleActivator(LogicalKeyboardKey.keyV, meta: true): const PasteTextIntent(SelectionChangedCause.keyboard), |
385 | const SingleActivator(LogicalKeyboardKey.keyA, meta: true): const SelectAllTextIntent(SelectionChangedCause.keyboard), |
386 | const SingleActivator(LogicalKeyboardKey.keyZ, meta: true): const UndoTextIntent(SelectionChangedCause.keyboard), |
387 | const SingleActivator(LogicalKeyboardKey.keyZ, shift: true, meta: true): const RedoTextIntent(SelectionChangedCause.keyboard), |
388 | const SingleActivator(LogicalKeyboardKey.keyE, control: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), |
389 | const SingleActivator(LogicalKeyboardKey.keyA, control: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), |
390 | const SingleActivator(LogicalKeyboardKey.keyF, control: true): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), |
391 | const SingleActivator(LogicalKeyboardKey.keyB, control: true): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), |
392 | const SingleActivator(LogicalKeyboardKey.keyN, control: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), |
393 | const SingleActivator(LogicalKeyboardKey.keyP, control: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), |
394 | // These keys should go to the IME when a field is focused, not to other |
395 | // Shortcuts. |
396 | const SingleActivator(LogicalKeyboardKey.space): const DoNothingAndStopPropagationTextIntent(), |
397 | const SingleActivator(LogicalKeyboardKey.enter): const DoNothingAndStopPropagationTextIntent(), |
398 | // The following key combinations have no effect on text editing on this |
399 | // platform: |
400 | // * End |
401 | // * Home |
402 | // * Control + shift? + end |
403 | // * Control + shift? + home |
404 | // * Control + shift? + Z |
405 | }; |
406 | |
407 | // There is no complete documentation of iOS shortcuts: use macOS ones. |
408 | static final Map<ShortcutActivator, Intent> _iOSShortcuts = _macShortcuts; |
409 | |
410 | // The following key combinations have no effect on text editing on this |
411 | // platform: |
412 | // * Meta + X |
413 | // * Meta + C |
414 | // * Meta + V |
415 | // * Meta + A |
416 | // * Meta + shift? + arrow down |
417 | // * Meta + shift? + arrow left |
418 | // * Meta + shift? + arrow right |
419 | // * Meta + shift? + arrow up |
420 | // * Meta + delete |
421 | // * Meta + backspace |
422 | static final Map<ShortcutActivator, Intent> _windowsShortcuts = <ShortcutActivator, Intent>{ |
423 | ..._commonShortcuts, |
424 | const SingleActivator(LogicalKeyboardKey.pageUp): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: true), |
425 | const SingleActivator(LogicalKeyboardKey.pageDown): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: true), |
426 | const SingleActivator(LogicalKeyboardKey.home): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true, continuesAtWrap: true), |
427 | const SingleActivator(LogicalKeyboardKey.end): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true, continuesAtWrap: true), |
428 | const SingleActivator(LogicalKeyboardKey.home, shift: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false, continuesAtWrap: true), |
429 | const SingleActivator(LogicalKeyboardKey.end, shift: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false, continuesAtWrap: true), |
430 | const SingleActivator(LogicalKeyboardKey.home, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), |
431 | const SingleActivator(LogicalKeyboardKey.end, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), |
432 | const SingleActivator(LogicalKeyboardKey.home, shift: true, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: false), |
433 | const SingleActivator(LogicalKeyboardKey.end, shift: true, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: false), |
434 | }; |
435 | |
436 | // Web handles its text selection natively and doesn't use any of these |
437 | // shortcuts in Flutter. |
438 | static final Map<ShortcutActivator, Intent> _webDisablingTextShortcuts = <ShortcutActivator, Intent>{ |
439 | for (final bool pressShift in const <bool>[true, false]) |
440 | ...<SingleActivator, Intent>{ |
441 | SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
442 | SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
443 | SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
444 | SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
445 | SingleActivator(LogicalKeyboardKey.backspace, control: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
446 | SingleActivator(LogicalKeyboardKey.delete, control: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
447 | SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
448 | SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), |
449 | }, |
450 | ..._commonDisablingTextShortcuts, |
451 | const SingleActivator(LogicalKeyboardKey.keyX, control: true): const DoNothingAndStopPropagationTextIntent(), |
452 | const SingleActivator(LogicalKeyboardKey.keyX, meta: true): const DoNothingAndStopPropagationTextIntent(), |
453 | const SingleActivator(LogicalKeyboardKey.keyC, control: true): const DoNothingAndStopPropagationTextIntent(), |
454 | const SingleActivator(LogicalKeyboardKey.keyC, meta: true): const DoNothingAndStopPropagationTextIntent(), |
455 | const SingleActivator(LogicalKeyboardKey.keyV, control: true): const DoNothingAndStopPropagationTextIntent(), |
456 | const SingleActivator(LogicalKeyboardKey.keyV, meta: true): const DoNothingAndStopPropagationTextIntent(), |
457 | const SingleActivator(LogicalKeyboardKey.keyA, control: true): const DoNothingAndStopPropagationTextIntent(), |
458 | const SingleActivator(LogicalKeyboardKey.keyA, meta: true): const DoNothingAndStopPropagationTextIntent(), |
459 | }; |
460 | |
461 | static const Map<ShortcutActivator, Intent> _commonDisablingTextShortcuts = <ShortcutActivator, Intent>{ |
462 | SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): DoNothingAndStopPropagationTextIntent(), |
463 | SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): DoNothingAndStopPropagationTextIntent(), |
464 | SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): DoNothingAndStopPropagationTextIntent(), |
465 | SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): DoNothingAndStopPropagationTextIntent(), |
466 | SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): DoNothingAndStopPropagationTextIntent(), |
467 | SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): DoNothingAndStopPropagationTextIntent(), |
468 | SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): DoNothingAndStopPropagationTextIntent(), |
469 | SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): DoNothingAndStopPropagationTextIntent(), |
470 | SingleActivator(LogicalKeyboardKey.arrowDown): DoNothingAndStopPropagationTextIntent(), |
471 | SingleActivator(LogicalKeyboardKey.arrowLeft): DoNothingAndStopPropagationTextIntent(), |
472 | SingleActivator(LogicalKeyboardKey.arrowRight): DoNothingAndStopPropagationTextIntent(), |
473 | SingleActivator(LogicalKeyboardKey.arrowUp): DoNothingAndStopPropagationTextIntent(), |
474 | SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): DoNothingAndStopPropagationTextIntent(), |
475 | SingleActivator(LogicalKeyboardKey.arrowRight, control: true): DoNothingAndStopPropagationTextIntent(), |
476 | SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): DoNothingAndStopPropagationTextIntent(), |
477 | SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): DoNothingAndStopPropagationTextIntent(), |
478 | SingleActivator(LogicalKeyboardKey.space): DoNothingAndStopPropagationTextIntent(), |
479 | SingleActivator(LogicalKeyboardKey.enter): DoNothingAndStopPropagationTextIntent(), |
480 | }; |
481 | |
482 | static final Map<ShortcutActivator, Intent> _macDisablingTextShortcuts = <ShortcutActivator, Intent>{ |
483 | ..._commonDisablingTextShortcuts, |
484 | ..._iOSDisablingTextShortcuts, |
485 | const SingleActivator(LogicalKeyboardKey.escape): const DoNothingAndStopPropagationTextIntent(), |
486 | const SingleActivator(LogicalKeyboardKey.tab): const DoNothingAndStopPropagationTextIntent(), |
487 | const SingleActivator(LogicalKeyboardKey.tab, shift: true): const DoNothingAndStopPropagationTextIntent(), |
488 | const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), |
489 | const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), |
490 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): const DoNothingAndStopPropagationTextIntent(), |
491 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): const DoNothingAndStopPropagationTextIntent(), |
492 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), |
493 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), |
494 | const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), |
495 | const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), |
496 | const SingleActivator(LogicalKeyboardKey.pageUp): const DoNothingAndStopPropagationTextIntent(), |
497 | const SingleActivator(LogicalKeyboardKey.pageDown): const DoNothingAndStopPropagationTextIntent(), |
498 | const SingleActivator(LogicalKeyboardKey.end): const DoNothingAndStopPropagationTextIntent(), |
499 | const SingleActivator(LogicalKeyboardKey.home): const DoNothingAndStopPropagationTextIntent(), |
500 | const SingleActivator(LogicalKeyboardKey.pageUp, shift: true): const DoNothingAndStopPropagationTextIntent(), |
501 | const SingleActivator(LogicalKeyboardKey.pageDown, shift: true): const DoNothingAndStopPropagationTextIntent(), |
502 | const SingleActivator(LogicalKeyboardKey.end, shift: true): const DoNothingAndStopPropagationTextIntent(), |
503 | const SingleActivator(LogicalKeyboardKey.home, shift: true): const DoNothingAndStopPropagationTextIntent(), |
504 | const SingleActivator(LogicalKeyboardKey.end, control: true): const DoNothingAndStopPropagationTextIntent(), |
505 | const SingleActivator(LogicalKeyboardKey.home, control: true): const DoNothingAndStopPropagationTextIntent(), |
506 | }; |
507 | |
508 | // Hand backspace/delete events that do not depend on text layout (delete |
509 | // character and delete to the next word) back to the IME to allow it to |
510 | // update composing text properly. |
511 | static const Map<ShortcutActivator, Intent> _iOSDisablingTextShortcuts = <ShortcutActivator, Intent>{ |
512 | SingleActivator(LogicalKeyboardKey.backspace): DoNothingAndStopPropagationTextIntent(), |
513 | SingleActivator(LogicalKeyboardKey.backspace, shift: true): DoNothingAndStopPropagationTextIntent(), |
514 | SingleActivator(LogicalKeyboardKey.delete): DoNothingAndStopPropagationTextIntent(), |
515 | SingleActivator(LogicalKeyboardKey.delete, shift: true): DoNothingAndStopPropagationTextIntent(), |
516 | SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: true): DoNothingAndStopPropagationTextIntent(), |
517 | SingleActivator(LogicalKeyboardKey.backspace, alt: true): DoNothingAndStopPropagationTextIntent(), |
518 | SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: true): DoNothingAndStopPropagationTextIntent(), |
519 | SingleActivator(LogicalKeyboardKey.delete, alt: true): DoNothingAndStopPropagationTextIntent(), |
520 | }; |
521 | |
522 | static Map<ShortcutActivator, Intent> get _shortcuts { |
523 | return switch (defaultTargetPlatform) { |
524 | TargetPlatform.android => _androidShortcuts, |
525 | TargetPlatform.fuchsia => _fuchsiaShortcuts, |
526 | TargetPlatform.iOS => _iOSShortcuts, |
527 | TargetPlatform.linux => _linuxShortcuts, |
528 | TargetPlatform.macOS => _macShortcuts, |
529 | TargetPlatform.windows => _windowsShortcuts, |
530 | }; |
531 | } |
532 | |
533 | Map<ShortcutActivator, Intent>? _getDisablingShortcut() { |
534 | if (kIsWeb) { |
535 | switch (defaultTargetPlatform) { |
536 | case TargetPlatform.linux: |
537 | return <ShortcutActivator, Intent>{ |
538 | ..._webDisablingTextShortcuts, |
539 | for (final ShortcutActivator activator in _linuxNumpadShortcuts.keys) |
540 | activator as SingleActivator: const DoNothingAndStopPropagationTextIntent(), |
541 | }; |
542 | case TargetPlatform.android: |
543 | case TargetPlatform.fuchsia: |
544 | case TargetPlatform.windows: |
545 | case TargetPlatform.iOS: |
546 | case TargetPlatform.macOS: |
547 | return _webDisablingTextShortcuts; |
548 | } |
549 | } |
550 | switch (defaultTargetPlatform) { |
551 | case TargetPlatform.android: |
552 | case TargetPlatform.fuchsia: |
553 | case TargetPlatform.linux: |
554 | case TargetPlatform.windows: |
555 | return null; |
556 | case TargetPlatform.iOS: |
557 | return _iOSDisablingTextShortcuts; |
558 | case TargetPlatform.macOS: |
559 | return _macDisablingTextShortcuts; |
560 | } |
561 | } |
562 | |
563 | @override |
564 | Widget build(BuildContext context) { |
565 | Widget result = child; |
566 | final Map<ShortcutActivator, Intent>? disablingShortcut = _getDisablingShortcut(); |
567 | if (disablingShortcut != null) { |
568 | // These shortcuts make sure of the following: |
569 | // |
570 | // 1. Shortcuts fired when an EditableText is focused are ignored and |
571 | // forwarded to the platform by the EditableText's Actions, because it |
572 | // maps DoNothingAndStopPropagationTextIntent to DoNothingAction. |
573 | // 2. Shortcuts fired when no EditableText is focused will still trigger |
574 | // _shortcuts assuming DoNothingAndStopPropagationTextIntent is |
575 | // unhandled elsewhere. |
576 | result = Shortcuts( |
577 | debugLabel: '<Web Disabling Text Editing Shortcuts>' , |
578 | shortcuts: disablingShortcut, |
579 | child: result |
580 | ); |
581 | } |
582 | return Shortcuts( |
583 | debugLabel: '<Default Text Editing Shortcuts>' , |
584 | shortcuts: _shortcuts, |
585 | child: result |
586 | ); |
587 | } |
588 | } |
589 | |
590 | /// Maps the selector from NSStandardKeyBindingResponding to the Intent if the |
591 | /// selector is recognized. |
592 | Intent? intentForMacOSSelector(String selectorName) { |
593 | const Map<String, Intent> selectorToIntent = <String, Intent>{ |
594 | 'deleteBackward:' : DeleteCharacterIntent(forward: false), |
595 | 'deleteWordBackward:' : DeleteToNextWordBoundaryIntent(forward: false), |
596 | 'deleteToBeginningOfLine:' : DeleteToLineBreakIntent(forward: false), |
597 | 'deleteForward:' : DeleteCharacterIntent(forward: true), |
598 | 'deleteWordForward:' : DeleteToNextWordBoundaryIntent(forward: true), |
599 | 'deleteToEndOfLine:' : DeleteToLineBreakIntent(forward: true), |
600 | |
601 | 'moveLeft:' : ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), |
602 | 'moveRight:' : ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), |
603 | 'moveForward:' : ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), |
604 | 'moveBackward:' : ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), |
605 | |
606 | 'moveUp:' : ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), |
607 | 'moveDown:' : ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), |
608 | |
609 | 'moveLeftAndModifySelection:' : ExtendSelectionByCharacterIntent(forward: false, collapseSelection: false), |
610 | 'moveRightAndModifySelection:' : ExtendSelectionByCharacterIntent(forward: true, collapseSelection: false), |
611 | 'moveUpAndModifySelection:' : ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), |
612 | 'moveDownAndModifySelection:' : ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), |
613 | |
614 | 'moveWordLeft:' : ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: true), |
615 | 'moveWordRight:' : ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: true), |
616 | 'moveToBeginningOfParagraph:' : ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), |
617 | 'moveToEndOfParagraph:' : ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), |
618 | |
619 | 'moveWordLeftAndModifySelection:' : ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: false), |
620 | 'moveWordRightAndModifySelection:' : ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: true), |
621 | 'moveParagraphBackwardAndModifySelection:' : ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent(forward: false), |
622 | 'moveParagraphForwardAndModifySelection:' : ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent(forward: true), |
623 | |
624 | 'moveToLeftEndOfLine:' : ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), |
625 | 'moveToRightEndOfLine:' : ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), |
626 | 'moveToBeginningOfDocument:' : ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), |
627 | 'moveToEndOfDocument:' : ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), |
628 | |
629 | 'moveToLeftEndOfLineAndModifySelection:' : ExpandSelectionToLineBreakIntent(forward: false), |
630 | 'moveToRightEndOfLineAndModifySelection:' : ExpandSelectionToLineBreakIntent(forward: true), |
631 | 'moveToBeginningOfDocumentAndModifySelection:' : ExpandSelectionToDocumentBoundaryIntent(forward: false), |
632 | 'moveToEndOfDocumentAndModifySelection:' : ExpandSelectionToDocumentBoundaryIntent(forward: true), |
633 | |
634 | 'transpose:' : TransposeCharactersIntent(), |
635 | |
636 | 'scrollToBeginningOfDocument:' : ScrollToDocumentBoundaryIntent(forward: false), |
637 | 'scrollToEndOfDocument:' : ScrollToDocumentBoundaryIntent(forward: true), |
638 | |
639 | 'scrollPageUp:' : ScrollIntent(direction: AxisDirection.up, type: ScrollIncrementType.page), |
640 | 'scrollPageDown:' : ScrollIntent(direction: AxisDirection.down, type: ScrollIncrementType.page), |
641 | 'pageUpAndModifySelection:' : ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: false), |
642 | 'pageDownAndModifySelection:' : ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: false), |
643 | |
644 | // Escape key when there's no IME selection popup. |
645 | 'cancelOperation:' : DismissIntent(), |
646 | // Tab when there's no IME selection. |
647 | 'insertTab:' : NextFocusIntent(), |
648 | 'insertBacktab:' : PreviousFocusIntent(), |
649 | }; |
650 | return selectorToIntent[selectorName]; |
651 | } |
652 | |