Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "prlog.h"
11 #include "mozilla/TextEvents.h"
13 namespace mozilla {
14 namespace widget {
16 #ifdef PR_LOGGING
17 PRLogModuleInfo* gNativeKeyBindingsLog = nullptr;
18 #endif
20 NativeKeyBindings* NativeKeyBindings::sInstanceForSingleLineEditor = nullptr;
21 NativeKeyBindings* NativeKeyBindings::sInstanceForMultiLineEditor = nullptr;
23 // static
24 NativeKeyBindings*
25 NativeKeyBindings::GetInstance(NativeKeyBindingsType aType)
26 {
27 switch (aType) {
28 case nsIWidget::NativeKeyBindingsForSingleLineEditor:
29 if (!sInstanceForSingleLineEditor) {
30 sInstanceForSingleLineEditor = new NativeKeyBindings();
31 sInstanceForSingleLineEditor->Init(aType);
32 }
33 return sInstanceForSingleLineEditor;
34 case nsIWidget::NativeKeyBindingsForMultiLineEditor:
35 case nsIWidget::NativeKeyBindingsForRichTextEditor:
36 if (!sInstanceForMultiLineEditor) {
37 sInstanceForMultiLineEditor = new NativeKeyBindings();
38 sInstanceForMultiLineEditor->Init(aType);
39 }
40 return sInstanceForMultiLineEditor;
41 default:
42 MOZ_CRASH("Not implemented");
43 return nullptr;
44 }
45 }
47 // static
48 void
49 NativeKeyBindings::Shutdown()
50 {
51 delete sInstanceForSingleLineEditor;
52 sInstanceForSingleLineEditor = nullptr;
53 delete sInstanceForMultiLineEditor;
54 sInstanceForMultiLineEditor = nullptr;
55 }
57 NativeKeyBindings::NativeKeyBindings()
58 {
59 }
61 #define SEL_TO_COMMAND(aSel, aCommand) \
62 mSelectorToCommand.Put( \
63 reinterpret_cast<struct objc_selector *>(@selector(aSel)), aCommand)
65 void
66 NativeKeyBindings::Init(NativeKeyBindingsType aType)
67 {
68 #ifdef PR_LOGGING
69 if (!gNativeKeyBindingsLog) {
70 gNativeKeyBindingsLog = PR_NewLogModule("NativeKeyBindings");
71 }
72 #endif
74 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
75 ("%p NativeKeyBindings::Init", this));
77 // Many selectors have a one-to-one mapping to a Gecko command. Those mappings
78 // are registered in mSelectorToCommand.
80 // Selectors from NSResponder's "Responding to Action Messages" section and
81 // from NSText's "Action Methods for Editing" section
83 // TODO: Improves correctness of left / right meaning
84 // TODO: Add real paragraph motions
86 // SEL_TO_COMMAND(cancelOperation:, );
87 // SEL_TO_COMMAND(capitalizeWord:, );
88 // SEL_TO_COMMAND(centerSelectionInVisibleArea:, );
89 // SEL_TO_COMMAND(changeCaseOfLetter:, );
90 // SEL_TO_COMMAND(complete:, );
91 SEL_TO_COMMAND(copy:, CommandCopy);
92 // SEL_TO_COMMAND(copyFont:, );
93 // SEL_TO_COMMAND(copyRuler:, );
94 SEL_TO_COMMAND(cut:, CommandCut);
95 SEL_TO_COMMAND(delete:, CommandDelete);
96 SEL_TO_COMMAND(deleteBackward:, CommandDeleteCharBackward);
97 // SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
98 SEL_TO_COMMAND(deleteForward:, CommandDeleteCharForward);
100 // TODO: deleteTo* selectors are also supposed to add text to a kill buffer
101 SEL_TO_COMMAND(deleteToBeginningOfLine:, CommandDeleteToBeginningOfLine);
102 SEL_TO_COMMAND(deleteToBeginningOfParagraph:, CommandDeleteToBeginningOfLine);
103 SEL_TO_COMMAND(deleteToEndOfLine:, CommandDeleteToEndOfLine);
104 SEL_TO_COMMAND(deleteToEndOfParagraph:, CommandDeleteToEndOfLine);
105 // SEL_TO_COMMAND(deleteToMark:, );
107 SEL_TO_COMMAND(deleteWordBackward:, CommandDeleteWordBackward);
108 SEL_TO_COMMAND(deleteWordForward:, CommandDeleteWordForward);
109 // SEL_TO_COMMAND(indent:, );
110 // SEL_TO_COMMAND(insertBacktab:, );
111 // SEL_TO_COMMAND(insertContainerBreak:, );
112 // SEL_TO_COMMAND(insertLineBreak:, );
113 // SEL_TO_COMMAND(insertNewline:, );
114 // SEL_TO_COMMAND(insertNewlineIgnoringFieldEditor:, );
115 // SEL_TO_COMMAND(insertParagraphSeparator:, );
116 // SEL_TO_COMMAND(insertTab:, );
117 // SEL_TO_COMMAND(insertTabIgnoringFieldEditor:, );
118 // SEL_TO_COMMAND(insertDoubleQuoteIgnoringSubstitution:, );
119 // SEL_TO_COMMAND(insertSingleQuoteIgnoringSubstitution:, );
120 // SEL_TO_COMMAND(lowercaseWord:, );
121 SEL_TO_COMMAND(moveBackward:, CommandCharPrevious);
122 SEL_TO_COMMAND(moveBackwardAndModifySelection:, CommandSelectCharPrevious);
123 if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
124 SEL_TO_COMMAND(moveDown:, CommandEndLine);
125 } else {
126 SEL_TO_COMMAND(moveDown:, CommandLineNext);
127 }
128 SEL_TO_COMMAND(moveDownAndModifySelection:, CommandSelectLineNext);
129 SEL_TO_COMMAND(moveForward:, CommandCharNext);
130 SEL_TO_COMMAND(moveForwardAndModifySelection:, CommandSelectCharNext);
131 SEL_TO_COMMAND(moveLeft:, CommandCharPrevious);
132 SEL_TO_COMMAND(moveLeftAndModifySelection:, CommandSelectCharPrevious);
133 SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
134 CommandSelectBeginLine);
135 SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, CommandSelectEndLine);
136 SEL_TO_COMMAND(moveRight:, CommandCharNext);
137 SEL_TO_COMMAND(moveRightAndModifySelection:, CommandSelectCharNext);
138 SEL_TO_COMMAND(moveToBeginningOfDocument:, CommandMoveTop);
139 SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:,
140 CommandSelectTop);
141 SEL_TO_COMMAND(moveToBeginningOfLine:, CommandBeginLine);
142 SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
143 CommandSelectBeginLine);
144 SEL_TO_COMMAND(moveToBeginningOfParagraph:, CommandBeginLine);
145 SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
146 CommandSelectBeginLine);
147 SEL_TO_COMMAND(moveToEndOfDocument:, CommandMoveBottom);
148 SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, CommandSelectBottom);
149 SEL_TO_COMMAND(moveToEndOfLine:, CommandEndLine);
150 SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, CommandSelectEndLine);
151 SEL_TO_COMMAND(moveToEndOfParagraph:, CommandEndLine);
152 SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, CommandSelectEndLine);
153 SEL_TO_COMMAND(moveToLeftEndOfLine:, CommandBeginLine);
154 SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
155 CommandSelectBeginLine);
156 SEL_TO_COMMAND(moveToRightEndOfLine:, CommandEndLine);
157 SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, CommandSelectEndLine);
158 if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
159 SEL_TO_COMMAND(moveUp:, CommandBeginLine);
160 } else {
161 SEL_TO_COMMAND(moveUp:, CommandLinePrevious);
162 }
163 SEL_TO_COMMAND(moveUpAndModifySelection:, CommandSelectLinePrevious);
164 SEL_TO_COMMAND(moveWordBackward:, CommandWordPrevious);
165 SEL_TO_COMMAND(moveWordBackwardAndModifySelection:,
166 CommandSelectWordPrevious);
167 SEL_TO_COMMAND(moveWordForward:, CommandWordNext);
168 SEL_TO_COMMAND(moveWordForwardAndModifySelection:, CommandSelectWordNext);
169 SEL_TO_COMMAND(moveWordLeft:, CommandWordPrevious);
170 SEL_TO_COMMAND(moveWordLeftAndModifySelection:, CommandSelectWordPrevious);
171 SEL_TO_COMMAND(moveWordRight:, CommandWordNext);
172 SEL_TO_COMMAND(moveWordRightAndModifySelection:, CommandSelectWordNext);
173 SEL_TO_COMMAND(pageDown:, CommandMovePageDown);
174 SEL_TO_COMMAND(pageDownAndModifySelection:, CommandSelectPageDown);
175 SEL_TO_COMMAND(pageUp:, CommandMovePageUp);
176 SEL_TO_COMMAND(pageUpAndModifySelection:, CommandSelectPageUp);
177 SEL_TO_COMMAND(paste:, CommandPaste);
178 // SEL_TO_COMMAND(pasteFont:, );
179 // SEL_TO_COMMAND(pasteRuler:, );
180 SEL_TO_COMMAND(scrollLineDown:, CommandScrollLineDown);
181 SEL_TO_COMMAND(scrollLineUp:, CommandScrollLineUp);
182 SEL_TO_COMMAND(scrollPageDown:, CommandScrollPageDown);
183 SEL_TO_COMMAND(scrollPageUp:, CommandScrollPageUp);
184 SEL_TO_COMMAND(scrollToBeginningOfDocument:, CommandScrollTop);
185 SEL_TO_COMMAND(scrollToEndOfDocument:, CommandScrollBottom);
186 SEL_TO_COMMAND(selectAll:, CommandSelectAll);
187 // selectLine: is complex, see KeyDown
188 if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
189 SEL_TO_COMMAND(selectParagraph:, CommandSelectAll);
190 }
191 // SEL_TO_COMMAND(selectToMark:, );
192 // selectWord: is complex, see KeyDown
193 // SEL_TO_COMMAND(setMark:, );
194 // SEL_TO_COMMAND(showContextHelp:, );
195 // SEL_TO_COMMAND(supplementalTargetForAction:sender:, );
196 // SEL_TO_COMMAND(swapWithMark:, );
197 // SEL_TO_COMMAND(transpose:, );
198 // SEL_TO_COMMAND(transposeWords:, );
199 // SEL_TO_COMMAND(uppercaseWord:, );
200 // SEL_TO_COMMAND(yank:, );
201 }
203 #undef SEL_TO_COMMAND
205 bool
206 NativeKeyBindings::Execute(const WidgetKeyboardEvent& aEvent,
207 DoCommandCallback aCallback,
208 void* aCallbackData)
209 {
210 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
211 ("%p NativeKeyBindings::KeyPress", this));
213 // Recover the current event, which should always be the key down we are
214 // responding to.
216 NSEvent* cocoaEvent = reinterpret_cast<NSEvent*>(aEvent.mNativeKeyEvent);
218 if (!cocoaEvent || [cocoaEvent type] != NSKeyDown) {
219 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
220 ("%p NativeKeyBindings::KeyPress, no Cocoa key down event", this));
222 return false;
223 }
225 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
226 ("%p NativeKeyBindings::KeyPress, interpreting", this));
228 nsAutoTArray<KeyBindingsCommand, 2> bindingCommands;
229 nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
231 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
232 ("%p NativeKeyBindings::KeyPress, bindingCommands=%u",
233 this, bindingCommands.Length()));
235 nsAutoTArray<Command, 4> geckoCommands;
237 for (uint32_t i = 0; i < bindingCommands.Length(); i++) {
238 SEL selector = bindingCommands[i].selector;
240 #ifdef PR_LOGGING
241 if (PR_LOG_TEST(gNativeKeyBindingsLog, PR_LOG_ALWAYS)) {
242 NSString* selectorString = NSStringFromSelector(selector);
243 nsAutoString nsSelectorString;
244 nsCocoaUtils::GetStringForNSString(selectorString, nsSelectorString);
246 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
247 ("%p NativeKeyBindings::KeyPress, selector=%s",
248 this, ToNewCString(nsSelectorString)));
249 }
250 #endif
252 // Try to find a simple mapping in the hashtable
253 Command geckoCommand = static_cast<Command>(mSelectorToCommand.Get(
254 reinterpret_cast<struct objc_selector*>(selector)));
256 if (geckoCommand) {
257 geckoCommands.AppendElement(geckoCommand);
258 } else if (selector == @selector(selectLine:)) {
259 // This is functional, but Cocoa's version is direction-less in that
260 // selection direction is not determined until some future directed action
261 // is taken. See bug 282097, comment 79 for more details.
262 geckoCommands.AppendElement(CommandBeginLine);
263 geckoCommands.AppendElement(CommandSelectEndLine);
264 } else if (selector == @selector(selectWord:)) {
265 // This is functional, but Cocoa's version is direction-less in that
266 // selection direction is not determined until some future directed action
267 // is taken. See bug 282097, comment 79 for more details.
268 geckoCommands.AppendElement(CommandWordPrevious);
269 geckoCommands.AppendElement(CommandSelectWordNext);
270 }
271 }
273 if (geckoCommands.IsEmpty()) {
274 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
275 ("%p NativeKeyBindings::KeyPress, handled=false", this));
277 return false;
278 }
280 for (uint32_t i = 0; i < geckoCommands.Length(); i++) {
281 Command geckoCommand = geckoCommands[i];
283 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
284 ("%p NativeKeyBindings::KeyPress, command=%s",
285 this, geckoCommand));
287 // Execute the Gecko command
288 aCallback(geckoCommand, aCallbackData);
289 }
291 PR_LOG(gNativeKeyBindingsLog, PR_LOG_ALWAYS,
292 ("%p NativeKeyBindings::KeyPress, handled=true", this));
294 return true;
295 }
297 } // namespace widget
298 } // namespace mozilla