|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim:expandtab:shiftwidth=4:tabstop=4: |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include "prlog.h" |
|
9 |
|
10 #include "nsGtkKeyUtils.h" |
|
11 |
|
12 #include <gdk/gdkkeysyms.h> |
|
13 #include <algorithm> |
|
14 #include <gdk/gdk.h> |
|
15 #include <gdk/gdkx.h> |
|
16 #if (MOZ_WIDGET_GTK == 3) |
|
17 #include <gdk/gdkkeysyms-compat.h> |
|
18 #endif |
|
19 #include <X11/XKBlib.h> |
|
20 #include "WidgetUtils.h" |
|
21 #include "keysym2ucs.h" |
|
22 #include "nsIBidiKeyboard.h" |
|
23 #include "nsServiceManagerUtils.h" |
|
24 |
|
25 #ifdef PR_LOGGING |
|
26 PRLogModuleInfo* gKeymapWrapperLog = nullptr; |
|
27 #endif // PR_LOGGING |
|
28 |
|
29 #include "mozilla/ArrayUtils.h" |
|
30 #include "mozilla/MouseEvents.h" |
|
31 #include "mozilla/TextEvents.h" |
|
32 |
|
33 namespace mozilla { |
|
34 namespace widget { |
|
35 |
|
36 #define IS_ASCII_ALPHABETICAL(key) \ |
|
37 ((('a' <= key) && (key <= 'z')) || (('A' <= key) && (key <= 'Z'))) |
|
38 |
|
39 #define MOZ_MODIFIER_KEYS "MozKeymapWrapper" |
|
40 |
|
41 KeymapWrapper* KeymapWrapper::sInstance = nullptr; |
|
42 guint KeymapWrapper::sLastRepeatableHardwareKeyCode = 0; |
|
43 KeymapWrapper::RepeatState KeymapWrapper::sRepeatState = |
|
44 KeymapWrapper::NOT_PRESSED; |
|
45 nsIBidiKeyboard* sBidiKeyboard = nullptr; |
|
46 |
|
47 #ifdef PR_LOGGING |
|
48 |
|
49 static const char* GetBoolName(bool aBool) |
|
50 { |
|
51 return aBool ? "TRUE" : "FALSE"; |
|
52 } |
|
53 |
|
54 /* static */ const char* |
|
55 KeymapWrapper::GetModifierName(Modifier aModifier) |
|
56 { |
|
57 switch (aModifier) { |
|
58 case CAPS_LOCK: return "CapsLock"; |
|
59 case NUM_LOCK: return "NumLock"; |
|
60 case SCROLL_LOCK: return "ScrollLock"; |
|
61 case SHIFT: return "Shift"; |
|
62 case CTRL: return "Ctrl"; |
|
63 case ALT: return "Alt"; |
|
64 case SUPER: return "Super"; |
|
65 case HYPER: return "Hyper"; |
|
66 case META: return "Meta"; |
|
67 case LEVEL3: return "Level3"; |
|
68 case LEVEL5: return "Level5"; |
|
69 case NOT_MODIFIER: return "NotModifier"; |
|
70 default: return "InvalidValue"; |
|
71 } |
|
72 } |
|
73 |
|
74 #endif // PR_LOGGING |
|
75 |
|
76 /* static */ KeymapWrapper::Modifier |
|
77 KeymapWrapper::GetModifierForGDKKeyval(guint aGdkKeyval) |
|
78 { |
|
79 switch (aGdkKeyval) { |
|
80 case GDK_Caps_Lock: return CAPS_LOCK; |
|
81 case GDK_Num_Lock: return NUM_LOCK; |
|
82 case GDK_Scroll_Lock: return SCROLL_LOCK; |
|
83 case GDK_Shift_Lock: |
|
84 case GDK_Shift_L: |
|
85 case GDK_Shift_R: return SHIFT; |
|
86 case GDK_Control_L: |
|
87 case GDK_Control_R: return CTRL; |
|
88 case GDK_Alt_L: |
|
89 case GDK_Alt_R: return ALT; |
|
90 case GDK_Super_L: |
|
91 case GDK_Super_R: return SUPER; |
|
92 case GDK_Hyper_L: |
|
93 case GDK_Hyper_R: return HYPER; |
|
94 case GDK_Meta_L: |
|
95 case GDK_Meta_R: return META; |
|
96 case GDK_ISO_Level3_Shift: |
|
97 case GDK_Mode_switch: return LEVEL3; |
|
98 case GDK_ISO_Level5_Shift: return LEVEL5; |
|
99 default: return NOT_MODIFIER; |
|
100 } |
|
101 } |
|
102 |
|
103 guint |
|
104 KeymapWrapper::GetModifierMask(Modifier aModifier) const |
|
105 { |
|
106 switch (aModifier) { |
|
107 case CAPS_LOCK: |
|
108 return GDK_LOCK_MASK; |
|
109 case NUM_LOCK: |
|
110 return mModifierMasks[INDEX_NUM_LOCK]; |
|
111 case SCROLL_LOCK: |
|
112 return mModifierMasks[INDEX_SCROLL_LOCK]; |
|
113 case SHIFT: |
|
114 return GDK_SHIFT_MASK; |
|
115 case CTRL: |
|
116 return GDK_CONTROL_MASK; |
|
117 case ALT: |
|
118 return mModifierMasks[INDEX_ALT]; |
|
119 case SUPER: |
|
120 return mModifierMasks[INDEX_SUPER]; |
|
121 case HYPER: |
|
122 return mModifierMasks[INDEX_HYPER]; |
|
123 case META: |
|
124 return mModifierMasks[INDEX_META]; |
|
125 case LEVEL3: |
|
126 return mModifierMasks[INDEX_LEVEL3]; |
|
127 case LEVEL5: |
|
128 return mModifierMasks[INDEX_LEVEL5]; |
|
129 default: |
|
130 return 0; |
|
131 } |
|
132 } |
|
133 |
|
134 KeymapWrapper::ModifierKey* |
|
135 KeymapWrapper::GetModifierKey(guint aHardwareKeycode) |
|
136 { |
|
137 for (uint32_t i = 0; i < mModifierKeys.Length(); i++) { |
|
138 ModifierKey& key = mModifierKeys[i]; |
|
139 if (key.mHardwareKeycode == aHardwareKeycode) { |
|
140 return &key; |
|
141 } |
|
142 } |
|
143 return nullptr; |
|
144 } |
|
145 |
|
146 /* static */ KeymapWrapper* |
|
147 KeymapWrapper::GetInstance() |
|
148 { |
|
149 if (sInstance) { |
|
150 sInstance->Init(); |
|
151 return sInstance; |
|
152 } |
|
153 |
|
154 sInstance = new KeymapWrapper(); |
|
155 return sInstance; |
|
156 } |
|
157 |
|
158 KeymapWrapper::KeymapWrapper() : |
|
159 mInitialized(false), mGdkKeymap(gdk_keymap_get_default()), |
|
160 mXKBBaseEventCode(0) |
|
161 { |
|
162 #ifdef PR_LOGGING |
|
163 if (!gKeymapWrapperLog) { |
|
164 gKeymapWrapperLog = PR_NewLogModule("KeymapWrapperWidgets"); |
|
165 } |
|
166 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
167 ("KeymapWrapper(%p): Constructor, mGdkKeymap=%p", |
|
168 this, mGdkKeymap)); |
|
169 #endif // PR_LOGGING |
|
170 |
|
171 g_signal_connect(mGdkKeymap, "keys-changed", |
|
172 (GCallback)OnKeysChanged, this); |
|
173 |
|
174 // This is necessary for catching the destroying timing. |
|
175 g_object_weak_ref(G_OBJECT(mGdkKeymap), |
|
176 (GWeakNotify)OnDestroyKeymap, this); |
|
177 |
|
178 InitXKBExtension(); |
|
179 |
|
180 Init(); |
|
181 } |
|
182 |
|
183 void |
|
184 KeymapWrapper::Init() |
|
185 { |
|
186 if (mInitialized) { |
|
187 return; |
|
188 } |
|
189 mInitialized = true; |
|
190 |
|
191 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
192 ("KeymapWrapper(%p): Init, mGdkKeymap=%p", |
|
193 this, mGdkKeymap)); |
|
194 |
|
195 mModifierKeys.Clear(); |
|
196 memset(mModifierMasks, 0, sizeof(mModifierMasks)); |
|
197 |
|
198 InitBySystemSettings(); |
|
199 |
|
200 gdk_window_add_filter(nullptr, FilterEvents, this); |
|
201 |
|
202 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
203 ("KeymapWrapper(%p): Init, CapsLock=0x%X, NumLock=0x%X, " |
|
204 "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, " |
|
205 "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X", |
|
206 this, |
|
207 GetModifierMask(CAPS_LOCK), GetModifierMask(NUM_LOCK), |
|
208 GetModifierMask(SCROLL_LOCK), GetModifierMask(LEVEL3), |
|
209 GetModifierMask(LEVEL5), |
|
210 GetModifierMask(SHIFT), GetModifierMask(CTRL), |
|
211 GetModifierMask(ALT), GetModifierMask(META), |
|
212 GetModifierMask(SUPER), GetModifierMask(HYPER))); |
|
213 } |
|
214 |
|
215 void |
|
216 KeymapWrapper::InitXKBExtension() |
|
217 { |
|
218 PodZero(&mKeyboardState); |
|
219 |
|
220 int xkbMajorVer = XkbMajorVersion; |
|
221 int xkbMinorVer = XkbMinorVersion; |
|
222 if (!XkbLibraryVersion(&xkbMajorVer, &xkbMinorVer)) { |
|
223 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
224 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " |
|
225 "XkbLibraryVersion()", this)); |
|
226 return; |
|
227 } |
|
228 |
|
229 Display* display = |
|
230 gdk_x11_display_get_xdisplay(gdk_display_get_default()); |
|
231 |
|
232 // XkbLibraryVersion() set xkbMajorVer and xkbMinorVer to that of the |
|
233 // library, which may be newer than what is required of the server in |
|
234 // XkbQueryExtension(), so these variables should be reset to |
|
235 // XkbMajorVersion and XkbMinorVersion before the XkbQueryExtension call. |
|
236 xkbMajorVer = XkbMajorVersion; |
|
237 xkbMinorVer = XkbMinorVersion; |
|
238 int opcode, baseErrorCode; |
|
239 if (!XkbQueryExtension(display, &opcode, &mXKBBaseEventCode, &baseErrorCode, |
|
240 &xkbMajorVer, &xkbMinorVer)) { |
|
241 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
242 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " |
|
243 "XkbQueryExtension(), display=0x%p", this, display)); |
|
244 return; |
|
245 } |
|
246 |
|
247 if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotify, |
|
248 XkbModifierStateMask, XkbModifierStateMask)) { |
|
249 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
250 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " |
|
251 "XkbSelectEventDetails() for XModifierStateMask, display=0x%p", |
|
252 this, display)); |
|
253 return; |
|
254 } |
|
255 |
|
256 if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbControlsNotify, |
|
257 XkbPerKeyRepeatMask, XkbPerKeyRepeatMask)) { |
|
258 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
259 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " |
|
260 "XkbSelectEventDetails() for XkbControlsNotify, display=0x%p", |
|
261 this, display)); |
|
262 return; |
|
263 } |
|
264 |
|
265 if (!XGetKeyboardControl(display, &mKeyboardState)) { |
|
266 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
267 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " |
|
268 "XGetKeyboardControl(), display=0x%p", |
|
269 this, display)); |
|
270 return; |
|
271 } |
|
272 |
|
273 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
274 ("KeymapWrapper(%p): InitXKBExtension, Succeeded", this)); |
|
275 } |
|
276 |
|
277 void |
|
278 KeymapWrapper::InitBySystemSettings() |
|
279 { |
|
280 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
281 ("KeymapWrapper(%p): InitBySystemSettings, mGdkKeymap=%p", |
|
282 this, mGdkKeymap)); |
|
283 |
|
284 Display* display = |
|
285 gdk_x11_display_get_xdisplay(gdk_display_get_default()); |
|
286 |
|
287 int min_keycode = 0; |
|
288 int max_keycode = 0; |
|
289 XDisplayKeycodes(display, &min_keycode, &max_keycode); |
|
290 |
|
291 int keysyms_per_keycode = 0; |
|
292 KeySym* xkeymap = XGetKeyboardMapping(display, min_keycode, |
|
293 max_keycode - min_keycode + 1, |
|
294 &keysyms_per_keycode); |
|
295 if (!xkeymap) { |
|
296 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
297 ("KeymapWrapper(%p): InitBySystemSettings, " |
|
298 "Failed due to null xkeymap", this)); |
|
299 return; |
|
300 } |
|
301 |
|
302 XModifierKeymap* xmodmap = XGetModifierMapping(display); |
|
303 if (!xmodmap) { |
|
304 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
305 ("KeymapWrapper(%p): InitBySystemSettings, " |
|
306 "Failed due to null xmodmap", this)); |
|
307 XFree(xkeymap); |
|
308 return; |
|
309 } |
|
310 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
311 ("KeymapWrapper(%p): InitBySystemSettings, min_keycode=%d, " |
|
312 "max_keycode=%d, keysyms_per_keycode=%d, max_keypermod=%d", |
|
313 this, min_keycode, max_keycode, keysyms_per_keycode, |
|
314 xmodmap->max_keypermod)); |
|
315 |
|
316 // The modifiermap member of the XModifierKeymap structure contains 8 sets |
|
317 // of max_keypermod KeyCodes, one for each modifier in the order Shift, |
|
318 // Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5. |
|
319 // Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are |
|
320 // ignored. |
|
321 |
|
322 // Note that two or more modifiers may use one modifier flag. E.g., |
|
323 // on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings. |
|
324 // And also Super and Hyper share the Mod4. In such cases, we need to |
|
325 // decide which modifier flag means one of DOM modifiers. |
|
326 |
|
327 // mod[0] is Modifier introduced by Mod1. |
|
328 Modifier mod[5]; |
|
329 int32_t foundLevel[5]; |
|
330 for (uint32_t i = 0; i < ArrayLength(mod); i++) { |
|
331 mod[i] = NOT_MODIFIER; |
|
332 foundLevel[i] = INT32_MAX; |
|
333 } |
|
334 const uint32_t map_size = 8 * xmodmap->max_keypermod; |
|
335 for (uint32_t i = 0; i < map_size; i++) { |
|
336 KeyCode keycode = xmodmap->modifiermap[i]; |
|
337 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
338 ("KeymapWrapper(%p): InitBySystemSettings, " |
|
339 " i=%d, keycode=0x%08X", |
|
340 this, i, keycode)); |
|
341 if (!keycode || keycode < min_keycode || keycode > max_keycode) { |
|
342 continue; |
|
343 } |
|
344 |
|
345 ModifierKey* modifierKey = GetModifierKey(keycode); |
|
346 if (!modifierKey) { |
|
347 modifierKey = mModifierKeys.AppendElement(ModifierKey(keycode)); |
|
348 } |
|
349 |
|
350 const KeySym* syms = |
|
351 xkeymap + (keycode - min_keycode) * keysyms_per_keycode; |
|
352 const uint32_t bit = i / xmodmap->max_keypermod; |
|
353 modifierKey->mMask |= 1 << bit; |
|
354 |
|
355 // We need to know the meaning of Mod1, Mod2, Mod3, Mod4 and Mod5. |
|
356 // Let's skip if current map is for others. |
|
357 if (bit < 3) { |
|
358 continue; |
|
359 } |
|
360 |
|
361 const int32_t modIndex = bit - 3; |
|
362 for (int32_t j = 0; j < keysyms_per_keycode; j++) { |
|
363 Modifier modifier = GetModifierForGDKKeyval(syms[j]); |
|
364 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
365 ("KeymapWrapper(%p): InitBySystemSettings, " |
|
366 " Mod%d, j=%d, syms[j]=%s(0x%X), modifier=%s", |
|
367 this, modIndex + 1, j, gdk_keyval_name(syms[j]), syms[j], |
|
368 GetModifierName(modifier))); |
|
369 |
|
370 switch (modifier) { |
|
371 case NOT_MODIFIER: |
|
372 // Don't overwrite the stored information with |
|
373 // NOT_MODIFIER. |
|
374 break; |
|
375 case CAPS_LOCK: |
|
376 case SHIFT: |
|
377 case CTRL: |
|
378 // Ignore the modifiers defined in GDK spec. They shouldn't |
|
379 // be mapped to Mod1-5 because they must not work on native |
|
380 // GTK applications. |
|
381 break; |
|
382 default: |
|
383 // If new modifier is found in higher level than stored |
|
384 // value, we don't need to overwrite it. |
|
385 if (j > foundLevel[modIndex]) { |
|
386 break; |
|
387 } |
|
388 // If new modifier is more important than stored value, |
|
389 // we should overwrite it with new modifier. |
|
390 if (j == foundLevel[modIndex]) { |
|
391 mod[modIndex] = std::min(modifier, mod[modIndex]); |
|
392 break; |
|
393 } |
|
394 foundLevel[modIndex] = j; |
|
395 mod[modIndex] = modifier; |
|
396 break; |
|
397 } |
|
398 } |
|
399 } |
|
400 |
|
401 for (uint32_t i = 0; i < COUNT_OF_MODIFIER_INDEX; i++) { |
|
402 Modifier modifier; |
|
403 switch (i) { |
|
404 case INDEX_NUM_LOCK: |
|
405 modifier = NUM_LOCK; |
|
406 break; |
|
407 case INDEX_SCROLL_LOCK: |
|
408 modifier = SCROLL_LOCK; |
|
409 break; |
|
410 case INDEX_ALT: |
|
411 modifier = ALT; |
|
412 break; |
|
413 case INDEX_META: |
|
414 modifier = META; |
|
415 break; |
|
416 case INDEX_SUPER: |
|
417 modifier = SUPER; |
|
418 break; |
|
419 case INDEX_HYPER: |
|
420 modifier = HYPER; |
|
421 break; |
|
422 case INDEX_LEVEL3: |
|
423 modifier = LEVEL3; |
|
424 break; |
|
425 case INDEX_LEVEL5: |
|
426 modifier = LEVEL5; |
|
427 break; |
|
428 default: |
|
429 MOZ_CRASH("All indexes must be handled here"); |
|
430 } |
|
431 for (uint32_t j = 0; j < ArrayLength(mod); j++) { |
|
432 if (modifier == mod[j]) { |
|
433 mModifierMasks[i] |= 1 << (j + 3); |
|
434 } |
|
435 } |
|
436 } |
|
437 |
|
438 XFreeModifiermap(xmodmap); |
|
439 XFree(xkeymap); |
|
440 } |
|
441 |
|
442 KeymapWrapper::~KeymapWrapper() |
|
443 { |
|
444 gdk_window_remove_filter(nullptr, FilterEvents, this); |
|
445 NS_IF_RELEASE(sBidiKeyboard); |
|
446 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
447 ("KeymapWrapper(%p): Destructor", this)); |
|
448 } |
|
449 |
|
450 /* static */ GdkFilterReturn |
|
451 KeymapWrapper::FilterEvents(GdkXEvent* aXEvent, |
|
452 GdkEvent* aGdkEvent, |
|
453 gpointer aData) |
|
454 { |
|
455 XEvent* xEvent = static_cast<XEvent*>(aXEvent); |
|
456 switch (xEvent->type) { |
|
457 case KeyPress: { |
|
458 // If the key doesn't support auto repeat, ignore the event because |
|
459 // even if such key (e.g., Shift) is pressed during auto repeat of |
|
460 // anoter key, it doesn't stop the auto repeat. |
|
461 KeymapWrapper* self = static_cast<KeymapWrapper*>(aData); |
|
462 if (!self->IsAutoRepeatableKey(xEvent->xkey.keycode)) { |
|
463 break; |
|
464 } |
|
465 if (sRepeatState == NOT_PRESSED) { |
|
466 sRepeatState = FIRST_PRESS; |
|
467 } else if (sLastRepeatableHardwareKeyCode == xEvent->xkey.keycode) { |
|
468 sRepeatState = REPEATING; |
|
469 } else { |
|
470 // If a different key is pressed while another key is pressed, |
|
471 // auto repeat system repeats only the last pressed key. |
|
472 // So, setting new keycode and setting repeat state as first key |
|
473 // press should work fine. |
|
474 sRepeatState = FIRST_PRESS; |
|
475 } |
|
476 sLastRepeatableHardwareKeyCode = xEvent->xkey.keycode; |
|
477 break; |
|
478 } |
|
479 case KeyRelease: { |
|
480 if (sLastRepeatableHardwareKeyCode != xEvent->xkey.keycode) { |
|
481 // This case means the key release event is caused by |
|
482 // a non-repeatable key such as Shift or a repeatable key that |
|
483 // was pressed before sLastRepeatableHardwareKeyCode was |
|
484 // pressed. |
|
485 break; |
|
486 } |
|
487 sRepeatState = NOT_PRESSED; |
|
488 break; |
|
489 } |
|
490 case FocusOut: { |
|
491 // At moving focus, we should reset keyboard repeat state. |
|
492 // Strictly, this causes incorrect behavior. However, this |
|
493 // correctness must be enough for web applications. |
|
494 sRepeatState = NOT_PRESSED; |
|
495 break; |
|
496 } |
|
497 default: { |
|
498 KeymapWrapper* self = static_cast<KeymapWrapper*>(aData); |
|
499 if (xEvent->type != self->mXKBBaseEventCode) { |
|
500 break; |
|
501 } |
|
502 XkbEvent* xkbEvent = (XkbEvent*)xEvent; |
|
503 if (xkbEvent->any.xkb_type != XkbControlsNotify || |
|
504 !(xkbEvent->ctrls.changed_ctrls & XkbPerKeyRepeatMask)) { |
|
505 break; |
|
506 } |
|
507 if (!XGetKeyboardControl(xkbEvent->any.display, |
|
508 &self->mKeyboardState)) { |
|
509 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
510 ("KeymapWrapper(%p): FilterEvents failed due to failure " |
|
511 "of XGetKeyboardControl(), display=0x%p", |
|
512 self, xkbEvent->any.display)); |
|
513 } |
|
514 break; |
|
515 } |
|
516 } |
|
517 |
|
518 return GDK_FILTER_CONTINUE; |
|
519 } |
|
520 |
|
521 /* static */ void |
|
522 KeymapWrapper::OnDestroyKeymap(KeymapWrapper* aKeymapWrapper, |
|
523 GdkKeymap *aGdkKeymap) |
|
524 { |
|
525 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
526 ("KeymapWrapper: OnDestroyKeymap, aGdkKeymap=%p, aKeymapWrapper=%p", |
|
527 aGdkKeymap, aKeymapWrapper)); |
|
528 MOZ_ASSERT(aKeymapWrapper == sInstance, |
|
529 "Desroying unexpected instance"); |
|
530 delete sInstance; |
|
531 sInstance = nullptr; |
|
532 } |
|
533 |
|
534 /* static */ void |
|
535 KeymapWrapper::OnKeysChanged(GdkKeymap *aGdkKeymap, |
|
536 KeymapWrapper* aKeymapWrapper) |
|
537 { |
|
538 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
539 ("KeymapWrapper: OnKeysChanged, aGdkKeymap=%p, aKeymapWrapper=%p", |
|
540 aGdkKeymap, aKeymapWrapper)); |
|
541 |
|
542 MOZ_ASSERT(sInstance == aKeymapWrapper, |
|
543 "This instance must be the singleton instance"); |
|
544 |
|
545 // We cannot reintialize here becasue we don't have GdkWindow which is using |
|
546 // the GdkKeymap. We'll reinitialize it when next GetInstance() is called. |
|
547 sInstance->mInitialized = false; |
|
548 |
|
549 // Reset the bidi keyboard settings for the new GdkKeymap |
|
550 if (!sBidiKeyboard) { |
|
551 CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard); |
|
552 } |
|
553 if (sBidiKeyboard) { |
|
554 sBidiKeyboard->Reset(); |
|
555 } |
|
556 } |
|
557 |
|
558 /* static */ guint |
|
559 KeymapWrapper::GetCurrentModifierState() |
|
560 { |
|
561 GdkModifierType modifiers; |
|
562 gdk_display_get_pointer(gdk_display_get_default(), |
|
563 nullptr, nullptr, nullptr, &modifiers); |
|
564 return static_cast<guint>(modifiers); |
|
565 } |
|
566 |
|
567 /* static */ bool |
|
568 KeymapWrapper::AreModifiersCurrentlyActive(Modifiers aModifiers) |
|
569 { |
|
570 guint modifierState = GetCurrentModifierState(); |
|
571 return AreModifiersActive(aModifiers, modifierState); |
|
572 } |
|
573 |
|
574 /* static */ bool |
|
575 KeymapWrapper::AreModifiersActive(Modifiers aModifiers, |
|
576 guint aModifierState) |
|
577 { |
|
578 NS_ENSURE_TRUE(aModifiers, false); |
|
579 |
|
580 KeymapWrapper* keymapWrapper = GetInstance(); |
|
581 for (uint32_t i = 0; i < sizeof(Modifier) * 8 && aModifiers; i++) { |
|
582 Modifier modifier = static_cast<Modifier>(1 << i); |
|
583 if (!(aModifiers & modifier)) { |
|
584 continue; |
|
585 } |
|
586 if (!(aModifierState & keymapWrapper->GetModifierMask(modifier))) { |
|
587 return false; |
|
588 } |
|
589 aModifiers &= ~modifier; |
|
590 } |
|
591 return true; |
|
592 } |
|
593 |
|
594 /* static */ void |
|
595 KeymapWrapper::InitInputEvent(WidgetInputEvent& aInputEvent, |
|
596 guint aModifierState) |
|
597 { |
|
598 KeymapWrapper* keymapWrapper = GetInstance(); |
|
599 |
|
600 aInputEvent.modifiers = 0; |
|
601 // DOM Meta key should be TRUE only on Mac. We need to discuss this |
|
602 // issue later. |
|
603 if (keymapWrapper->AreModifiersActive(SHIFT, aModifierState)) { |
|
604 aInputEvent.modifiers |= MODIFIER_SHIFT; |
|
605 } |
|
606 if (keymapWrapper->AreModifiersActive(CTRL, aModifierState)) { |
|
607 aInputEvent.modifiers |= MODIFIER_CONTROL; |
|
608 } |
|
609 if (keymapWrapper->AreModifiersActive(ALT, aModifierState)) { |
|
610 aInputEvent.modifiers |= MODIFIER_ALT; |
|
611 } |
|
612 if (keymapWrapper->AreModifiersActive(META, aModifierState)) { |
|
613 aInputEvent.modifiers |= MODIFIER_META; |
|
614 } |
|
615 if (keymapWrapper->AreModifiersActive(SUPER, aModifierState) || |
|
616 keymapWrapper->AreModifiersActive(HYPER, aModifierState)) { |
|
617 aInputEvent.modifiers |= MODIFIER_OS; |
|
618 } |
|
619 if (keymapWrapper->AreModifiersActive(LEVEL3, aModifierState) || |
|
620 keymapWrapper->AreModifiersActive(LEVEL5, aModifierState)) { |
|
621 aInputEvent.modifiers |= MODIFIER_ALTGRAPH; |
|
622 } |
|
623 if (keymapWrapper->AreModifiersActive(CAPS_LOCK, aModifierState)) { |
|
624 aInputEvent.modifiers |= MODIFIER_CAPSLOCK; |
|
625 } |
|
626 if (keymapWrapper->AreModifiersActive(NUM_LOCK, aModifierState)) { |
|
627 aInputEvent.modifiers |= MODIFIER_NUMLOCK; |
|
628 } |
|
629 if (keymapWrapper->AreModifiersActive(SCROLL_LOCK, aModifierState)) { |
|
630 aInputEvent.modifiers |= MODIFIER_SCROLLLOCK; |
|
631 } |
|
632 |
|
633 PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG, |
|
634 ("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X, " |
|
635 "aInputEvent.modifiers=0x%04X (Shift: %s, Control: %s, Alt: %s, " |
|
636 "Meta: %s, OS: %s, AltGr: %s, " |
|
637 "CapsLock: %s, NumLock: %s, ScrollLock: %s)", |
|
638 keymapWrapper, aModifierState, aInputEvent.modifiers, |
|
639 GetBoolName(aInputEvent.modifiers & MODIFIER_SHIFT), |
|
640 GetBoolName(aInputEvent.modifiers & MODIFIER_CONTROL), |
|
641 GetBoolName(aInputEvent.modifiers & MODIFIER_ALT), |
|
642 GetBoolName(aInputEvent.modifiers & MODIFIER_META), |
|
643 GetBoolName(aInputEvent.modifiers & MODIFIER_OS), |
|
644 GetBoolName(aInputEvent.modifiers & MODIFIER_ALTGRAPH), |
|
645 GetBoolName(aInputEvent.modifiers & MODIFIER_CAPSLOCK), |
|
646 GetBoolName(aInputEvent.modifiers & MODIFIER_NUMLOCK), |
|
647 GetBoolName(aInputEvent.modifiers & MODIFIER_SCROLLLOCK))); |
|
648 |
|
649 switch(aInputEvent.eventStructType) { |
|
650 case NS_MOUSE_EVENT: |
|
651 case NS_MOUSE_SCROLL_EVENT: |
|
652 case NS_WHEEL_EVENT: |
|
653 case NS_DRAG_EVENT: |
|
654 case NS_SIMPLE_GESTURE_EVENT: |
|
655 break; |
|
656 default: |
|
657 return; |
|
658 } |
|
659 |
|
660 WidgetMouseEventBase& mouseEvent = *aInputEvent.AsMouseEventBase(); |
|
661 mouseEvent.buttons = 0; |
|
662 if (aModifierState & GDK_BUTTON1_MASK) { |
|
663 mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag; |
|
664 } |
|
665 if (aModifierState & GDK_BUTTON3_MASK) { |
|
666 mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag; |
|
667 } |
|
668 if (aModifierState & GDK_BUTTON2_MASK) { |
|
669 mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag; |
|
670 } |
|
671 |
|
672 PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG, |
|
673 ("KeymapWrapper(%p): InitInputEvent, aInputEvent has buttons, " |
|
674 "aInputEvent.buttons=0x%04X (Left: %s, Right: %s, Middle: %s, " |
|
675 "4th (BACK): %s, 5th (FORWARD): %s)", |
|
676 keymapWrapper, mouseEvent.buttons, |
|
677 GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eLeftButtonFlag), |
|
678 GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eRightButtonFlag), |
|
679 GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eMiddleButtonFlag), |
|
680 GetBoolName(mouseEvent.buttons & WidgetMouseEvent::e4thButtonFlag), |
|
681 GetBoolName(mouseEvent.buttons & WidgetMouseEvent::e5thButtonFlag))); |
|
682 } |
|
683 |
|
684 /* static */ uint32_t |
|
685 KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent) |
|
686 { |
|
687 // If the keyval indicates it's a modifier key, we should use unshifted |
|
688 // key's modifier keyval. |
|
689 guint keyval = aGdkKeyEvent->keyval; |
|
690 if (GetModifierForGDKKeyval(keyval)) { |
|
691 // But if the keyval without modifiers isn't a modifier key, we |
|
692 // shouldn't use it. E.g., Japanese keyboard layout's |
|
693 // Shift + Eisu-Toggle key is CapsLock. This is an actual rare case, |
|
694 // Windows uses different keycode for a physical key for different |
|
695 // shift key state. |
|
696 guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent); |
|
697 if (GetModifierForGDKKeyval(keyvalWithoutModifier)) { |
|
698 keyval = keyvalWithoutModifier; |
|
699 } |
|
700 // Note that the modifier keycode and activating or deactivating |
|
701 // modifier flag may be mismatched, but it's okay. If a DOM key |
|
702 // event handler is testing a keydown event, it's more likely being |
|
703 // used to test which key is being pressed than to test which |
|
704 // modifier will become active. So, if we computed DOM keycode |
|
705 // from modifier flag which were changing by the physical key, then |
|
706 // there would be no other way for the user to generate the original |
|
707 // keycode. |
|
708 uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval); |
|
709 NS_ASSERTION(DOMKeyCode, "All modifier keys must have a DOM keycode"); |
|
710 return DOMKeyCode; |
|
711 } |
|
712 |
|
713 // If the key isn't printable, let's look at the key pairs. |
|
714 uint32_t charCode = GetCharCodeFor(aGdkKeyEvent); |
|
715 if (!charCode) { |
|
716 // Always use unshifted keycode for the non-printable key. |
|
717 // XXX It might be better to decide DOM keycode from all keyvals of |
|
718 // the hardware keycode. However, I think that it's too excessive. |
|
719 guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent); |
|
720 uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyvalWithoutModifier); |
|
721 if (!DOMKeyCode) { |
|
722 // If the unshifted keyval couldn't be mapped to a DOM keycode, |
|
723 // we should fallback to legacy logic, so, we should recompute with |
|
724 // the keyval with aGdkKeyEvent. |
|
725 DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval); |
|
726 } |
|
727 return DOMKeyCode; |
|
728 } |
|
729 |
|
730 // printable numpad keys should be resolved here. |
|
731 switch (keyval) { |
|
732 case GDK_KP_Multiply: return NS_VK_MULTIPLY; |
|
733 case GDK_KP_Add: return NS_VK_ADD; |
|
734 case GDK_KP_Separator: return NS_VK_SEPARATOR; |
|
735 case GDK_KP_Subtract: return NS_VK_SUBTRACT; |
|
736 case GDK_KP_Decimal: return NS_VK_DECIMAL; |
|
737 case GDK_KP_Divide: return NS_VK_DIVIDE; |
|
738 case GDK_KP_0: return NS_VK_NUMPAD0; |
|
739 case GDK_KP_1: return NS_VK_NUMPAD1; |
|
740 case GDK_KP_2: return NS_VK_NUMPAD2; |
|
741 case GDK_KP_3: return NS_VK_NUMPAD3; |
|
742 case GDK_KP_4: return NS_VK_NUMPAD4; |
|
743 case GDK_KP_5: return NS_VK_NUMPAD5; |
|
744 case GDK_KP_6: return NS_VK_NUMPAD6; |
|
745 case GDK_KP_7: return NS_VK_NUMPAD7; |
|
746 case GDK_KP_8: return NS_VK_NUMPAD8; |
|
747 case GDK_KP_9: return NS_VK_NUMPAD9; |
|
748 } |
|
749 |
|
750 KeymapWrapper* keymapWrapper = GetInstance(); |
|
751 |
|
752 // Ignore all modifier state except NumLock. |
|
753 guint baseState = |
|
754 (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK)); |
|
755 |
|
756 // Basically, we should use unmodified character for deciding our keyCode. |
|
757 uint32_t unmodifiedChar = |
|
758 keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, |
|
759 aGdkKeyEvent->group); |
|
760 if (IsBasicLatinLetterOrNumeral(unmodifiedChar)) { |
|
761 // If the unmodified character is an ASCII alphabet or an ASCII |
|
762 // numeric, it's the best hint for deciding our keyCode. |
|
763 return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar); |
|
764 } |
|
765 |
|
766 // If the unmodified character is not an ASCII character, that means we |
|
767 // couldn't find the hint. We should reset it. |
|
768 if (unmodifiedChar > 0x7F) { |
|
769 unmodifiedChar = 0; |
|
770 } |
|
771 |
|
772 // Retry with shifted keycode. |
|
773 guint shiftState = (baseState | keymapWrapper->GetModifierMask(SHIFT)); |
|
774 uint32_t shiftedChar = |
|
775 keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, |
|
776 aGdkKeyEvent->group); |
|
777 if (IsBasicLatinLetterOrNumeral(shiftedChar)) { |
|
778 // A shifted character can be an ASCII alphabet on Hebrew keyboard |
|
779 // layout. And also shifted character can be an ASCII numeric on |
|
780 // AZERTY keyboad layout. Then, it's a good hint for deciding our |
|
781 // keyCode. |
|
782 return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar); |
|
783 } |
|
784 |
|
785 // If the shifted unmodified character isn't an ASCII character, we should |
|
786 // discard it too. |
|
787 if (shiftedChar > 0x7F) { |
|
788 shiftedChar = 0; |
|
789 } |
|
790 |
|
791 // If current keyboard layout isn't ASCII alphabet inputtable layout, |
|
792 // look for ASCII alphabet inputtable keyboard layout. If the key |
|
793 // inputs an ASCII alphabet or an ASCII numeric, we should use it |
|
794 // for deciding our keyCode. |
|
795 // Note that it's important not to use alternative keyboard layout for ASCII |
|
796 // alphabet inputabble keyboard layout because the keycode for the key with |
|
797 // alternative keyboard layout may conflict with another key on current |
|
798 // keyboard layout. |
|
799 if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) { |
|
800 gint minGroup = keymapWrapper->GetFirstLatinGroup(); |
|
801 if (minGroup >= 0) { |
|
802 uint32_t unmodCharLatin = |
|
803 keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, |
|
804 minGroup); |
|
805 if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) { |
|
806 // If the unmodified character is an ASCII alphabet or |
|
807 // an ASCII numeric, we should use it for the keyCode. |
|
808 return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin); |
|
809 } |
|
810 uint32_t shiftedCharLatin = |
|
811 keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, |
|
812 minGroup); |
|
813 if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) { |
|
814 // If the shifted character is an ASCII alphabet or an ASCII |
|
815 // numeric, we should use it for the keyCode. |
|
816 return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin); |
|
817 } |
|
818 } |
|
819 } |
|
820 |
|
821 // If unmodified character is in ASCII range, use it. Otherwise, use |
|
822 // shifted character. |
|
823 if (!unmodifiedChar && !shiftedChar) { |
|
824 return 0; |
|
825 } |
|
826 return WidgetUtils::ComputeKeyCodeFromChar( |
|
827 unmodifiedChar ? unmodifiedChar : shiftedChar); |
|
828 } |
|
829 |
|
830 KeyNameIndex |
|
831 KeymapWrapper::ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent) |
|
832 { |
|
833 switch (aGdkKeyEvent->keyval) { |
|
834 |
|
835 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ |
|
836 case aNativeKey: return aKeyNameIndex; |
|
837 |
|
838 #include "NativeKeyToDOMKeyName.h" |
|
839 |
|
840 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX |
|
841 |
|
842 default: |
|
843 break; |
|
844 } |
|
845 |
|
846 return KEY_NAME_INDEX_Unidentified; |
|
847 } |
|
848 |
|
849 /* static */ void |
|
850 KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, |
|
851 GdkEventKey* aGdkKeyEvent) |
|
852 { |
|
853 KeymapWrapper* keymapWrapper = GetInstance(); |
|
854 |
|
855 aKeyEvent.mKeyNameIndex = |
|
856 keymapWrapper->ComputeDOMKeyNameIndex(aGdkKeyEvent); |
|
857 if (aKeyEvent.mKeyNameIndex == KEY_NAME_INDEX_Unidentified) { |
|
858 uint32_t charCode = GetCharCodeFor(aGdkKeyEvent); |
|
859 if (!charCode) { |
|
860 charCode = keymapWrapper->GetUnmodifiedCharCodeFor(aGdkKeyEvent); |
|
861 } |
|
862 if (charCode) { |
|
863 aKeyEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING; |
|
864 MOZ_ASSERT(aKeyEvent.mKeyValue.IsEmpty(), |
|
865 "Uninitialized mKeyValue must be empty"); |
|
866 AppendUCS4ToUTF16(charCode, aKeyEvent.mKeyValue); |
|
867 } |
|
868 } |
|
869 aKeyEvent.keyCode = ComputeDOMKeyCode(aGdkKeyEvent); |
|
870 |
|
871 // NOTE: The state of given key event indicates adjacent state of |
|
872 // modifier keys. E.g., even if the event is Shift key press event, |
|
873 // the bit for Shift is still false. By the same token, even if the |
|
874 // event is Shift key release event, the bit for Shift is still true. |
|
875 // Unfortunately, gdk_keyboard_get_modifiers() returns current modifier |
|
876 // state. It means if there're some pending modifier key press or |
|
877 // key release events, the result isn't what we want. |
|
878 guint modifierState = aGdkKeyEvent->state; |
|
879 if (aGdkKeyEvent->is_modifier) { |
|
880 Display* display = |
|
881 gdk_x11_display_get_xdisplay(gdk_display_get_default()); |
|
882 if (XEventsQueued(display, QueuedAfterReading)) { |
|
883 XEvent nextEvent; |
|
884 XPeekEvent(display, &nextEvent); |
|
885 if (nextEvent.type == keymapWrapper->mXKBBaseEventCode) { |
|
886 XkbEvent* XKBEvent = (XkbEvent*)&nextEvent; |
|
887 if (XKBEvent->any.xkb_type == XkbStateNotify) { |
|
888 XkbStateNotifyEvent* stateNotifyEvent = |
|
889 (XkbStateNotifyEvent*)XKBEvent; |
|
890 modifierState &= ~0xFF; |
|
891 modifierState |= stateNotifyEvent->lookup_mods; |
|
892 } |
|
893 } |
|
894 } |
|
895 } |
|
896 InitInputEvent(aKeyEvent, modifierState); |
|
897 |
|
898 switch (aGdkKeyEvent->keyval) { |
|
899 case GDK_Shift_L: |
|
900 case GDK_Control_L: |
|
901 case GDK_Alt_L: |
|
902 case GDK_Super_L: |
|
903 case GDK_Hyper_L: |
|
904 case GDK_Meta_L: |
|
905 aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT; |
|
906 break; |
|
907 |
|
908 case GDK_Shift_R: |
|
909 case GDK_Control_R: |
|
910 case GDK_Alt_R: |
|
911 case GDK_Super_R: |
|
912 case GDK_Hyper_R: |
|
913 case GDK_Meta_R: |
|
914 aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT; |
|
915 break; |
|
916 |
|
917 case GDK_KP_0: |
|
918 case GDK_KP_1: |
|
919 case GDK_KP_2: |
|
920 case GDK_KP_3: |
|
921 case GDK_KP_4: |
|
922 case GDK_KP_5: |
|
923 case GDK_KP_6: |
|
924 case GDK_KP_7: |
|
925 case GDK_KP_8: |
|
926 case GDK_KP_9: |
|
927 case GDK_KP_Space: |
|
928 case GDK_KP_Tab: |
|
929 case GDK_KP_Enter: |
|
930 case GDK_KP_F1: |
|
931 case GDK_KP_F2: |
|
932 case GDK_KP_F3: |
|
933 case GDK_KP_F4: |
|
934 case GDK_KP_Home: |
|
935 case GDK_KP_Left: |
|
936 case GDK_KP_Up: |
|
937 case GDK_KP_Right: |
|
938 case GDK_KP_Down: |
|
939 case GDK_KP_Prior: // same as GDK_KP_Page_Up |
|
940 case GDK_KP_Next: // same as GDK_KP_Page_Down |
|
941 case GDK_KP_End: |
|
942 case GDK_KP_Begin: |
|
943 case GDK_KP_Insert: |
|
944 case GDK_KP_Delete: |
|
945 case GDK_KP_Equal: |
|
946 case GDK_KP_Multiply: |
|
947 case GDK_KP_Add: |
|
948 case GDK_KP_Separator: |
|
949 case GDK_KP_Subtract: |
|
950 case GDK_KP_Decimal: |
|
951 case GDK_KP_Divide: |
|
952 aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD; |
|
953 break; |
|
954 |
|
955 default: |
|
956 aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD; |
|
957 break; |
|
958 } |
|
959 |
|
960 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
961 ("KeymapWrapper(%p): InitKeyEvent, modifierState=0x%08X " |
|
962 "aGdkKeyEvent={ type=%s, keyval=%s(0x%X), state=0x%08X, " |
|
963 "hardware_keycode=0x%08X, is_modifier=%s } " |
|
964 "aKeyEvent={ message=%s, isShift=%s, isControl=%s, " |
|
965 "isAlt=%s, isMeta=%s }", |
|
966 keymapWrapper, modifierState, |
|
967 ((aGdkKeyEvent->type == GDK_KEY_PRESS) ? |
|
968 "GDK_KEY_PRESS" : "GDK_KEY_RELEASE"), |
|
969 gdk_keyval_name(aGdkKeyEvent->keyval), |
|
970 aGdkKeyEvent->keyval, aGdkKeyEvent->state, |
|
971 aGdkKeyEvent->hardware_keycode, |
|
972 GetBoolName(aGdkKeyEvent->is_modifier), |
|
973 ((aKeyEvent.message == NS_KEY_DOWN) ? "NS_KEY_DOWN" : |
|
974 (aKeyEvent.message == NS_KEY_PRESS) ? "NS_KEY_PRESS" : |
|
975 "NS_KEY_UP"), |
|
976 GetBoolName(aKeyEvent.IsShift()), GetBoolName(aKeyEvent.IsControl()), |
|
977 GetBoolName(aKeyEvent.IsAlt()), GetBoolName(aKeyEvent.IsMeta()))); |
|
978 |
|
979 if (aKeyEvent.message == NS_KEY_PRESS) { |
|
980 keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent); |
|
981 } |
|
982 |
|
983 // The transformations above and in gdk for the keyval are not invertible |
|
984 // so link to the GdkEvent (which will vanish soon after return from the |
|
985 // event callback) to give plugins access to hardware_keycode and state. |
|
986 // (An XEvent would be nice but the GdkEvent is good enough.) |
|
987 aKeyEvent.pluginEvent = (void *)aGdkKeyEvent; |
|
988 aKeyEvent.time = aGdkKeyEvent->time; |
|
989 aKeyEvent.mNativeKeyEvent = static_cast<void*>(aGdkKeyEvent); |
|
990 aKeyEvent.mIsRepeat = sRepeatState == REPEATING && |
|
991 aGdkKeyEvent->hardware_keycode == sLastRepeatableHardwareKeyCode; |
|
992 } |
|
993 |
|
994 /* static */ uint32_t |
|
995 KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent) |
|
996 { |
|
997 // Anything above 0xf000 is considered a non-printable |
|
998 // Exception: directly encoded UCS characters |
|
999 if (aGdkKeyEvent->keyval > 0xf000 && |
|
1000 (aGdkKeyEvent->keyval & 0xff000000) != 0x01000000) { |
|
1001 // Keypad keys are an exception: they return a value different |
|
1002 // from their non-keypad equivalents, but mozilla doesn't distinguish. |
|
1003 switch (aGdkKeyEvent->keyval) { |
|
1004 case GDK_KP_Space: return ' '; |
|
1005 case GDK_KP_Equal: return '='; |
|
1006 case GDK_KP_Multiply: return '*'; |
|
1007 case GDK_KP_Add: return '+'; |
|
1008 case GDK_KP_Separator: return ','; |
|
1009 case GDK_KP_Subtract: return '-'; |
|
1010 case GDK_KP_Decimal: return '.'; |
|
1011 case GDK_KP_Divide: return '/'; |
|
1012 case GDK_KP_0: return '0'; |
|
1013 case GDK_KP_1: return '1'; |
|
1014 case GDK_KP_2: return '2'; |
|
1015 case GDK_KP_3: return '3'; |
|
1016 case GDK_KP_4: return '4'; |
|
1017 case GDK_KP_5: return '5'; |
|
1018 case GDK_KP_6: return '6'; |
|
1019 case GDK_KP_7: return '7'; |
|
1020 case GDK_KP_8: return '8'; |
|
1021 case GDK_KP_9: return '9'; |
|
1022 default: return 0; // non-printables |
|
1023 } |
|
1024 } |
|
1025 |
|
1026 static const long MAX_UNICODE = 0x10FFFF; |
|
1027 |
|
1028 // we're supposedly printable, let's try to convert |
|
1029 long ucs = keysym2ucs(aGdkKeyEvent->keyval); |
|
1030 if ((ucs != -1) && (ucs < MAX_UNICODE)) { |
|
1031 return ucs; |
|
1032 } |
|
1033 |
|
1034 // I guess we couldn't convert |
|
1035 return 0; |
|
1036 } |
|
1037 |
|
1038 uint32_t |
|
1039 KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent, |
|
1040 guint aModifierState, |
|
1041 gint aGroup) |
|
1042 { |
|
1043 guint keyval; |
|
1044 if (!gdk_keymap_translate_keyboard_state(mGdkKeymap, |
|
1045 aGdkKeyEvent->hardware_keycode, |
|
1046 GdkModifierType(aModifierState), |
|
1047 aGroup, &keyval, nullptr, nullptr, nullptr)) { |
|
1048 return 0; |
|
1049 } |
|
1050 GdkEventKey tmpEvent = *aGdkKeyEvent; |
|
1051 tmpEvent.state = aModifierState; |
|
1052 tmpEvent.keyval = keyval; |
|
1053 tmpEvent.group = aGroup; |
|
1054 return GetCharCodeFor(&tmpEvent); |
|
1055 } |
|
1056 |
|
1057 uint32_t |
|
1058 KeymapWrapper::GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent) |
|
1059 { |
|
1060 guint state = aGdkKeyEvent->state & |
|
1061 (GetModifierMask(SHIFT) | GetModifierMask(CAPS_LOCK) | |
|
1062 GetModifierMask(NUM_LOCK) | GetModifierMask(SCROLL_LOCK) | |
|
1063 GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5)); |
|
1064 uint32_t charCode = GetCharCodeFor(aGdkKeyEvent, GdkModifierType(state), |
|
1065 aGdkKeyEvent->group); |
|
1066 if (charCode) { |
|
1067 return charCode; |
|
1068 } |
|
1069 // If no character is mapped to the key when Level3 Shift or Level5 Shift |
|
1070 // is active, let's return a character which is inputted by the key without |
|
1071 // Level3 nor Level5 Shift. |
|
1072 guint stateWithoutAltGraph = |
|
1073 state & ~(GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5)); |
|
1074 if (state == stateWithoutAltGraph) { |
|
1075 return 0; |
|
1076 } |
|
1077 return GetCharCodeFor(aGdkKeyEvent, GdkModifierType(stateWithoutAltGraph), |
|
1078 aGdkKeyEvent->group); |
|
1079 } |
|
1080 |
|
1081 gint |
|
1082 KeymapWrapper::GetKeyLevel(GdkEventKey *aGdkKeyEvent) |
|
1083 { |
|
1084 gint level; |
|
1085 if (!gdk_keymap_translate_keyboard_state(mGdkKeymap, |
|
1086 aGdkKeyEvent->hardware_keycode, |
|
1087 GdkModifierType(aGdkKeyEvent->state), |
|
1088 aGdkKeyEvent->group, nullptr, nullptr, &level, nullptr)) { |
|
1089 return -1; |
|
1090 } |
|
1091 return level; |
|
1092 } |
|
1093 |
|
1094 gint |
|
1095 KeymapWrapper::GetFirstLatinGroup() |
|
1096 { |
|
1097 GdkKeymapKey *keys; |
|
1098 gint count; |
|
1099 gint minGroup = -1; |
|
1100 if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) { |
|
1101 // find the minimum number group for latin inputtable layout |
|
1102 for (gint i = 0; i < count && minGroup != 0; ++i) { |
|
1103 if (keys[i].level != 0 && keys[i].level != 1) { |
|
1104 continue; |
|
1105 } |
|
1106 if (minGroup >= 0 && keys[i].group > minGroup) { |
|
1107 continue; |
|
1108 } |
|
1109 minGroup = keys[i].group; |
|
1110 } |
|
1111 g_free(keys); |
|
1112 } |
|
1113 return minGroup; |
|
1114 } |
|
1115 |
|
1116 bool |
|
1117 KeymapWrapper::IsLatinGroup(guint8 aGroup) |
|
1118 { |
|
1119 GdkKeymapKey *keys; |
|
1120 gint count; |
|
1121 bool result = false; |
|
1122 if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) { |
|
1123 for (gint i = 0; i < count; ++i) { |
|
1124 if (keys[i].level != 0 && keys[i].level != 1) { |
|
1125 continue; |
|
1126 } |
|
1127 if (keys[i].group == aGroup) { |
|
1128 result = true; |
|
1129 break; |
|
1130 } |
|
1131 } |
|
1132 g_free(keys); |
|
1133 } |
|
1134 return result; |
|
1135 } |
|
1136 |
|
1137 bool |
|
1138 KeymapWrapper::IsAutoRepeatableKey(guint aHardwareKeyCode) |
|
1139 { |
|
1140 uint8_t indexOfArray = aHardwareKeyCode / 8; |
|
1141 MOZ_ASSERT(indexOfArray < ArrayLength(mKeyboardState.auto_repeats), |
|
1142 "invalid index"); |
|
1143 char bitMask = 1 << (aHardwareKeyCode % 8); |
|
1144 return (mKeyboardState.auto_repeats[indexOfArray] & bitMask) != 0; |
|
1145 } |
|
1146 |
|
1147 /* static */ bool |
|
1148 KeymapWrapper::IsBasicLatinLetterOrNumeral(uint32_t aCharCode) |
|
1149 { |
|
1150 return (aCharCode >= 'a' && aCharCode <= 'z') || |
|
1151 (aCharCode >= 'A' && aCharCode <= 'Z') || |
|
1152 (aCharCode >= '0' && aCharCode <= '9'); |
|
1153 } |
|
1154 |
|
1155 /* static */ guint |
|
1156 KeymapWrapper::GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent) |
|
1157 { |
|
1158 KeymapWrapper* keymapWrapper = GetInstance(); |
|
1159 guint state = |
|
1160 (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK)); |
|
1161 guint keyval; |
|
1162 if (!gdk_keymap_translate_keyboard_state(keymapWrapper->mGdkKeymap, |
|
1163 aGdkKeyEvent->hardware_keycode, GdkModifierType(state), |
|
1164 aGdkKeyEvent->group, &keyval, nullptr, nullptr, nullptr)) { |
|
1165 return 0; |
|
1166 } |
|
1167 return keyval; |
|
1168 } |
|
1169 |
|
1170 /* static */ uint32_t |
|
1171 KeymapWrapper::GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval) |
|
1172 { |
|
1173 switch (aGdkKeyval) { |
|
1174 case GDK_Cancel: return NS_VK_CANCEL; |
|
1175 case GDK_BackSpace: return NS_VK_BACK; |
|
1176 case GDK_Tab: |
|
1177 case GDK_ISO_Left_Tab: return NS_VK_TAB; |
|
1178 case GDK_Clear: return NS_VK_CLEAR; |
|
1179 case GDK_Return: return NS_VK_RETURN; |
|
1180 case GDK_Shift_L: |
|
1181 case GDK_Shift_R: |
|
1182 case GDK_Shift_Lock: return NS_VK_SHIFT; |
|
1183 case GDK_Control_L: |
|
1184 case GDK_Control_R: return NS_VK_CONTROL; |
|
1185 case GDK_Alt_L: |
|
1186 case GDK_Alt_R: return NS_VK_ALT; |
|
1187 case GDK_Meta_L: |
|
1188 case GDK_Meta_R: return NS_VK_META; |
|
1189 |
|
1190 // Assume that Super or Hyper is always mapped to physical Win key. |
|
1191 case GDK_Super_L: |
|
1192 case GDK_Super_R: |
|
1193 case GDK_Hyper_L: |
|
1194 case GDK_Hyper_R: return NS_VK_WIN; |
|
1195 |
|
1196 // GTK's AltGraph key is similar to Mac's Option (Alt) key. However, |
|
1197 // unfortunately, browsers on Mac are using NS_VK_ALT for it even though |
|
1198 // it's really different from Alt key on Windows. |
|
1199 // On the other hand, GTK's AltGrapsh keys are really different from |
|
1200 // Alt key. However, there is no AltGrapsh key on Windows. On Windows, |
|
1201 // both Ctrl and Alt keys are pressed internally when AltGr key is |
|
1202 // pressed. For some languages' users, AltGraph key is important, so, |
|
1203 // web applications on such locale may want to know AltGraph key press. |
|
1204 // Therefore, we should map AltGr keycode for them only on GTK. |
|
1205 case GDK_ISO_Level3_Shift: |
|
1206 case GDK_ISO_Level5_Shift: |
|
1207 // We assume that Mode_switch is always used for level3 shift. |
|
1208 case GDK_Mode_switch: return NS_VK_ALTGR; |
|
1209 |
|
1210 case GDK_Pause: return NS_VK_PAUSE; |
|
1211 case GDK_Caps_Lock: return NS_VK_CAPS_LOCK; |
|
1212 case GDK_Kana_Lock: |
|
1213 case GDK_Kana_Shift: return NS_VK_KANA; |
|
1214 case GDK_Hangul: return NS_VK_HANGUL; |
|
1215 // case GDK_XXX: return NS_VK_JUNJA; |
|
1216 // case GDK_XXX: return NS_VK_FINAL; |
|
1217 case GDK_Hangul_Hanja: return NS_VK_HANJA; |
|
1218 case GDK_Kanji: return NS_VK_KANJI; |
|
1219 case GDK_Escape: return NS_VK_ESCAPE; |
|
1220 case GDK_Henkan: return NS_VK_CONVERT; |
|
1221 case GDK_Muhenkan: return NS_VK_NONCONVERT; |
|
1222 // case GDK_XXX: return NS_VK_ACCEPT; |
|
1223 // case GDK_XXX: return NS_VK_MODECHANGE; |
|
1224 case GDK_Page_Up: return NS_VK_PAGE_UP; |
|
1225 case GDK_Page_Down: return NS_VK_PAGE_DOWN; |
|
1226 case GDK_End: return NS_VK_END; |
|
1227 case GDK_Home: return NS_VK_HOME; |
|
1228 case GDK_Left: return NS_VK_LEFT; |
|
1229 case GDK_Up: return NS_VK_UP; |
|
1230 case GDK_Right: return NS_VK_RIGHT; |
|
1231 case GDK_Down: return NS_VK_DOWN; |
|
1232 case GDK_Select: return NS_VK_SELECT; |
|
1233 case GDK_Print: return NS_VK_PRINT; |
|
1234 case GDK_Execute: return NS_VK_EXECUTE; |
|
1235 case GDK_Insert: return NS_VK_INSERT; |
|
1236 case GDK_Delete: return NS_VK_DELETE; |
|
1237 case GDK_Help: return NS_VK_HELP; |
|
1238 |
|
1239 // keypad keys |
|
1240 case GDK_KP_Left: return NS_VK_LEFT; |
|
1241 case GDK_KP_Right: return NS_VK_RIGHT; |
|
1242 case GDK_KP_Up: return NS_VK_UP; |
|
1243 case GDK_KP_Down: return NS_VK_DOWN; |
|
1244 case GDK_KP_Page_Up: return NS_VK_PAGE_UP; |
|
1245 // Not sure what these are |
|
1246 // case GDK_KP_Prior: return NS_VK_; |
|
1247 // case GDK_KP_Next: return NS_VK_; |
|
1248 case GDK_KP_Begin: return NS_VK_CLEAR; // Num-unlocked 5 |
|
1249 case GDK_KP_Page_Down: return NS_VK_PAGE_DOWN; |
|
1250 case GDK_KP_Home: return NS_VK_HOME; |
|
1251 case GDK_KP_End: return NS_VK_END; |
|
1252 case GDK_KP_Insert: return NS_VK_INSERT; |
|
1253 case GDK_KP_Delete: return NS_VK_DELETE; |
|
1254 case GDK_KP_Enter: return NS_VK_RETURN; |
|
1255 |
|
1256 case GDK_Num_Lock: return NS_VK_NUM_LOCK; |
|
1257 case GDK_Scroll_Lock: return NS_VK_SCROLL_LOCK; |
|
1258 |
|
1259 // Function keys |
|
1260 case GDK_F1: return NS_VK_F1; |
|
1261 case GDK_F2: return NS_VK_F2; |
|
1262 case GDK_F3: return NS_VK_F3; |
|
1263 case GDK_F4: return NS_VK_F4; |
|
1264 case GDK_F5: return NS_VK_F5; |
|
1265 case GDK_F6: return NS_VK_F6; |
|
1266 case GDK_F7: return NS_VK_F7; |
|
1267 case GDK_F8: return NS_VK_F8; |
|
1268 case GDK_F9: return NS_VK_F9; |
|
1269 case GDK_F10: return NS_VK_F10; |
|
1270 case GDK_F11: return NS_VK_F11; |
|
1271 case GDK_F12: return NS_VK_F12; |
|
1272 case GDK_F13: return NS_VK_F13; |
|
1273 case GDK_F14: return NS_VK_F14; |
|
1274 case GDK_F15: return NS_VK_F15; |
|
1275 case GDK_F16: return NS_VK_F16; |
|
1276 case GDK_F17: return NS_VK_F17; |
|
1277 case GDK_F18: return NS_VK_F18; |
|
1278 case GDK_F19: return NS_VK_F19; |
|
1279 case GDK_F20: return NS_VK_F20; |
|
1280 case GDK_F21: return NS_VK_F21; |
|
1281 case GDK_F22: return NS_VK_F22; |
|
1282 case GDK_F23: return NS_VK_F23; |
|
1283 case GDK_F24: return NS_VK_F24; |
|
1284 |
|
1285 // context menu key, keysym 0xff67, typically keycode 117 on 105-key |
|
1286 // (Microsoft) x86 keyboards, located between right 'Windows' key and |
|
1287 // right Ctrl key |
|
1288 case GDK_Menu: return NS_VK_CONTEXT_MENU; |
|
1289 case GDK_Sleep: return NS_VK_SLEEP; |
|
1290 |
|
1291 case GDK_3270_Attn: return NS_VK_ATTN; |
|
1292 case GDK_3270_CursorSelect: return NS_VK_CRSEL; |
|
1293 case GDK_3270_ExSelect: return NS_VK_EXSEL; |
|
1294 case GDK_3270_EraseEOF: return NS_VK_EREOF; |
|
1295 case GDK_3270_Play: return NS_VK_PLAY; |
|
1296 // case GDK_XXX: return NS_VK_ZOOM; |
|
1297 case GDK_3270_PA1: return NS_VK_PA1; |
|
1298 |
|
1299 // map Sun Keyboard special keysyms on to NS_VK keys |
|
1300 |
|
1301 // Sun F11 key generates SunF36(0x1005ff10) keysym |
|
1302 case 0x1005ff10: return NS_VK_F11; |
|
1303 // Sun F12 key generates SunF37(0x1005ff11) keysym |
|
1304 case 0x1005ff11: return NS_VK_F12; |
|
1305 default: return 0; |
|
1306 } |
|
1307 } |
|
1308 |
|
1309 void |
|
1310 KeymapWrapper::InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent, |
|
1311 GdkEventKey* aGdkKeyEvent) |
|
1312 { |
|
1313 NS_ENSURE_TRUE_VOID(aKeyEvent.message == NS_KEY_PRESS); |
|
1314 |
|
1315 aKeyEvent.charCode = GetCharCodeFor(aGdkKeyEvent); |
|
1316 if (!aKeyEvent.charCode) { |
|
1317 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
1318 ("KeymapWrapper(%p): InitKeypressEvent, " |
|
1319 "keyCode=0x%02X, charCode=0x%08X", |
|
1320 this, aKeyEvent.keyCode, aKeyEvent.charCode)); |
|
1321 return; |
|
1322 } |
|
1323 |
|
1324 // If the event causes inputting a character, keyCode must be zero. |
|
1325 aKeyEvent.keyCode = 0; |
|
1326 |
|
1327 // If Ctrl or Alt or Meta or OS is pressed, we need to append the key |
|
1328 // details for handling shortcut key. Otherwise, we have no additional |
|
1329 // work. |
|
1330 if (!aKeyEvent.IsControl() && !aKeyEvent.IsAlt() && |
|
1331 !aKeyEvent.IsMeta() && !aKeyEvent.IsOS()) { |
|
1332 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
1333 ("KeymapWrapper(%p): InitKeypressEvent, " |
|
1334 "keyCode=0x%02X, charCode=0x%08X", |
|
1335 this, aKeyEvent.keyCode, aKeyEvent.charCode)); |
|
1336 return; |
|
1337 } |
|
1338 |
|
1339 gint level = GetKeyLevel(aGdkKeyEvent); |
|
1340 if (level != 0 && level != 1) { |
|
1341 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
1342 ("KeymapWrapper(%p): InitKeypressEvent, " |
|
1343 "keyCode=0x%02X, charCode=0x%08X, level=%d", |
|
1344 this, aKeyEvent.keyCode, aKeyEvent.charCode, level)); |
|
1345 return; |
|
1346 } |
|
1347 |
|
1348 guint baseState = aGdkKeyEvent->state & |
|
1349 ~(GetModifierMask(SHIFT) | GetModifierMask(CTRL) | |
|
1350 GetModifierMask(ALT) | GetModifierMask(META) | |
|
1351 GetModifierMask(SUPER) | GetModifierMask(HYPER)); |
|
1352 |
|
1353 // We shold send both shifted char and unshifted char, all keyboard layout |
|
1354 // users can use all keys. Don't change event.charCode. On some keyboard |
|
1355 // layouts, Ctrl/Alt/Meta keys are used for inputting some characters. |
|
1356 AlternativeCharCode altCharCodes(0, 0); |
|
1357 // unshifted charcode of current keyboard layout. |
|
1358 altCharCodes.mUnshiftedCharCode = |
|
1359 GetCharCodeFor(aGdkKeyEvent, baseState, aGdkKeyEvent->group); |
|
1360 bool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF); |
|
1361 // shifted charcode of current keyboard layout. |
|
1362 altCharCodes.mShiftedCharCode = |
|
1363 GetCharCodeFor(aGdkKeyEvent, |
|
1364 baseState | GetModifierMask(SHIFT), |
|
1365 aGdkKeyEvent->group); |
|
1366 isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF); |
|
1367 if (altCharCodes.mUnshiftedCharCode || altCharCodes.mShiftedCharCode) { |
|
1368 aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes); |
|
1369 } |
|
1370 |
|
1371 bool needLatinKeyCodes = !isLatin; |
|
1372 if (!needLatinKeyCodes) { |
|
1373 needLatinKeyCodes = |
|
1374 (IS_ASCII_ALPHABETICAL(altCharCodes.mUnshiftedCharCode) != |
|
1375 IS_ASCII_ALPHABETICAL(altCharCodes.mShiftedCharCode)); |
|
1376 } |
|
1377 |
|
1378 // If current keyboard layout can input Latin characters, we don't need |
|
1379 // more information. |
|
1380 if (!needLatinKeyCodes) { |
|
1381 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
1382 ("KeymapWrapper(%p): InitKeypressEvent, keyCode=0x%02X, " |
|
1383 "charCode=0x%08X, level=%d, altCharCodes={ " |
|
1384 "mUnshiftedCharCode=0x%08X, mShiftedCharCode=0x%08X }", |
|
1385 this, aKeyEvent.keyCode, aKeyEvent.charCode, level, |
|
1386 altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode)); |
|
1387 return; |
|
1388 } |
|
1389 |
|
1390 // Next, find Latin inputtable keyboard layout. |
|
1391 gint minGroup = GetFirstLatinGroup(); |
|
1392 if (minGroup < 0) { |
|
1393 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
1394 ("KeymapWrapper(%p): InitKeypressEvent, " |
|
1395 "Latin keyboard layout isn't found: " |
|
1396 "keyCode=0x%02X, charCode=0x%08X, level=%d, " |
|
1397 "altCharCodes={ mUnshiftedCharCode=0x%08X, " |
|
1398 "mShiftedCharCode=0x%08X }", |
|
1399 this, aKeyEvent.keyCode, aKeyEvent.charCode, level, |
|
1400 altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode)); |
|
1401 return; |
|
1402 } |
|
1403 |
|
1404 AlternativeCharCode altLatinCharCodes(0, 0); |
|
1405 uint32_t unmodifiedCh = |
|
1406 aKeyEvent.IsShift() ? altCharCodes.mShiftedCharCode : |
|
1407 altCharCodes.mUnshiftedCharCode; |
|
1408 |
|
1409 // unshifted charcode of found keyboard layout. |
|
1410 uint32_t ch = GetCharCodeFor(aGdkKeyEvent, baseState, minGroup); |
|
1411 altLatinCharCodes.mUnshiftedCharCode = |
|
1412 IsBasicLatinLetterOrNumeral(ch) ? ch : 0; |
|
1413 // shifted charcode of found keyboard layout. |
|
1414 ch = GetCharCodeFor(aGdkKeyEvent, |
|
1415 baseState | GetModifierMask(SHIFT), |
|
1416 minGroup); |
|
1417 altLatinCharCodes.mShiftedCharCode = |
|
1418 IsBasicLatinLetterOrNumeral(ch) ? ch : 0; |
|
1419 if (altLatinCharCodes.mUnshiftedCharCode || |
|
1420 altLatinCharCodes.mShiftedCharCode) { |
|
1421 aKeyEvent.alternativeCharCodes.AppendElement(altLatinCharCodes); |
|
1422 } |
|
1423 // If the charCode is not Latin, and the level is 0 or 1, we should |
|
1424 // replace the charCode to Latin char if Alt and Meta keys are not |
|
1425 // pressed. (Alt should be sent the localized char for accesskey |
|
1426 // like handling of Web Applications.) |
|
1427 ch = aKeyEvent.IsShift() ? altLatinCharCodes.mShiftedCharCode : |
|
1428 altLatinCharCodes.mUnshiftedCharCode; |
|
1429 if (ch && !(aKeyEvent.IsAlt() || aKeyEvent.IsMeta()) && |
|
1430 aKeyEvent.charCode == unmodifiedCh) { |
|
1431 aKeyEvent.charCode = ch; |
|
1432 } |
|
1433 |
|
1434 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, |
|
1435 ("KeymapWrapper(%p): InitKeypressEvent, " |
|
1436 "keyCode=0x%02X, charCode=0x%08X, level=%d, minGroup=%d, " |
|
1437 "altCharCodes={ mUnshiftedCharCode=0x%08X, " |
|
1438 "mShiftedCharCode=0x%08X } " |
|
1439 "altLatinCharCodes={ mUnshiftedCharCode=0x%08X, " |
|
1440 "mShiftedCharCode=0x%08X }", |
|
1441 this, aKeyEvent.keyCode, aKeyEvent.charCode, level, minGroup, |
|
1442 altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode, |
|
1443 altLatinCharCodes.mUnshiftedCharCode, |
|
1444 altLatinCharCodes.mShiftedCharCode)); |
|
1445 } |
|
1446 |
|
1447 /* static */ bool |
|
1448 KeymapWrapper::IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent) |
|
1449 { |
|
1450 // If this is a modifier key event, we shouldn't send keypress event. |
|
1451 switch (ComputeDOMKeyCode(aGdkKeyEvent)) { |
|
1452 case NS_VK_SHIFT: |
|
1453 case NS_VK_CONTROL: |
|
1454 case NS_VK_ALT: |
|
1455 case NS_VK_ALTGR: |
|
1456 case NS_VK_WIN: |
|
1457 case NS_VK_CAPS_LOCK: |
|
1458 case NS_VK_NUM_LOCK: |
|
1459 case NS_VK_SCROLL_LOCK: |
|
1460 return false; |
|
1461 default: |
|
1462 return true; |
|
1463 } |
|
1464 } |
|
1465 |
|
1466 } // namespace widget |
|
1467 } // namespace mozilla |