Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
8 #include "prlog.h"
10 #include "nsGtkKeyUtils.h"
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"
25 #ifdef PR_LOGGING
26 PRLogModuleInfo* gKeymapWrapperLog = nullptr;
27 #endif // PR_LOGGING
29 #include "mozilla/ArrayUtils.h"
30 #include "mozilla/MouseEvents.h"
31 #include "mozilla/TextEvents.h"
33 namespace mozilla {
34 namespace widget {
36 #define IS_ASCII_ALPHABETICAL(key) \
37 ((('a' <= key) && (key <= 'z')) || (('A' <= key) && (key <= 'Z')))
39 #define MOZ_MODIFIER_KEYS "MozKeymapWrapper"
41 KeymapWrapper* KeymapWrapper::sInstance = nullptr;
42 guint KeymapWrapper::sLastRepeatableHardwareKeyCode = 0;
43 KeymapWrapper::RepeatState KeymapWrapper::sRepeatState =
44 KeymapWrapper::NOT_PRESSED;
45 nsIBidiKeyboard* sBidiKeyboard = nullptr;
47 #ifdef PR_LOGGING
49 static const char* GetBoolName(bool aBool)
50 {
51 return aBool ? "TRUE" : "FALSE";
52 }
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 }
74 #endif // PR_LOGGING
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 }
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 }
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 }
146 /* static */ KeymapWrapper*
147 KeymapWrapper::GetInstance()
148 {
149 if (sInstance) {
150 sInstance->Init();
151 return sInstance;
152 }
154 sInstance = new KeymapWrapper();
155 return sInstance;
156 }
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
171 g_signal_connect(mGdkKeymap, "keys-changed",
172 (GCallback)OnKeysChanged, this);
174 // This is necessary for catching the destroying timing.
175 g_object_weak_ref(G_OBJECT(mGdkKeymap),
176 (GWeakNotify)OnDestroyKeymap, this);
178 InitXKBExtension();
180 Init();
181 }
183 void
184 KeymapWrapper::Init()
185 {
186 if (mInitialized) {
187 return;
188 }
189 mInitialized = true;
191 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
192 ("KeymapWrapper(%p): Init, mGdkKeymap=%p",
193 this, mGdkKeymap));
195 mModifierKeys.Clear();
196 memset(mModifierMasks, 0, sizeof(mModifierMasks));
198 InitBySystemSettings();
200 gdk_window_add_filter(nullptr, FilterEvents, this);
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 }
215 void
216 KeymapWrapper::InitXKBExtension()
217 {
218 PodZero(&mKeyboardState);
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 }
229 Display* display =
230 gdk_x11_display_get_xdisplay(gdk_display_get_default());
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 }
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 }
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 }
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 }
273 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
274 ("KeymapWrapper(%p): InitXKBExtension, Succeeded", this));
275 }
277 void
278 KeymapWrapper::InitBySystemSettings()
279 {
280 PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
281 ("KeymapWrapper(%p): InitBySystemSettings, mGdkKeymap=%p",
282 this, mGdkKeymap));
284 Display* display =
285 gdk_x11_display_get_xdisplay(gdk_display_get_default());
287 int min_keycode = 0;
288 int max_keycode = 0;
289 XDisplayKeycodes(display, &min_keycode, &max_keycode);
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 }
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));
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.
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.
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 }
345 ModifierKey* modifierKey = GetModifierKey(keycode);
346 if (!modifierKey) {
347 modifierKey = mModifierKeys.AppendElement(ModifierKey(keycode));
348 }
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;
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 }
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)));
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 }
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 }
438 XFreeModifiermap(xmodmap);
439 XFree(xkeymap);
440 }
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 }
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 }
518 return GDK_FILTER_CONTINUE;
519 }
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 }
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));
542 MOZ_ASSERT(sInstance == aKeymapWrapper,
543 "This instance must be the singleton instance");
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;
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 }
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 }
567 /* static */ bool
568 KeymapWrapper::AreModifiersCurrentlyActive(Modifiers aModifiers)
569 {
570 guint modifierState = GetCurrentModifierState();
571 return AreModifiersActive(aModifiers, modifierState);
572 }
574 /* static */ bool
575 KeymapWrapper::AreModifiersActive(Modifiers aModifiers,
576 guint aModifierState)
577 {
578 NS_ENSURE_TRUE(aModifiers, false);
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 }
594 /* static */ void
595 KeymapWrapper::InitInputEvent(WidgetInputEvent& aInputEvent,
596 guint aModifierState)
597 {
598 KeymapWrapper* keymapWrapper = GetInstance();
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 }
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)));
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 }
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 }
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 }
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 }
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 }
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 }
750 KeymapWrapper* keymapWrapper = GetInstance();
752 // Ignore all modifier state except NumLock.
753 guint baseState =
754 (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK));
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 }
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 }
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 }
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 }
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 }
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 }
830 KeyNameIndex
831 KeymapWrapper::ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent)
832 {
833 switch (aGdkKeyEvent->keyval) {
835 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
836 case aNativeKey: return aKeyNameIndex;
838 #include "NativeKeyToDOMKeyName.h"
840 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
842 default:
843 break;
844 }
846 return KEY_NAME_INDEX_Unidentified;
847 }
849 /* static */ void
850 KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
851 GdkEventKey* aGdkKeyEvent)
852 {
853 KeymapWrapper* keymapWrapper = GetInstance();
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);
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);
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;
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;
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;
955 default:
956 aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
957 break;
958 }
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())));
979 if (aKeyEvent.message == NS_KEY_PRESS) {
980 keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent);
981 }
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 }
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 }
1026 static const long MAX_UNICODE = 0x10FFFF;
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 }
1034 // I guess we couldn't convert
1035 return 0;
1036 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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;
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;
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;
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;
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;
1256 case GDK_Num_Lock: return NS_VK_NUM_LOCK;
1257 case GDK_Scroll_Lock: return NS_VK_SCROLL_LOCK;
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;
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;
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;
1299 // map Sun Keyboard special keysyms on to NS_VK keys
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 }
1309 void
1310 KeymapWrapper::InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent,
1311 GdkEventKey* aGdkKeyEvent)
1312 {
1313 NS_ENSURE_TRUE_VOID(aKeyEvent.message == NS_KEY_PRESS);
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 }
1324 // If the event causes inputting a character, keyCode must be zero.
1325 aKeyEvent.keyCode = 0;
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 }
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 }
1348 guint baseState = aGdkKeyEvent->state &
1349 ~(GetModifierMask(SHIFT) | GetModifierMask(CTRL) |
1350 GetModifierMask(ALT) | GetModifierMask(META) |
1351 GetModifierMask(SUPER) | GetModifierMask(HYPER));
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 }
1371 bool needLatinKeyCodes = !isLatin;
1372 if (!needLatinKeyCodes) {
1373 needLatinKeyCodes =
1374 (IS_ASCII_ALPHABETICAL(altCharCodes.mUnshiftedCharCode) !=
1375 IS_ASCII_ALPHABETICAL(altCharCodes.mShiftedCharCode));
1376 }
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 }
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 }
1404 AlternativeCharCode altLatinCharCodes(0, 0);
1405 uint32_t unmodifiedCh =
1406 aKeyEvent.IsShift() ? altCharCodes.mShiftedCharCode :
1407 altCharCodes.mUnshiftedCharCode;
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 }
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 }
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 }
1466 } // namespace widget
1467 } // namespace mozilla