Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / widget / cocoa / NativeKeyBindings.mm
blobe4bdf715e2fb899e97a5bfeb2e147127460d6047
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "NativeKeyBindings.h"
8 #include "nsTArray.h"
9 #include "nsCocoaUtils.h"
10 #include "mozilla/Logging.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/NativeKeyBindingsType.h"
13 #include "mozilla/TextEvents.h"
14 #include "mozilla/WritingModes.h"
16 #import <Cocoa/Cocoa.h>
17 #import <Carbon/Carbon.h>
19 namespace mozilla {
20 namespace widget {
22 static LazyLogModule gNativeKeyBindingsLog("NativeKeyBindings");
24 NativeKeyBindings* NativeKeyBindings::sInstanceForSingleLineEditor = nullptr;
25 NativeKeyBindings* NativeKeyBindings::sInstanceForMultiLineEditor = nullptr;
27 // static
28 NativeKeyBindings* NativeKeyBindings::GetInstance(NativeKeyBindingsType aType) {
29   switch (aType) {
30     case NativeKeyBindingsType::SingleLineEditor:
31       if (!sInstanceForSingleLineEditor) {
32         sInstanceForSingleLineEditor = new NativeKeyBindings();
33         sInstanceForSingleLineEditor->Init(aType);
34       }
35       return sInstanceForSingleLineEditor;
36     case NativeKeyBindingsType::MultiLineEditor:
37     case NativeKeyBindingsType::RichTextEditor:
38       if (!sInstanceForMultiLineEditor) {
39         sInstanceForMultiLineEditor = new NativeKeyBindings();
40         sInstanceForMultiLineEditor->Init(aType);
41       }
42       return sInstanceForMultiLineEditor;
43     default:
44       MOZ_CRASH("Not implemented");
45       return nullptr;
46   }
49 // static
50 void NativeKeyBindings::Shutdown() {
51   delete sInstanceForSingleLineEditor;
52   sInstanceForSingleLineEditor = nullptr;
53   delete sInstanceForMultiLineEditor;
54   sInstanceForMultiLineEditor = nullptr;
57 NativeKeyBindings::NativeKeyBindings() {}
59 inline objc_selector* ToObjcSelectorPtr(SEL aSel) {
60   return reinterpret_cast<objc_selector*>(aSel);
62 #define SEL_TO_COMMAND(aSel, aCommand)                                  \
63   mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), \
64                                     aCommand)
66 void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
67   MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
68           ("%p NativeKeyBindings::Init", this));
70   // Many selectors have a one-to-one mapping to a Gecko command. Those mappings
71   // are registered in mSelectorToCommand.
73   // Selectors from NSResponder's "Responding to Action Messages" section and
74   // from NSText's "Action Methods for Editing" section
76   // TODO: Improves correctness of left / right meaning
77   // TODO: Add real paragraph motions
79   // SEL_TO_COMMAND(cancelOperation:, );
80   // SEL_TO_COMMAND(capitalizeWord:, );
81   // SEL_TO_COMMAND(centerSelectionInVisibleArea:, );
82   // SEL_TO_COMMAND(changeCaseOfLetter:, );
83   // SEL_TO_COMMAND(complete:, );
84   SEL_TO_COMMAND(copy:, Command::Copy);
85   // SEL_TO_COMMAND(copyFont:, );
86   // SEL_TO_COMMAND(copyRuler:, );
87   SEL_TO_COMMAND(cut:, Command::Cut);
88   SEL_TO_COMMAND(delete:, Command::Delete);
89   SEL_TO_COMMAND(deleteBackward:, Command::DeleteCharBackward);
90   // SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
91   SEL_TO_COMMAND(deleteForward:, Command::DeleteCharForward);
93   // TODO: deleteTo* selectors are also supposed to add text to a kill buffer
94   SEL_TO_COMMAND(deleteToBeginningOfLine:, Command::DeleteToBeginningOfLine);
95   SEL_TO_COMMAND(deleteToBeginningOfParagraph:,
96                  Command::DeleteToBeginningOfLine);
97   SEL_TO_COMMAND(deleteToEndOfLine:, Command::DeleteToEndOfLine);
98   SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine);
99   // SEL_TO_COMMAND(deleteToMark:, );
101   SEL_TO_COMMAND(deleteWordBackward:, Command::DeleteWordBackward);
102   SEL_TO_COMMAND(deleteWordForward:, Command::DeleteWordForward);
103   // SEL_TO_COMMAND(indent:, );
104   // SEL_TO_COMMAND(insertBacktab:, );
105   // SEL_TO_COMMAND(insertContainerBreak:, );
106   // SEL_TO_COMMAND(insertLineBreak:, );
107   // SEL_TO_COMMAND(insertNewline:, );
108   // SEL_TO_COMMAND(insertNewlineIgnoringFieldEditor:, );
109   // SEL_TO_COMMAND(insertParagraphSeparator:, );
110   // SEL_TO_COMMAND(insertTab:, );
111   // SEL_TO_COMMAND(insertTabIgnoringFieldEditor:, );
112   // SEL_TO_COMMAND(insertDoubleQuoteIgnoringSubstitution:, );
113   // SEL_TO_COMMAND(insertSingleQuoteIgnoringSubstitution:, );
114   // SEL_TO_COMMAND(lowercaseWord:, );
115   SEL_TO_COMMAND(moveBackward:, Command::CharPrevious);
116   SEL_TO_COMMAND(moveBackwardAndModifySelection:, Command::SelectCharPrevious);
117   if (aType == NativeKeyBindingsType::SingleLineEditor) {
118     SEL_TO_COMMAND(moveDown:, Command::EndLine);
119   } else {
120     SEL_TO_COMMAND(moveDown:, Command::LineNext);
121   }
122   SEL_TO_COMMAND(moveDownAndModifySelection:, Command::SelectLineNext);
123   SEL_TO_COMMAND(moveForward:, Command::CharNext);
124   SEL_TO_COMMAND(moveForwardAndModifySelection:, Command::SelectCharNext);
125   SEL_TO_COMMAND(moveLeft:, Command::CharPrevious);
126   SEL_TO_COMMAND(moveLeftAndModifySelection:, Command::SelectCharPrevious);
127   SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
128                  Command::SelectBeginLine);
129   SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:,
130                  Command::SelectEndLine);
131   SEL_TO_COMMAND(moveRight:, Command::CharNext);
132   SEL_TO_COMMAND(moveRightAndModifySelection:, Command::SelectCharNext);
133   SEL_TO_COMMAND(moveToBeginningOfDocument:, Command::MoveTop);
134   SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:,
135                  Command::SelectTop);
136   SEL_TO_COMMAND(moveToBeginningOfLine:, Command::BeginLine);
137   SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
138                  Command::SelectBeginLine);
139   SEL_TO_COMMAND(moveToBeginningOfParagraph:, Command::BeginLine);
140   SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
141                  Command::SelectBeginLine);
142   SEL_TO_COMMAND(moveToEndOfDocument:, Command::MoveBottom);
143   SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, Command::SelectBottom);
144   SEL_TO_COMMAND(moveToEndOfLine:, Command::EndLine);
145   SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, Command::SelectEndLine);
146   SEL_TO_COMMAND(moveToEndOfParagraph:, Command::EndLine);
147   SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:,
148                  Command::SelectEndLine);
149   SEL_TO_COMMAND(moveToLeftEndOfLine:, Command::BeginLine);
150   SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
151                  Command::SelectBeginLine);
152   SEL_TO_COMMAND(moveToRightEndOfLine:, Command::EndLine);
153   SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:,
154                  Command::SelectEndLine);
155   if (aType == NativeKeyBindingsType::SingleLineEditor) {
156     SEL_TO_COMMAND(moveUp:, Command::BeginLine);
157   } else {
158     SEL_TO_COMMAND(moveUp:, Command::LinePrevious);
159   }
160   SEL_TO_COMMAND(moveUpAndModifySelection:, Command::SelectLinePrevious);
161   SEL_TO_COMMAND(moveWordBackward:, Command::WordPrevious);
162   SEL_TO_COMMAND(moveWordBackwardAndModifySelection:,
163                  Command::SelectWordPrevious);
164   SEL_TO_COMMAND(moveWordForward:, Command::WordNext);
165   SEL_TO_COMMAND(moveWordForwardAndModifySelection:, Command::SelectWordNext);
166   SEL_TO_COMMAND(moveWordLeft:, Command::WordPrevious);
167   SEL_TO_COMMAND(moveWordLeftAndModifySelection:, Command::SelectWordPrevious);
168   SEL_TO_COMMAND(moveWordRight:, Command::WordNext);
169   SEL_TO_COMMAND(moveWordRightAndModifySelection:, Command::SelectWordNext);
170   SEL_TO_COMMAND(pageDown:, Command::MovePageDown);
171   SEL_TO_COMMAND(pageDownAndModifySelection:, Command::SelectPageDown);
172   SEL_TO_COMMAND(pageUp:, Command::MovePageUp);
173   SEL_TO_COMMAND(pageUpAndModifySelection:, Command::SelectPageUp);
174   SEL_TO_COMMAND(paste:, Command::Paste);
175   // SEL_TO_COMMAND(pasteFont:, );
176   // SEL_TO_COMMAND(pasteRuler:, );
177   SEL_TO_COMMAND(scrollLineDown:, Command::ScrollLineDown);
178   SEL_TO_COMMAND(scrollLineUp:, Command::ScrollLineUp);
179   SEL_TO_COMMAND(scrollPageDown:, Command::ScrollPageDown);
180   SEL_TO_COMMAND(scrollPageUp:, Command::ScrollPageUp);
181   SEL_TO_COMMAND(scrollToBeginningOfDocument:, Command::ScrollTop);
182   SEL_TO_COMMAND(scrollToEndOfDocument:, Command::ScrollBottom);
183   SEL_TO_COMMAND(selectAll:, Command::SelectAll);
184   // selectLine: is complex, see KeyDown
185   if (aType == NativeKeyBindingsType::SingleLineEditor) {
186     SEL_TO_COMMAND(selectParagraph:, Command::SelectAll);
187   }
188   // SEL_TO_COMMAND(selectToMark:, );
189   // selectWord: is complex, see KeyDown
190   // SEL_TO_COMMAND(setMark:, );
191   // SEL_TO_COMMAND(showContextHelp:, );
192   // SEL_TO_COMMAND(supplementalTargetForAction:sender:, );
193   // SEL_TO_COMMAND(swapWithMark:, );
194   // SEL_TO_COMMAND(transpose:, );
195   // SEL_TO_COMMAND(transposeWords:, );
196   // SEL_TO_COMMAND(uppercaseWord:, );
197   // SEL_TO_COMMAND(yank:, );
200 #undef SEL_TO_COMMAND
202 void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
203                                         const Maybe<WritingMode>& aWritingMode,
204                                         nsTArray<CommandInt>& aCommands) {
205   MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests);
206   MOZ_ASSERT(aCommands.IsEmpty());
208   MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
209           ("%p NativeKeyBindings::GetEditCommands", this));
211   // Recover the current event, which should always be the key down we are
212   // responding to.
214   NSEvent* cocoaEvent = reinterpret_cast<NSEvent*>(aEvent.mNativeKeyEvent);
216   if (!cocoaEvent || [cocoaEvent type] != NSEventTypeKeyDown) {
217     MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
218             ("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event",
219              this));
221     return;
222   }
224   if (aWritingMode.isSome() && aEvent.NeedsToRemapNavigationKey() &&
225       aWritingMode.ref().IsVertical()) {
226     NSEvent* originalEvent = cocoaEvent;
228     // TODO: Use KeyNameIndex rather than legacy keyCode.
229     uint32_t remappedGeckoKeyCode =
230         aEvent.GetRemappedKeyCode(aWritingMode.ref());
231     uint32_t remappedCocoaKeyCode = 0;
232     switch (remappedGeckoKeyCode) {
233       case NS_VK_UP:
234         remappedCocoaKeyCode = kVK_UpArrow;
235         break;
236       case NS_VK_DOWN:
237         remappedCocoaKeyCode = kVK_DownArrow;
238         break;
239       case NS_VK_LEFT:
240         remappedCocoaKeyCode = kVK_LeftArrow;
241         break;
242       case NS_VK_RIGHT:
243         remappedCocoaKeyCode = kVK_RightArrow;
244         break;
245       default:
246         MOZ_ASSERT_UNREACHABLE("Add a case for the new remapped key");
247         return;
248     }
249     unichar ch =
250         nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode);
251     NSString* chars = [[[NSString alloc] initWithCharacters:&ch
252                                                      length:1] autorelease];
253     cocoaEvent = [NSEvent keyEventWithType:[originalEvent type]
254                                   location:[originalEvent locationInWindow]
255                              modifierFlags:[originalEvent modifierFlags]
256                                  timestamp:[originalEvent timestamp]
257                               windowNumber:[originalEvent windowNumber]
258                                    context:nil
259                                 characters:chars
260                charactersIgnoringModifiers:chars
261                                  isARepeat:[originalEvent isARepeat]
262                                    keyCode:remappedCocoaKeyCode];
263   }
265   MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
266           ("%p NativeKeyBindings::GetEditCommands, interpreting", this));
268   AutoTArray<KeyBindingsCommand, 2> bindingCommands;
269   nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
271   MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
272           ("%p NativeKeyBindings::GetEditCommands, bindingCommands=%zu", this,
273            bindingCommands.Length()));
275   for (uint32_t i = 0; i < bindingCommands.Length(); i++) {
276     SEL selector = bindingCommands[i].selector;
278     if (MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
279       NSString* selectorString = NSStringFromSelector(selector);
280       nsAutoString nsSelectorString;
281       nsCocoaUtils::GetStringForNSString(selectorString, nsSelectorString);
283       MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
284               ("%p NativeKeyBindings::GetEditCommands, selector=%s", this,
285                NS_LossyConvertUTF16toASCII(nsSelectorString).get()));
286     }
288     AppendEditCommandsForSelector(ToObjcSelectorPtr(selector), aCommands);
289   }
291   LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommands");
294 void NativeKeyBindings::AppendEditCommandsForSelector(
295     objc_selector* aSelector, nsTArray<CommandInt>& aCommands) const {
296   // Try to find a simple mapping in the hashtable
297   Command geckoCommand = Command::DoNothing;
298   if (mSelectorToCommand.Get(aSelector, &geckoCommand) &&
299       geckoCommand != Command::DoNothing) {
300     aCommands.AppendElement(static_cast<CommandInt>(geckoCommand));
301   } else if (aSelector == ToObjcSelectorPtr(@selector(selectLine:))) {
302     // This is functional, but Cocoa's version is direction-less in that
303     // selection direction is not determined until some future directed action
304     // is taken. See bug 282097, comment 79 for more details.
305     aCommands.AppendElement(static_cast<CommandInt>(Command::BeginLine));
306     aCommands.AppendElement(static_cast<CommandInt>(Command::SelectEndLine));
307   } else if (aSelector == ToObjcSelectorPtr(@selector(selectWord:))) {
308     // This is functional, but Cocoa's version is direction-less in that
309     // selection direction is not determined until some future directed action
310     // is taken. See bug 282097, comment 79 for more details.
311     aCommands.AppendElement(static_cast<CommandInt>(Command::WordPrevious));
312     aCommands.AppendElement(static_cast<CommandInt>(Command::SelectWordNext));
313   }
316 void NativeKeyBindings::LogEditCommands(const nsTArray<CommandInt>& aCommands,
317                                         const char* aDescription) const {
318   if (!MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
319     return;
320   }
322   if (aCommands.IsEmpty()) {
323     MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
324             ("%p %s, no edit commands", this, aDescription));
325     return;
326   }
328   for (CommandInt commandInt : aCommands) {
329     Command geckoCommand = static_cast<Command>(commandInt);
330     MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
331             ("%p %s, command=%s", this, aDescription,
332              WidgetKeyboardEvent::GetCommandStr(geckoCommand)));
333   }
336 // static
337 void NativeKeyBindings::GetEditCommandsForTests(
338     NativeKeyBindingsType aType, const WidgetKeyboardEvent& aEvent,
339     const Maybe<WritingMode>& aWritingMode, nsTArray<CommandInt>& aCommands) {
340   MOZ_DIAGNOSTIC_ASSERT(aEvent.IsTrusted());
342   // The following mapping is checked on Big Sur. Some of them are defined in:
343   // https://support.apple.com/en-us/HT201236#text
344   NativeKeyBindings* instance = NativeKeyBindings::GetInstance(aType);
345   if (NS_WARN_IF(!instance)) {
346     return;
347   }
348   switch (aWritingMode.isSome()
349               ? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref())
350               : aEvent.mKeyNameIndex) {
351     case KEY_NAME_INDEX_USE_STRING:
352       if (!aEvent.IsControl() || aEvent.IsAlt() || aEvent.IsMeta()) {
353         break;
354       }
355       switch (aEvent.PseudoCharCode()) {
356         case 'a':
357         case 'A':
358           instance->AppendEditCommandsForSelector(
359               !aEvent.IsShift()
360                   ? ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:))
361                   : ToObjcSelectorPtr(@selector(
362                         moveToBeginningOfParagraphAndModifySelection:)),
363               aCommands);
364           break;
365         case 'b':
366         case 'B':
367           instance->AppendEditCommandsForSelector(
368               !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveBackward:))
369                                 : ToObjcSelectorPtr(@selector(
370                                       moveBackwardAndModifySelection:)),
371               aCommands);
372           break;
373         case 'd':
374         case 'D':
375           if (!aEvent.IsShift()) {
376             instance->AppendEditCommandsForSelector(
377                 ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
378           }
379           break;
380         case 'e':
381         case 'E':
382           instance->AppendEditCommandsForSelector(
383               !aEvent.IsShift()
384                   ? ToObjcSelectorPtr(@selector(moveToEndOfParagraph:))
385                   : ToObjcSelectorPtr(
386                         @selector(moveToEndOfParagraphAndModifySelection:)),
387               aCommands);
388           break;
389         case 'f':
390         case 'F':
391           instance->AppendEditCommandsForSelector(
392               !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveForward:))
393                                 : ToObjcSelectorPtr(@selector(
394                                       moveForwardAndModifySelection:)),
395               aCommands);
396           break;
397         case 'h':
398         case 'H':
399           if (!aEvent.IsShift()) {
400             instance->AppendEditCommandsForSelector(
401                 ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
402           }
403           break;
404         case 'k':
405         case 'K':
406           if (!aEvent.IsShift()) {
407             instance->AppendEditCommandsForSelector(
408                 ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)),
409                 aCommands);
410           }
411           break;
412         case 'n':
413         case 'N':
414           instance->AppendEditCommandsForSelector(
415               !aEvent.IsShift()
416                   ? ToObjcSelectorPtr(@selector(moveDown:))
417                   : ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
418               aCommands);
419           break;
420         case 'p':
421         case 'P':
422           instance->AppendEditCommandsForSelector(
423               !aEvent.IsShift()
424                   ? ToObjcSelectorPtr(@selector(moveUp:))
425                   : ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
426               aCommands);
427           break;
428         default:
429           break;
430       }
431       break;
432     case KEY_NAME_INDEX_Backspace:
433       if (aEvent.IsMeta()) {
434         if (aEvent.IsAlt() || aEvent.IsControl()) {
435           break;
436         }
437         // Shift is ignored.
438         instance->AppendEditCommandsForSelector(
439             ToObjcSelectorPtr(@selector(deleteToBeginningOfLine:)), aCommands);
440         break;
441       }
442       if (aEvent.IsAlt()) {
443         // Shift and Control are ignored.
444         instance->AppendEditCommandsForSelector(
445             ToObjcSelectorPtr(@selector(deleteWordBackward:)), aCommands);
446         break;
447       }
448       if (aEvent.IsControl()) {
449         if (aEvent.IsShift()) {
450           instance->AppendEditCommandsForSelector(
451               ToObjcSelectorPtr(
452                   @selector(deleteBackwardByDecomposingPreviousCharacter:)),
453               aCommands);
454         }
455         break;
456       }
457       // Shift is ignored.
458       instance->AppendEditCommandsForSelector(
459           ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
460       break;
461     case KEY_NAME_INDEX_Delete:
462       if (aEvent.IsControl() || aEvent.IsMeta()) {
463         break;
464       }
465       if (aEvent.IsAlt()) {
466         // Shift is ignored.
467         instance->AppendEditCommandsForSelector(
468             ToObjcSelectorPtr(@selector(deleteWordForward:)), aCommands);
469         break;
470       }
471       // Shift is ignored.
472       instance->AppendEditCommandsForSelector(
473           ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
474       break;
475     case KEY_NAME_INDEX_PageDown:
476       if (aEvent.IsControl() || aEvent.IsMeta()) {
477         break;
478       }
479       if (aEvent.IsAlt()) {
480         // Shift is ignored.
481         instance->AppendEditCommandsForSelector(
482             ToObjcSelectorPtr(@selector(pageDown:)), aCommands);
483         break;
484       }
485       instance->AppendEditCommandsForSelector(
486           !aEvent.IsShift()
487               ? ToObjcSelectorPtr(@selector(scrollPageDown:))
488               : ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)),
489           aCommands);
490       break;
491     case KEY_NAME_INDEX_PageUp:
492       if (aEvent.IsControl() || aEvent.IsMeta()) {
493         break;
494       }
495       if (aEvent.IsAlt()) {
496         // Shift is ignored.
497         instance->AppendEditCommandsForSelector(
498             ToObjcSelectorPtr(@selector(pageUp:)), aCommands);
499         break;
500       }
501       instance->AppendEditCommandsForSelector(
502           !aEvent.IsShift()
503               ? ToObjcSelectorPtr(@selector(scrollPageUp:))
504               : ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)),
505           aCommands);
506       break;
507     case KEY_NAME_INDEX_Home:
508       if (aEvent.IsAlt() || aEvent.IsControl() || aEvent.IsMeta()) {
509         break;
510       }
511       instance->AppendEditCommandsForSelector(
512           !aEvent.IsShift()
513               ? ToObjcSelectorPtr(@selector(scrollToBeginningOfDocument:))
514               : ToObjcSelectorPtr(
515                     @selector(moveToBeginningOfDocumentAndModifySelection:)),
516           aCommands);
517       break;
518     case KEY_NAME_INDEX_End:
519       if (aEvent.IsAlt() || aEvent.IsControl() || aEvent.IsMeta()) {
520         break;
521       }
522       instance->AppendEditCommandsForSelector(
523           !aEvent.IsShift()
524               ? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:))
525               : ToObjcSelectorPtr(@selector
526                                   (moveToEndOfDocumentAndModifySelection:)),
527           aCommands);
528       break;
529     case KEY_NAME_INDEX_ArrowLeft:
530       if (aEvent.IsAlt()) {
531         break;
532       }
533       if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
534         instance->AppendEditCommandsForSelector(
535             !aEvent.IsShift()
536                 ? ToObjcSelectorPtr(@selector(moveToLeftEndOfLine:))
537                 : ToObjcSelectorPtr(@selector
538                                     (moveToLeftEndOfLineAndModifySelection:)),
539             aCommands);
540         break;
541       }
542       if (aEvent.IsControl()) {
543         break;
544       }
545       instance->AppendEditCommandsForSelector(
546           !aEvent.IsShift()
547               ? ToObjcSelectorPtr(@selector(moveLeft:))
548               : ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)),
549           aCommands);
550       break;
551     case KEY_NAME_INDEX_ArrowRight:
552       if (aEvent.IsAlt()) {
553         break;
554       }
555       if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
556         instance->AppendEditCommandsForSelector(
557             !aEvent.IsShift()
558                 ? ToObjcSelectorPtr(@selector(moveToRightEndOfLine:))
559                 : ToObjcSelectorPtr(@selector
560                                     (moveToRightEndOfLineAndModifySelection:)),
561             aCommands);
562         break;
563       }
564       if (aEvent.IsControl()) {
565         break;
566       }
567       instance->AppendEditCommandsForSelector(
568           !aEvent.IsShift()
569               ? ToObjcSelectorPtr(@selector(moveRight:))
570               : ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)),
571           aCommands);
572       break;
573     case KEY_NAME_INDEX_ArrowUp:
574       if (aEvent.IsControl()) {
575         break;
576       }
577       if (aEvent.IsMeta()) {
578         if (aEvent.IsAlt()) {
579           break;
580         }
581         instance->AppendEditCommandsForSelector(
582             !aEvent.IsShift()
583                 ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
584                 : ToObjcSelectorPtr(
585                       @selector(moveToBegginingOfDocumentAndModifySelection:)),
586             aCommands);
587         break;
588       }
589       if (aEvent.IsAlt()) {
590         if (!aEvent.IsShift()) {
591           instance->AppendEditCommandsForSelector(
592               ToObjcSelectorPtr(@selector(moveBackward:)), aCommands);
593           instance->AppendEditCommandsForSelector(
594               ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)),
595               aCommands);
596           break;
597         }
598         instance->AppendEditCommandsForSelector(
599             ToObjcSelectorPtr(@selector
600                               (moveParagraphBackwardAndModifySelection:)),
601             aCommands);
602         break;
603       }
604       instance->AppendEditCommandsForSelector(
605           !aEvent.IsShift()
606               ? ToObjcSelectorPtr(@selector(moveUp:))
607               : ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
608           aCommands);
609       break;
610     case KEY_NAME_INDEX_ArrowDown:
611       if (aEvent.IsControl()) {
612         break;
613       }
614       if (aEvent.IsMeta()) {
615         if (aEvent.IsAlt()) {
616           break;
617         }
618         instance->AppendEditCommandsForSelector(
619             !aEvent.IsShift()
620                 ? ToObjcSelectorPtr(@selector(moveToEndOfDocument:))
621                 : ToObjcSelectorPtr(@selector
622                                     (moveToEndOfDocumentAndModifySelection:)),
623             aCommands);
624         break;
625       }
626       if (aEvent.IsAlt()) {
627         if (!aEvent.IsShift()) {
628           instance->AppendEditCommandsForSelector(
629               ToObjcSelectorPtr(@selector(moveForward:)), aCommands);
630           instance->AppendEditCommandsForSelector(
631               ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)), aCommands);
632           break;
633         }
634         instance->AppendEditCommandsForSelector(
635             ToObjcSelectorPtr(@selector
636                               (moveParagraphForwardAndModifySelection:)),
637             aCommands);
638         break;
639       }
640       instance->AppendEditCommandsForSelector(
641           !aEvent.IsShift()
642               ? ToObjcSelectorPtr(@selector(moveDown:))
643               : ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
644           aCommands);
645       break;
646     default:
647       break;
648   }
650   instance->LogEditCommands(aCommands,
651                             "NativeKeyBindings::GetEditCommandsForTests");
654 }  // namespace widget
655 }  // namespace mozilla