Bug 977959 part.1 Define constants for each command which may be caused by native key bindings r=roc
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 14 Mar 2014 22:13:30 +0900
changeset 190851 74ba454a18212a62e73a77826c770658a5e8ff35
parent 190850 18d9ef6053d1180ff2d079b38dc2d2a9c460782d
child 190852 ffcd85163a89862fb6f83babb1428e2bd1d9030e
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs977959
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 977959 part.1 Define constants for each command which may be caused by native key bindings r=roc
content/html/content/src/nsTextEditorState.cpp
editor/libeditor/base/nsEditorEventListener.cpp
widget/CommandList.h
widget/EventForwards.h
widget/TextEvents.h
widget/cocoa/NativeKeyBindings.h
widget/cocoa/NativeKeyBindings.mm
widget/gtk/nsNativeKeyBindings.cpp
widget/moz.build
widget/nsINativeKeyBindings.h
widget/shared/WidgetEventImpl.cpp
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -793,17 +793,17 @@ nsTextInputListener::NotifySelectionChan
     return NS_OK;
 
   return UpdateTextInputCommands(NS_LITERAL_STRING("select"));
 }
 
 // END nsIDOMSelectionListener
 
 static void
-DoCommandCallback(const char *aCommand, void *aData)
+DoCommandCallback(Command aCommand, void* aData)
 {
   nsTextControlFrame *frame = static_cast<nsTextControlFrame*>(aData);
   nsIContent *content = frame->GetContent();
 
   nsCOMPtr<nsIControllers> controllers;
   nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(content);
   if (input) {
     input->GetControllers(getter_AddRefs(controllers));
@@ -816,27 +816,29 @@ DoCommandCallback(const char *aCommand, 
     }
   }
 
   if (!controllers) {
     NS_WARNING("Could not get controllers");
     return;
   }
 
+  const char* commandStr = WidgetKeyboardEvent::GetCommandStr(aCommand);
+
   nsCOMPtr<nsIController> controller;
-  controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
+  controllers->GetControllerForCommand(commandStr, getter_AddRefs(controller));
   if (!controller) {
     return;
   }
 
   bool commandEnabled;
-  nsresult rv = controller->IsCommandEnabled(aCommand, &commandEnabled);
+  nsresult rv = controller->IsCommandEnabled(commandStr, &commandEnabled);
   NS_ENSURE_SUCCESS_VOID(rv);
   if (commandEnabled) {
-    controller->DoCommand(aCommand);
+    controller->DoCommand(commandStr);
   }
 }
 
 NS_IMETHODIMP
 nsTextInputListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   bool defaultPrevented = false;
   nsresult rv = aEvent->GetDefaultPrevented(&defaultPrevented);
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -75,39 +75,41 @@ GetEditorKeyBindings()
       noBindings = true;
     }
   }
 
   return sNativeEditorBindings;
 }
 
 static void
-DoCommandCallback(const char *aCommand, void *aData)
+DoCommandCallback(Command aCommand, void* aData)
 {
   nsIDocument* doc = static_cast<nsIDocument*>(aData);
   nsPIDOMWindow* win = doc->GetWindow();
   if (!win) {
     return;
   }
   nsCOMPtr<nsPIWindowRoot> root = win->GetTopWindowRoot();
   if (!root) {
     return;
   }
 
+  const char* commandStr = WidgetKeyboardEvent::GetCommandStr(aCommand);
+
   nsCOMPtr<nsIController> controller;
-  root->GetControllerForCommand(aCommand, getter_AddRefs(controller));
+  root->GetControllerForCommand(commandStr, getter_AddRefs(controller));
   if (!controller) {
     return;
   }
 
   bool commandEnabled;
-  nsresult rv = controller->IsCommandEnabled(aCommand, &commandEnabled);
+  nsresult rv = controller->IsCommandEnabled(commandStr, &commandEnabled);
   NS_ENSURE_SUCCESS_VOID(rv);
   if (commandEnabled) {
-    controller->DoCommand(aCommand);
+    controller->DoCommand(commandStr);
   }
 }
 
 nsEditorEventListener::nsEditorEventListener() :
   mEditor(nullptr), mCommitText(false),
   mInTransaction(false)
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
   , mHaveBidiKeyboards(false)
new file mode 100644
--- /dev/null
+++ b/widget/CommandList.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Define NS_DEFIVE_COMMAND(aName, aCommandStr) before including this.
+ * @param aName          The name useful in C++ of the command.
+ * @param aCommandStr    The command string in JS.
+ */
+
+NS_DEFINE_COMMAND(BeginLine,                   cmd_beginLine)
+NS_DEFINE_COMMAND(CharNext,                    cmd_charNext)
+NS_DEFINE_COMMAND(CharPrevious,                cmd_charPrevious)
+NS_DEFINE_COMMAND(Copy,                        cmd_copy)
+NS_DEFINE_COMMAND(Cut,                         cmd_cut)
+NS_DEFINE_COMMAND(Delete,                      cmd_delete)
+NS_DEFINE_COMMAND(DeleteCharBackward,          cmd_deleteCharBackward)
+NS_DEFINE_COMMAND(DeleteCharForward,           cmd_deleteCharForward)
+NS_DEFINE_COMMAND(DeleteToBeginningOfLine,     cmd_deleteToBeginningOfLine)
+NS_DEFINE_COMMAND(DeleteToEndOfLine,           cmd_deleteToEndOfLine)
+NS_DEFINE_COMMAND(DeleteWordBackward,          cmd_deleteWordBackward)
+NS_DEFINE_COMMAND(DeleteWordForward,           cmd_deleteWordForward)
+NS_DEFINE_COMMAND(EndLine,                     cmd_endLine)
+NS_DEFINE_COMMAND(LineNext,                    cmd_lineNext)
+NS_DEFINE_COMMAND(LinePrevious,                cmd_linePrevious)
+NS_DEFINE_COMMAND(MoveBottom,                  cmd_moveBottom)
+NS_DEFINE_COMMAND(MovePageDown,                cmd_movePageDown)
+NS_DEFINE_COMMAND(MovePageUp,                  cmd_movePageUp)
+NS_DEFINE_COMMAND(MoveTop,                     cmd_moveTop)
+NS_DEFINE_COMMAND(Paste,                       cmd_paste)
+NS_DEFINE_COMMAND(ScrollBottom,                cmd_scrollBottom)
+NS_DEFINE_COMMAND(ScrollLineDown,              cmd_scrollLineDown)
+NS_DEFINE_COMMAND(ScrollLineUp,                cmd_scrollLineUp)
+NS_DEFINE_COMMAND(ScrollPageDown,              cmd_scrollPageDown)
+NS_DEFINE_COMMAND(ScrollPageUp,                cmd_scrollPageUp)
+NS_DEFINE_COMMAND(ScrollTop,                   cmd_scrollTop)
+NS_DEFINE_COMMAND(SelectAll,                   cmd_selectAll)
+NS_DEFINE_COMMAND(SelectBeginLine,             cmd_selectBeginLine)
+NS_DEFINE_COMMAND(SelectBottom,                cmd_selectBottom)
+NS_DEFINE_COMMAND(SelectCharNext,              cmd_selectCharNext)
+NS_DEFINE_COMMAND(SelectCharPrevious,          cmd_selectCharPrevious)
+NS_DEFINE_COMMAND(SelectEndLine,               cmd_selectEndLine)
+NS_DEFINE_COMMAND(SelectLineNext,              cmd_selectLineNext)
+NS_DEFINE_COMMAND(SelectLinePrevious,          cmd_selectLinePrevious)
+NS_DEFINE_COMMAND(SelectPageDown,              cmd_selectPageDown)
+NS_DEFINE_COMMAND(SelectPageUp,                cmd_selectPageUp)
+NS_DEFINE_COMMAND(SelectTop,                   cmd_selectTop)
+NS_DEFINE_COMMAND(SelectWordNext,              cmd_selectWordNext)
+NS_DEFINE_COMMAND(SelectWordPrevious,          cmd_selectWordPrevious)
+NS_DEFINE_COMMAND(WordNext,                    cmd_wordNext)
+NS_DEFINE_COMMAND(WordPrevious,                cmd_wordPrevious)
--- a/widget/EventForwards.h
+++ b/widget/EventForwards.h
@@ -3,16 +3,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_EventForwards_h__
 #define mozilla_EventForwards_h__
 
 #include <stdint.h>
 
+#include "mozilla/TypedEnum.h"
+
 /**
  * XXX Following enums should be in BasicEvents.h.  However, currently, it's
  *     impossible to use foward delearation for enum.
  */
 
 /**
  * Return status for event processors.
  */
@@ -38,16 +40,27 @@ enum KeyNameIndex
 #include "nsDOMKeyNameList.h"
   // If a DOM keyboard event is synthesized by script, this is used.  Then,
   // specified key name should be stored and use it as .key value.
   KEY_NAME_INDEX_USE_STRING
 };
 
 #undef NS_DEFINE_KEYNAME
 
+#define NS_DEFINE_COMMAND(aName, aCommandStr) , Command##aName
+
+typedef int8_t CommandInt;
+enum Command MOZ_ENUM_TYPE(CommandInt)
+{
+  CommandDoNothing
+
+#include "mozilla/CommandList.h"
+};
+#undef NS_DEFINE_COMMAND
+
 } // namespace mozilla
 
 /**
  * All header files should include this header instead of *Events.h.
  */
 
 namespace mozilla {
 
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -138,16 +138,18 @@ public:
       return;
     }
     GetDOMKeyName(mKeyNameIndex, aKeyName);
   }
 
   static void GetDOMKeyName(mozilla::KeyNameIndex aKeyNameIndex,
                             nsAString& aKeyName);
 
+  static const char* GetCommandStr(Command aCommand);
+
   void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets)
   {
     AssignInputEventData(aEvent, aCopyTargets);
 
     keyCode = aEvent.keyCode;
     charCode = aEvent.charCode;
     location = aEvent.location;
     alternativeCharCodes = aEvent.alternativeCharCodes;
--- a/widget/cocoa/NativeKeyBindings.h
+++ b/widget/cocoa/NativeKeyBindings.h
@@ -33,17 +33,17 @@ namespace widget {
 
 enum NativeKeyBindingsType
 {
   eNativeKeyBindingsType_Input,
   eNativeKeyBindingsType_TextArea,
   eNativeKeyBindingsType_Editor
 };
 
-typedef nsDataHashtable<nsPtrHashKey<struct objc_selector>, const char *>
+typedef nsDataHashtable<nsPtrHashKey<struct objc_selector>, CommandInt>
   SelectorCommandHashtable;
 
 class NativeKeyBindings MOZ_FINAL : public nsINativeKeyBindings
 {
 public:
   NativeKeyBindings();
 
   NS_DECL_ISUPPORTS
--- a/widget/cocoa/NativeKeyBindings.mm
+++ b/widget/cocoa/NativeKeyBindings.mm
@@ -46,112 +46,115 @@ NativeKeyBindings::Init(NativeKeyBinding
   // TODO: Improves correctness of left / right meaning
   // TODO: Add real paragraph motions
 
   // SEL_TO_COMMAND(cancelOperation:, );
   // SEL_TO_COMMAND(capitalizeWord:, );
   // SEL_TO_COMMAND(centerSelectionInVisibleArea:, );
   // SEL_TO_COMMAND(changeCaseOfLetter:, );
   // SEL_TO_COMMAND(complete:, );
-  SEL_TO_COMMAND(copy:, "cmd_copy");
+  SEL_TO_COMMAND(copy:, CommandCopy);
   // SEL_TO_COMMAND(copyFont:, );
   // SEL_TO_COMMAND(copyRuler:, );
-  SEL_TO_COMMAND(cut:, "cmd_cut");
-  SEL_TO_COMMAND(delete:, "cmd_delete");
-  SEL_TO_COMMAND(deleteBackward:, "cmd_deleteCharBackward");
+  SEL_TO_COMMAND(cut:, CommandCut);
+  SEL_TO_COMMAND(delete:, CommandDelete);
+  SEL_TO_COMMAND(deleteBackward:, CommandDeleteCharBackward);
   // SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
-  SEL_TO_COMMAND(deleteForward:, "cmd_deleteCharForward");
+  SEL_TO_COMMAND(deleteForward:, CommandDeleteCharForward);
 
   // TODO: deleteTo* selectors are also supposed to add text to a kill buffer
-  SEL_TO_COMMAND(deleteToBeginningOfLine:, "cmd_deleteToBeginningOfLine");
-  SEL_TO_COMMAND(deleteToBeginningOfParagraph:, "cmd_deleteToBeginningOfLine");
-  SEL_TO_COMMAND(deleteToEndOfLine:, "cmd_deleteToEndOfLine");
-  SEL_TO_COMMAND(deleteToEndOfParagraph:, "cmd_deleteToEndOfLine");
+  SEL_TO_COMMAND(deleteToBeginningOfLine:, CommandDeleteToBeginningOfLine);
+  SEL_TO_COMMAND(deleteToBeginningOfParagraph:, CommandDeleteToBeginningOfLine);
+  SEL_TO_COMMAND(deleteToEndOfLine:, CommandDeleteToEndOfLine);
+  SEL_TO_COMMAND(deleteToEndOfParagraph:, CommandDeleteToEndOfLine);
   // SEL_TO_COMMAND(deleteToMark:, );
 
-  SEL_TO_COMMAND(deleteWordBackward:, "cmd_deleteWordBackward");
-  SEL_TO_COMMAND(deleteWordForward:, "cmd_deleteWordForward");
+  SEL_TO_COMMAND(deleteWordBackward:, CommandDeleteWordBackward);
+  SEL_TO_COMMAND(deleteWordForward:, CommandDeleteWordForward);
   // SEL_TO_COMMAND(indent:, );
   // SEL_TO_COMMAND(insertBacktab:, );
   // SEL_TO_COMMAND(insertContainerBreak:, );
   // SEL_TO_COMMAND(insertLineBreak:, );
   // SEL_TO_COMMAND(insertNewline:, );
   // SEL_TO_COMMAND(insertNewlineIgnoringFieldEditor:, );
   // SEL_TO_COMMAND(insertParagraphSeparator:, );
   // SEL_TO_COMMAND(insertTab:, );
   // SEL_TO_COMMAND(insertTabIgnoringFieldEditor:, );
   // SEL_TO_COMMAND(insertDoubleQuoteIgnoringSubstitution:, );
   // SEL_TO_COMMAND(insertSingleQuoteIgnoringSubstitution:, );
   // SEL_TO_COMMAND(lowercaseWord:, );
-  SEL_TO_COMMAND(moveBackward:, "cmd_charPrevious");
-  SEL_TO_COMMAND(moveBackwardAndModifySelection:, "cmd_selectCharPrevious");
+  SEL_TO_COMMAND(moveBackward:, CommandCharPrevious);
+  SEL_TO_COMMAND(moveBackwardAndModifySelection:, CommandSelectCharPrevious);
   if (aType == eNativeKeyBindingsType_Input) {
-    SEL_TO_COMMAND(moveDown:, "cmd_endLine");
+    SEL_TO_COMMAND(moveDown:, CommandEndLine);
   } else {
-    SEL_TO_COMMAND(moveDown:, "cmd_lineNext");
+    SEL_TO_COMMAND(moveDown:, CommandLineNext);
   }
-  SEL_TO_COMMAND(moveDownAndModifySelection:, "cmd_selectLineNext");
-  SEL_TO_COMMAND(moveForward:, "cmd_charNext");
-  SEL_TO_COMMAND(moveForwardAndModifySelection:, "cmd_selectCharNext");
-  SEL_TO_COMMAND(moveLeft:, "cmd_charPrevious");
-  SEL_TO_COMMAND(moveLeftAndModifySelection:, "cmd_selectCharPrevious");
+  SEL_TO_COMMAND(moveDownAndModifySelection:, CommandSelectLineNext);
+  SEL_TO_COMMAND(moveForward:, CommandCharNext);
+  SEL_TO_COMMAND(moveForwardAndModifySelection:, CommandSelectCharNext);
+  SEL_TO_COMMAND(moveLeft:, CommandCharPrevious);
+  SEL_TO_COMMAND(moveLeftAndModifySelection:, CommandSelectCharPrevious);
   SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
-    "cmd_selectBeginLine");
-  SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, "cmd_selectEndLine");
-  SEL_TO_COMMAND(moveRight:, "cmd_charNext");
-  SEL_TO_COMMAND(moveRightAndModifySelection:, "cmd_selectCharNext");
-  SEL_TO_COMMAND(moveToBeginningOfDocument:, "cmd_moveTop");
-  SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:, "cmd_selectTop");
-  SEL_TO_COMMAND(moveToBeginningOfLine:, "cmd_beginLine");
+    CommandSelectBeginLine);
+  SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, CommandSelectEndLine);
+  SEL_TO_COMMAND(moveRight:, CommandCharNext);
+  SEL_TO_COMMAND(moveRightAndModifySelection:, CommandSelectCharNext);
+  SEL_TO_COMMAND(moveToBeginningOfDocument:, CommandMoveTop);
+  SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:,
+    CommandSelectTop);
+  SEL_TO_COMMAND(moveToBeginningOfLine:, CommandBeginLine);
   SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
-    "cmd_selectBeginLine");
-  SEL_TO_COMMAND(moveToBeginningOfParagraph:, "cmd_beginLine");
+    CommandSelectBeginLine);
+  SEL_TO_COMMAND(moveToBeginningOfParagraph:, CommandBeginLine);
   SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
-    "cmd_selectBeginLine");
-  SEL_TO_COMMAND(moveToEndOfDocument:, "cmd_moveBottom");
-  SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, "cmd_selectBottom");
-  SEL_TO_COMMAND(moveToEndOfLine:, "cmd_endLine");
-  SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, "cmd_selectEndLine");
-  SEL_TO_COMMAND(moveToEndOfParagraph:, "cmd_endLine");
-  SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, "cmd_selectEndLine");
-  SEL_TO_COMMAND(moveToLeftEndOfLine:, "cmd_beginLine");
-  SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:, "cmd_selectBeginLine");
-  SEL_TO_COMMAND(moveToRightEndOfLine:, "cmd_endLine");
-  SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, "cmd_selectEndLine");
+    CommandSelectBeginLine);
+  SEL_TO_COMMAND(moveToEndOfDocument:, CommandMoveBottom);
+  SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, CommandSelectBottom);
+  SEL_TO_COMMAND(moveToEndOfLine:, CommandEndLine);
+  SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, CommandSelectEndLine);
+  SEL_TO_COMMAND(moveToEndOfParagraph:, CommandEndLine);
+  SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, CommandSelectEndLine);
+  SEL_TO_COMMAND(moveToLeftEndOfLine:, CommandBeginLine);
+  SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
+    CommandSelectBeginLine);
+  SEL_TO_COMMAND(moveToRightEndOfLine:, CommandEndLine);
+  SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, CommandSelectEndLine);
   if (aType == eNativeKeyBindingsType_Input) {
-    SEL_TO_COMMAND(moveUp:, "cmd_beginLine");
+    SEL_TO_COMMAND(moveUp:, CommandBeginLine);
   } else {
-    SEL_TO_COMMAND(moveUp:, "cmd_linePrevious");
+    SEL_TO_COMMAND(moveUp:, CommandLinePrevious);
   }
-  SEL_TO_COMMAND(moveUpAndModifySelection:, "cmd_selectLinePrevious");
-  SEL_TO_COMMAND(moveWordBackward:, "cmd_wordPrevious");
-  SEL_TO_COMMAND(moveWordBackwardAndModifySelection:, "cmd_selectWordPrevious");
-  SEL_TO_COMMAND(moveWordForward:, "cmd_wordNext");
-  SEL_TO_COMMAND(moveWordForwardAndModifySelection:, "cmd_selectWordNext");
-  SEL_TO_COMMAND(moveWordLeft:, "cmd_wordPrevious");
-  SEL_TO_COMMAND(moveWordLeftAndModifySelection:, "cmd_selectWordPrevious");
-  SEL_TO_COMMAND(moveWordRight:, "cmd_wordNext");
-  SEL_TO_COMMAND(moveWordRightAndModifySelection:, "cmd_selectWordNext");
-  SEL_TO_COMMAND(pageDown:, "cmd_movePageDown");
-  SEL_TO_COMMAND(pageDownAndModifySelection:, "cmd_selectPageDown");
-  SEL_TO_COMMAND(pageUp:, "cmd_movePageUp");
-  SEL_TO_COMMAND(pageUpAndModifySelection:, "cmd_selectPageUp");
-  SEL_TO_COMMAND(paste:, "cmd_paste");
+  SEL_TO_COMMAND(moveUpAndModifySelection:, CommandSelectLinePrevious);
+  SEL_TO_COMMAND(moveWordBackward:, CommandWordPrevious);
+  SEL_TO_COMMAND(moveWordBackwardAndModifySelection:,
+    CommandSelectWordPrevious);
+  SEL_TO_COMMAND(moveWordForward:, CommandWordNext);
+  SEL_TO_COMMAND(moveWordForwardAndModifySelection:, CommandSelectWordNext);
+  SEL_TO_COMMAND(moveWordLeft:, CommandWordPrevious);
+  SEL_TO_COMMAND(moveWordLeftAndModifySelection:, CommandSelectWordPrevious);
+  SEL_TO_COMMAND(moveWordRight:, CommandWordNext);
+  SEL_TO_COMMAND(moveWordRightAndModifySelection:, CommandSelectWordNext);
+  SEL_TO_COMMAND(pageDown:, CommandMovePageDown);
+  SEL_TO_COMMAND(pageDownAndModifySelection:, CommandSelectPageDown);
+  SEL_TO_COMMAND(pageUp:, CommandMovePageUp);
+  SEL_TO_COMMAND(pageUpAndModifySelection:, CommandSelectPageUp);
+  SEL_TO_COMMAND(paste:, CommandPaste);
   // SEL_TO_COMMAND(pasteFont:, );
   // SEL_TO_COMMAND(pasteRuler:, );
-  SEL_TO_COMMAND(scrollLineDown:, "cmd_scrollLineDown");
-  SEL_TO_COMMAND(scrollLineUp:, "cmd_scrollLineUp");
-  SEL_TO_COMMAND(scrollPageDown:, "cmd_scrollPageDown");
-  SEL_TO_COMMAND(scrollPageUp:, "cmd_scrollPageUp");
-  SEL_TO_COMMAND(scrollToBeginningOfDocument:, "cmd_scrollTop");
-  SEL_TO_COMMAND(scrollToEndOfDocument:, "cmd_scrollBottom");
-  SEL_TO_COMMAND(selectAll:, "cmd_selectAll");
+  SEL_TO_COMMAND(scrollLineDown:, CommandScrollLineDown);
+  SEL_TO_COMMAND(scrollLineUp:, CommandScrollLineUp);
+  SEL_TO_COMMAND(scrollPageDown:, CommandScrollPageDown);
+  SEL_TO_COMMAND(scrollPageUp:, CommandScrollPageUp);
+  SEL_TO_COMMAND(scrollToBeginningOfDocument:, CommandScrollTop);
+  SEL_TO_COMMAND(scrollToEndOfDocument:, CommandScrollBottom);
+  SEL_TO_COMMAND(selectAll:, CommandSelectAll);
   // selectLine: is complex, see KeyDown
   if (aType == eNativeKeyBindingsType_Input) {
-    SEL_TO_COMMAND(selectParagraph:, "cmd_selectAll");
+    SEL_TO_COMMAND(selectParagraph:, CommandSelectAll);
   }
   // SEL_TO_COMMAND(selectToMark:, );
   // selectWord: is complex, see KeyDown
   // SEL_TO_COMMAND(setMark:, );
   // SEL_TO_COMMAND(showContextHelp:, );
   // SEL_TO_COMMAND(supplementalTargetForAction:sender:, );
   // SEL_TO_COMMAND(swapWithMark:, );
   // SEL_TO_COMMAND(transpose:, );
@@ -197,17 +200,17 @@ NativeKeyBindings::KeyPress(const Widget
 
   nsAutoTArray<KeyBindingsCommand, 2> bindingCommands;
   nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
 
   PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
     ("%p NativeKeyBindings::KeyPress, bindingCommands=%u",
      this, bindingCommands.Length()));
 
-  nsAutoTArray<const char*, 4> geckoCommands;
+  nsAutoTArray<Command, 4> geckoCommands;
 
   for (uint32_t i = 0; i < bindingCommands.Length(); i++) {
     SEL selector = bindingCommands[i].selector;
 
 #ifdef PR_LOGGING
     if (PR_LOG_TEST(gNativeKeyBindingsLog, PR_LOG_ALWAYS)) {
       NSString* selectorString = NSStringFromSelector(selector);
       nsAutoString nsSelectorString;
@@ -215,45 +218,45 @@ NativeKeyBindings::KeyPress(const Widget
 
       PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
         ("%p NativeKeyBindings::KeyPress, selector=%s",
          this, ToNewCString(nsSelectorString)));
     }
 #endif
 
     // Try to find a simple mapping in the hashtable
-    const char* commandStr = mSelectorToCommand.Get(
-      reinterpret_cast<struct objc_selector*>(selector));
+    Command geckoCommand = static_cast<Command>(mSelectorToCommand.Get(
+      reinterpret_cast<struct objc_selector*>(selector)));
 
-    if (commandStr) {
-      geckoCommands.AppendElement(commandStr);
+    if (geckoCommand) {
+      geckoCommands.AppendElement(geckoCommand);
     } else if (selector == @selector(selectLine:)) {
       // This is functional, but Cocoa's version is direction-less in that
       // selection direction is not determined until some future directed action
       // is taken. See bug 282097, comment 79 for more details.
-      geckoCommands.AppendElement("cmd_beginLine");
-      geckoCommands.AppendElement("cmd_selectEndLine");
+      geckoCommands.AppendElement(CommandBeginLine);
+      geckoCommands.AppendElement(CommandSelectEndLine);
     } else if (selector == @selector(selectWord:)) {
       // This is functional, but Cocoa's version is direction-less in that
       // selection direction is not determined until some future directed action
       // is taken. See bug 282097, comment 79 for more details.
-      geckoCommands.AppendElement("cmd_wordPrevious");
-      geckoCommands.AppendElement("cmd_selectWordNext");
+      geckoCommands.AppendElement(CommandWordPrevious);
+      geckoCommands.AppendElement(CommandSelectWordNext);
     }
   }
 
   if (geckoCommands.IsEmpty()) {
     PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
       ("%p NativeKeyBindings::KeyPress, handled=false", this));
 
     return false;
   }
 
   for (uint32_t i = 0; i < geckoCommands.Length(); i++) {
-    const char* geckoCommand = geckoCommands[i];
+    Command geckoCommand = geckoCommands[i];
 
     PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
       ("%p NativeKeyBindings::KeyPress, command=%s",
        this, geckoCommand));
 
     // Execute the Gecko command
     aCallback(geckoCommand, aCallbackData);
   }
--- a/widget/gtk/nsNativeKeyBindings.cpp
+++ b/widget/gtk/nsNativeKeyBindings.cpp
@@ -27,47 +27,47 @@ using namespace mozilla::widget;
 static nsINativeKeyBindings::DoCommandCallback gCurrentCallback;
 static void *gCurrentCallbackData;
 static bool gHandled;
 
 // Common GtkEntry and GtkTextView signals
 static void
 copy_clipboard_cb(GtkWidget *w, gpointer user_data)
 {
-  gCurrentCallback("cmd_copy", gCurrentCallbackData);
+  gCurrentCallback(CommandCopy, gCurrentCallbackData);
   g_signal_stop_emission_by_name(w, "copy_clipboard");
   gHandled = true;
 }
 
 static void
 cut_clipboard_cb(GtkWidget *w, gpointer user_data)
 {
-  gCurrentCallback("cmd_cut", gCurrentCallbackData);
+  gCurrentCallback(CommandCut, gCurrentCallbackData);
   g_signal_stop_emission_by_name(w, "cut_clipboard");
   gHandled = true;
 }
 
 // GTK distinguishes between display lines (wrapped, as they appear on the
 // screen) and paragraphs, which are runs of text terminated by a newline.
 // We don't have this distinction, so we always use editor's notion of
 // lines, which are newline-terminated.
 
-static const char *const sDeleteCommands[][2] = {
+static const Command sDeleteCommands[][2] = {
   // backward, forward
-  { "cmd_deleteCharBackward", "cmd_deleteCharForward" },    // CHARS
-  { "cmd_deleteWordBackward", "cmd_deleteWordForward" },    // WORD_ENDS
-  { "cmd_deleteWordBackward", "cmd_deleteWordForward" },    // WORDS
-  { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // LINES
-  { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // LINE_ENDS
-  { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // PARAGRAPH_ENDS
-  { "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // PARAGRAPHS
+  { CommandDeleteCharBackward, CommandDeleteCharForward },    // CHARS
+  { CommandDeleteWordBackward, CommandDeleteWordForward },    // WORD_ENDS
+  { CommandDeleteWordBackward, CommandDeleteWordForward },    // WORDS
+  { CommandDeleteToBeginningOfLine, CommandDeleteToEndOfLine }, // LINES
+  { CommandDeleteToBeginningOfLine, CommandDeleteToEndOfLine }, // LINE_ENDS
+  { CommandDeleteToBeginningOfLine, CommandDeleteToEndOfLine }, // PARAGRAPH_ENDS
+  { CommandDeleteToBeginningOfLine, CommandDeleteToEndOfLine }, // PARAGRAPHS
   // This deletes from the end of the previous word to the beginning of the
   // next word, but only if the caret is not in a word.
   // XXX need to implement in editor
-  { nullptr, nullptr } // WHITESPACE
+  { CommandDoNothing, CommandDoNothing } // WHITESPACE
 };
 
 static void
 delete_from_cursor_cb(GtkWidget *w, GtkDeleteType del_type,
                       gint count, gpointer user_data)
 {
   g_signal_stop_emission_by_name(w, "delete_from_cursor");
   gHandled = true;
@@ -77,127 +77,128 @@ delete_from_cursor_cb(GtkWidget *w, GtkD
     // unsupported deletion type
     return;
   }
 
   if (del_type == GTK_DELETE_WORDS) {
     // This works like word_ends, except we first move the caret to the
     // beginning/end of the current word.
     if (forward) {
-      gCurrentCallback("cmd_wordNext", gCurrentCallbackData);
-      gCurrentCallback("cmd_wordPrevious", gCurrentCallbackData);
+      gCurrentCallback(CommandWordNext, gCurrentCallbackData);
+      gCurrentCallback(CommandWordPrevious, gCurrentCallbackData);
     } else {
-      gCurrentCallback("cmd_wordPrevious", gCurrentCallbackData);
-      gCurrentCallback("cmd_wordNext", gCurrentCallbackData);
+      gCurrentCallback(CommandWordPrevious, gCurrentCallbackData);
+      gCurrentCallback(CommandWordNext, gCurrentCallbackData);
     }
   } else if (del_type == GTK_DELETE_DISPLAY_LINES ||
              del_type == GTK_DELETE_PARAGRAPHS) {
 
     // This works like display_line_ends, except we first move the caret to the
     // beginning/end of the current line.
     if (forward) {
-      gCurrentCallback("cmd_beginLine", gCurrentCallbackData);
+      gCurrentCallback(CommandBeginLine, gCurrentCallbackData);
     } else {
-      gCurrentCallback("cmd_endLine", gCurrentCallbackData);
+      gCurrentCallback(CommandEndLine, gCurrentCallbackData);
     }
   }
 
-  const char *cmd = sDeleteCommands[del_type][forward];
-  if (!cmd)
+  Command command = sDeleteCommands[del_type][forward];
+  if (!command) {
     return; // unsupported command
+  }
 
   unsigned int absCount = Abs(count);
   for (unsigned int i = 0; i < absCount; ++i) {
-    gCurrentCallback(cmd, gCurrentCallbackData);
+    gCurrentCallback(command, gCurrentCallbackData);
   }
 }
 
-static const char *const sMoveCommands[][2][2] = {
+static const Command sMoveCommands[][2][2] = {
   // non-extend { backward, forward }, extend { backward, forward }
   // GTK differentiates between logical position, which is prev/next,
   // and visual position, which is always left/right.
   // We should fix this to work the same way for RTL text input.
   { // LOGICAL_POSITIONS
-    { "cmd_charPrevious", "cmd_charNext" },
-    { "cmd_selectCharPrevious", "cmd_selectCharNext" }
+    { CommandCharPrevious, CommandCharNext },
+    { CommandSelectCharPrevious, CommandSelectCharNext }
   },
   { // VISUAL_POSITIONS
-    { "cmd_charPrevious", "cmd_charNext" },
-    { "cmd_selectCharPrevious", "cmd_selectCharNext" }
+    { CommandCharPrevious, CommandCharNext },
+    { CommandSelectCharPrevious, CommandSelectCharNext }
   },
   { // WORDS
-    { "cmd_wordPrevious", "cmd_wordNext" },
-    { "cmd_selectWordPrevious", "cmd_selectWordNext" }
+    { CommandWordPrevious, CommandWordNext },
+    { CommandSelectWordPrevious, CommandSelectWordNext }
   },
   { // DISPLAY_LINES
-    { "cmd_linePrevious", "cmd_lineNext" },
-    { "cmd_selectLinePrevious", "cmd_selectLineNext" }
+    { CommandLinePrevious, CommandLineNext },
+    { CommandSelectLinePrevious, CommandSelectLineNext }
   },
   { // DISPLAY_LINE_ENDS
-    { "cmd_beginLine", "cmd_endLine" },
-    { "cmd_selectBeginLine", "cmd_selectEndLine" }
+    { CommandBeginLine, CommandEndLine },
+    { CommandSelectBeginLine, CommandSelectEndLine }
   },
   { // PARAGRAPHS
-    { "cmd_linePrevious", "cmd_lineNext" },
-    { "cmd_selectLinePrevious", "cmd_selectLineNext" }
+    { CommandLinePrevious, CommandLineNext },
+    { CommandSelectLinePrevious, CommandSelectLineNext }
   },
   { // PARAGRAPH_ENDS
-    { "cmd_beginLine", "cmd_endLine" },
-    { "cmd_selectBeginLine", "cmd_selectEndLine" }
+    { CommandBeginLine, CommandEndLine },
+    { CommandSelectBeginLine, CommandSelectEndLine }
   },
   { // PAGES
-    { "cmd_movePageUp", "cmd_movePageDown" },
-    { "cmd_selectPageUp", "cmd_selectPageDown" }
+    { CommandMovePageUp, CommandMovePageDown },
+    { CommandSelectPageUp, CommandSelectPageDown }
   },
   { // BUFFER_ENDS
-    { "cmd_moveTop", "cmd_moveBottom" },
-    { "cmd_selectTop", "cmd_selectBottom" }
+    { CommandMoveTop, CommandMoveBottom },
+    { CommandSelectTop, CommandSelectBottom }
   },
   { // HORIZONTAL_PAGES (unsupported)
-    { nullptr, nullptr },
-    { nullptr, nullptr }
+    { CommandDoNothing, CommandDoNothing },
+    { CommandDoNothing, CommandDoNothing }
   }
 };
 
 static void
 move_cursor_cb(GtkWidget *w, GtkMovementStep step, gint count,
                gboolean extend_selection, gpointer user_data)
 {
   g_signal_stop_emission_by_name(w, "move_cursor");
   gHandled = true;
   bool forward = count > 0;
   if (uint32_t(step) >= ArrayLength(sMoveCommands)) {
     // unsupported movement type
     return;
   }
 
-  const char *cmd = sMoveCommands[step][extend_selection][forward];
-  if (!cmd)
+  Command command = sMoveCommands[step][extend_selection][forward];
+  if (!command) {
     return; // unsupported command
+  }
 
-  
   unsigned int absCount = Abs(count);
   for (unsigned int i = 0; i < absCount; ++i) {
-    gCurrentCallback(cmd, gCurrentCallbackData);
+    gCurrentCallback(command, gCurrentCallbackData);
   }
 }
 
 static void
 paste_clipboard_cb(GtkWidget *w, gpointer user_data)
 {
-  gCurrentCallback("cmd_paste", gCurrentCallbackData);
+  gCurrentCallback(CommandPaste, gCurrentCallbackData);
   g_signal_stop_emission_by_name(w, "paste_clipboard");
   gHandled = true;
 }
 
 // GtkTextView-only signals
 static void
 select_all_cb(GtkWidget *w, gboolean select, gpointer user_data)
 {
-  gCurrentCallback("cmd_selectAll", gCurrentCallbackData);
+  gCurrentCallback(CommandSelectAll, gCurrentCallbackData);
   g_signal_stop_emission_by_name(w, "select_all");
   gHandled = true;
 }
 
 void
 nsNativeKeyBindings::Init(NativeKeyBindingsType  aType)
 {
   switch (aType) {
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -101,16 +101,17 @@ EXPORTS += [
     'nsIWidget.h',
     'nsIWidgetListener.h',
     'nsWidgetInitData.h',
     'nsWidgetsCID.h',
 ]
 
 EXPORTS.mozilla += [
     'BasicEvents.h',
+    'CommandList.h',
     'ContentEvents.h',
     'EventClassList.h',
     'EventForwards.h',
     'LookAndFeel.h',
     'MiscEvents.h',
     'MouseEvents.h',
     'TextEvents.h',
     'TextRange.h',
--- a/widget/nsINativeKeyBindings.h
+++ b/widget/nsINativeKeyBindings.h
@@ -22,17 +22,17 @@ NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "
 NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea"
 
 #define NS_NATIVEKEYBINDINGSEDITOR_CONTRACTID \
 NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "editor"
 
 class nsINativeKeyBindings : public nsISupports
 {
  public:
-  typedef void (*DoCommandCallback)(const char *, void*);
+  typedef void (*DoCommandCallback)(mozilla::Command, void*);
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_INATIVEKEYBINDINGS_IID)
 
   virtual NS_HIDDEN_(bool) KeyDown(const mozilla::WidgetKeyboardEvent& aEvent,
                                    DoCommandCallback aCallback,
                                    void *aCallbackData) = 0;
 
   virtual NS_HIDDEN_(bool) KeyPress(const mozilla::WidgetKeyboardEvent& aEvent,
--- a/widget/shared/WidgetEventImpl.cpp
+++ b/widget/shared/WidgetEventImpl.cpp
@@ -302,9 +302,24 @@ WidgetKeyboardEvent::GetDOMKeyName(KeyNa
 
   // Subtract off 1 for the null terminator.
   aKeyName.Assign(table + offset, nextOffset - offset - 1);
 
 #undef KEY_STR_NUM
 #undef KEY_STR_NUM_INTERNAL
 }
 
+/* static */ const char*
+WidgetKeyboardEvent::GetCommandStr(Command aCommand)
+{
+#define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr
+  static const char* kCommands[] = {
+    "" // CommandDoNothing
+#include "mozilla/CommandList.h"
+  };
+#undef NS_DEFINE_COMMAND
+
+  MOZ_RELEASE_ASSERT(static_cast<size_t>(aCommand) < ArrayLength(kCommands),
+                     "Illegal command enumeration value");
+  return kCommands[aCommand];
+}
+
 } // namespace mozilla