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