1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 #include <dlfcn.h>
17 #include <gdk/gdkkeysyms-compat.h>
18 #include <X11/XKBlib.h>
19 #include "X11UndefineNone.h"
20 #include "IMContextWrapper.h"
21 #include "WidgetUtils.h"
22 #include "WidgetUtilsGtk.h"
23 #include "keysym2ucs.h"
24 #include "nsContentUtils.h"
25 #include "nsGtkUtils.h"
26 #include "nsIBidiKeyboard.h"
27 #include "nsPrintfCString.h"
28 #include "nsReadableUtils.h"
29 #include "nsServiceManagerUtils.h"
30 #include "nsWindow.h"
31 
32 #include "mozilla/ArrayUtils.h"
33 #include "mozilla/MouseEvents.h"
34 #include "mozilla/TextEventDispatcher.h"
35 #include "mozilla/TextEvents.h"
36 
37 #ifdef MOZ_WAYLAND
38 #  include <sys/mman.h>
39 #  include "nsWaylandDisplay.h"
40 #endif
41 
42 // For collecting other people's log, tell them `MOZ_LOG=KeyboardHandler:4,sync`
43 // rather than `MOZ_LOG=KeyboardHandler:5,sync` since using `5` may create too
44 // big file.
45 // Therefore you shouldn't use `LogLevel::Verbose` for logging usual behavior.
46 mozilla::LazyLogModule gKeyLog("KeyboardHandler");
47 
48 namespace mozilla {
49 namespace widget {
50 
51 #define IS_ASCII_ALPHABETICAL(key) \
52   ((('a' <= key) && (key <= 'z')) || (('A' <= key) && (key <= 'Z')))
53 
54 #define MOZ_MODIFIER_KEYS "MozKeymapWrapper"
55 
56 KeymapWrapper* KeymapWrapper::sInstance = nullptr;
57 guint KeymapWrapper::sLastRepeatableHardwareKeyCode = 0;
58 Time KeymapWrapper::sLastRepeatableKeyTime = 0;
59 KeymapWrapper::RepeatState KeymapWrapper::sRepeatState =
60     KeymapWrapper::NOT_PRESSED;
61 
GetBoolName(bool aBool)62 static const char* GetBoolName(bool aBool) { return aBool ? "TRUE" : "FALSE"; }
63 
GetStatusName(nsEventStatus aStatus)64 static const char* GetStatusName(nsEventStatus aStatus) {
65   switch (aStatus) {
66     case nsEventStatus_eConsumeDoDefault:
67       return "nsEventStatus_eConsumeDoDefault";
68     case nsEventStatus_eConsumeNoDefault:
69       return "nsEventStatus_eConsumeNoDefault";
70     case nsEventStatus_eIgnore:
71       return "nsEventStatus_eIgnore";
72     case nsEventStatus_eSentinel:
73       return "nsEventStatus_eSentinel";
74     default:
75       return "Illegal value";
76   }
77 }
78 
GetKeyLocationName(uint32_t aLocation)79 static const nsCString GetKeyLocationName(uint32_t aLocation) {
80   switch (aLocation) {
81     case eKeyLocationLeft:
82       return "KEY_LOCATION_LEFT"_ns;
83     case eKeyLocationRight:
84       return "KEY_LOCATION_RIGHT"_ns;
85     case eKeyLocationStandard:
86       return "KEY_LOCATION_STANDARD"_ns;
87     case eKeyLocationNumpad:
88       return "KEY_LOCATION_NUMPAD"_ns;
89     default:
90       return nsPrintfCString("Unknown (0x%04X)", aLocation);
91   }
92 }
93 
GetCharacterCodeName(char16_t aChar)94 static const nsCString GetCharacterCodeName(char16_t aChar) {
95   switch (aChar) {
96     case 0x0000:
97       return "NULL (0x0000)"_ns;
98     case 0x0008:
99       return "BACKSPACE (0x0008)"_ns;
100     case 0x0009:
101       return "CHARACTER TABULATION (0x0009)"_ns;
102     case 0x000A:
103       return "LINE FEED (0x000A)"_ns;
104     case 0x000B:
105       return "LINE TABULATION (0x000B)"_ns;
106     case 0x000C:
107       return "FORM FEED (0x000C)"_ns;
108     case 0x000D:
109       return "CARRIAGE RETURN (0x000D)"_ns;
110     case 0x0018:
111       return "CANCEL (0x0018)"_ns;
112     case 0x001B:
113       return "ESCAPE (0x001B)"_ns;
114     case 0x0020:
115       return "SPACE (0x0020)"_ns;
116     case 0x007F:
117       return "DELETE (0x007F)"_ns;
118     case 0x00A0:
119       return "NO-BREAK SPACE (0x00A0)"_ns;
120     case 0x00AD:
121       return "SOFT HYPHEN (0x00AD)"_ns;
122     case 0x2000:
123       return "EN QUAD (0x2000)"_ns;
124     case 0x2001:
125       return "EM QUAD (0x2001)"_ns;
126     case 0x2002:
127       return "EN SPACE (0x2002)"_ns;
128     case 0x2003:
129       return "EM SPACE (0x2003)"_ns;
130     case 0x2004:
131       return "THREE-PER-EM SPACE (0x2004)"_ns;
132     case 0x2005:
133       return "FOUR-PER-EM SPACE (0x2005)"_ns;
134     case 0x2006:
135       return "SIX-PER-EM SPACE (0x2006)"_ns;
136     case 0x2007:
137       return "FIGURE SPACE (0x2007)"_ns;
138     case 0x2008:
139       return "PUNCTUATION SPACE (0x2008)"_ns;
140     case 0x2009:
141       return "THIN SPACE (0x2009)"_ns;
142     case 0x200A:
143       return "HAIR SPACE (0x200A)"_ns;
144     case 0x200B:
145       return "ZERO WIDTH SPACE (0x200B)"_ns;
146     case 0x200C:
147       return "ZERO WIDTH NON-JOINER (0x200C)"_ns;
148     case 0x200D:
149       return "ZERO WIDTH JOINER (0x200D)"_ns;
150     case 0x200E:
151       return "LEFT-TO-RIGHT MARK (0x200E)"_ns;
152     case 0x200F:
153       return "RIGHT-TO-LEFT MARK (0x200F)"_ns;
154     case 0x2029:
155       return "PARAGRAPH SEPARATOR (0x2029)"_ns;
156     case 0x202A:
157       return "LEFT-TO-RIGHT EMBEDDING (0x202A)"_ns;
158     case 0x202B:
159       return "RIGHT-TO-LEFT EMBEDDING (0x202B)"_ns;
160     case 0x202D:
161       return "LEFT-TO-RIGHT OVERRIDE (0x202D)"_ns;
162     case 0x202E:
163       return "RIGHT-TO-LEFT OVERRIDE (0x202E)"_ns;
164     case 0x202F:
165       return "NARROW NO-BREAK SPACE (0x202F)"_ns;
166     case 0x205F:
167       return "MEDIUM MATHEMATICAL SPACE (0x205F)"_ns;
168     case 0x2060:
169       return "WORD JOINER (0x2060)"_ns;
170     case 0x2066:
171       return "LEFT-TO-RIGHT ISOLATE (0x2066)"_ns;
172     case 0x2067:
173       return "RIGHT-TO-LEFT ISOLATE (0x2067)"_ns;
174     case 0x3000:
175       return "IDEOGRAPHIC SPACE (0x3000)"_ns;
176     case 0xFEFF:
177       return "ZERO WIDTH NO-BREAK SPACE (0xFEFF)"_ns;
178     default: {
179       if (aChar < ' ' || (aChar >= 0x80 && aChar < 0xA0)) {
180         return nsPrintfCString("control (0x%04X)", aChar);
181       }
182       if (NS_IS_HIGH_SURROGATE(aChar)) {
183         return nsPrintfCString("high surrogate (0x%04X)", aChar);
184       }
185       if (NS_IS_LOW_SURROGATE(aChar)) {
186         return nsPrintfCString("low surrogate (0x%04X)", aChar);
187       }
188       return nsPrintfCString("'%s' (0x%04X)",
189                              NS_ConvertUTF16toUTF8(nsAutoString(aChar)).get(),
190                              aChar);
191     }
192   }
193 }
194 
GetCharacterCodeNames(const char16_t * aChars,uint32_t aLength)195 static const nsCString GetCharacterCodeNames(const char16_t* aChars,
196                                              uint32_t aLength) {
197   if (!aLength) {
198     return "\"\""_ns;
199   }
200   nsCString result;
201   result.AssignLiteral("\"");
202   StringJoinAppend(result, ", "_ns, Span{aChars, aLength},
203                    [](nsACString& dest, const char16_t charValue) {
204                      dest.Append(GetCharacterCodeName(charValue));
205                    });
206   result.AppendLiteral("\"");
207   return result;
208 }
209 
GetCharacterCodeNames(const nsAString & aString)210 static const nsCString GetCharacterCodeNames(const nsAString& aString) {
211   return GetCharacterCodeNames(aString.BeginReading(), aString.Length());
212 }
213 
GetModifierName(Modifier aModifier)214 /* static */ const char* KeymapWrapper::GetModifierName(Modifier aModifier) {
215   switch (aModifier) {
216     case CAPS_LOCK:
217       return "CapsLock";
218     case NUM_LOCK:
219       return "NumLock";
220     case SCROLL_LOCK:
221       return "ScrollLock";
222     case SHIFT:
223       return "Shift";
224     case CTRL:
225       return "Ctrl";
226     case ALT:
227       return "Alt";
228     case SUPER:
229       return "Super";
230     case HYPER:
231       return "Hyper";
232     case META:
233       return "Meta";
234     case LEVEL3:
235       return "Level3";
236     case LEVEL5:
237       return "Level5";
238     case NOT_MODIFIER:
239       return "NotModifier";
240     default:
241       return "InvalidValue";
242   }
243 }
244 
GetModifierForGDKKeyval(guint aGdkKeyval)245 /* static */ KeymapWrapper::Modifier KeymapWrapper::GetModifierForGDKKeyval(
246     guint aGdkKeyval) {
247   switch (aGdkKeyval) {
248     case GDK_Caps_Lock:
249       return CAPS_LOCK;
250     case GDK_Num_Lock:
251       return NUM_LOCK;
252     case GDK_Scroll_Lock:
253       return SCROLL_LOCK;
254     case GDK_Shift_Lock:
255     case GDK_Shift_L:
256     case GDK_Shift_R:
257       return SHIFT;
258     case GDK_Control_L:
259     case GDK_Control_R:
260       return CTRL;
261     case GDK_Alt_L:
262     case GDK_Alt_R:
263       return ALT;
264     case GDK_Super_L:
265     case GDK_Super_R:
266       return SUPER;
267     case GDK_Hyper_L:
268     case GDK_Hyper_R:
269       return HYPER;
270     case GDK_Meta_L:
271     case GDK_Meta_R:
272       return META;
273     case GDK_ISO_Level3_Shift:
274     case GDK_Mode_switch:
275       return LEVEL3;
276     case GDK_ISO_Level5_Shift:
277       return LEVEL5;
278     default:
279       return NOT_MODIFIER;
280   }
281 }
282 
GetModifierMask(Modifier aModifier) const283 guint KeymapWrapper::GetModifierMask(Modifier aModifier) const {
284   switch (aModifier) {
285     case CAPS_LOCK:
286       return GDK_LOCK_MASK;
287     case NUM_LOCK:
288       return mModifierMasks[INDEX_NUM_LOCK];
289     case SCROLL_LOCK:
290       return mModifierMasks[INDEX_SCROLL_LOCK];
291     case SHIFT:
292       return GDK_SHIFT_MASK;
293     case CTRL:
294       return GDK_CONTROL_MASK;
295     case ALT:
296       return mModifierMasks[INDEX_ALT];
297     case SUPER:
298       return mModifierMasks[INDEX_SUPER];
299     case HYPER:
300       return mModifierMasks[INDEX_HYPER];
301     case META:
302       return mModifierMasks[INDEX_META];
303     case LEVEL3:
304       return mModifierMasks[INDEX_LEVEL3];
305     case LEVEL5:
306       return mModifierMasks[INDEX_LEVEL5];
307     default:
308       return 0;
309   }
310 }
311 
GetModifierKey(guint aHardwareKeycode)312 KeymapWrapper::ModifierKey* KeymapWrapper::GetModifierKey(
313     guint aHardwareKeycode) {
314   for (uint32_t i = 0; i < mModifierKeys.Length(); i++) {
315     ModifierKey& key = mModifierKeys[i];
316     if (key.mHardwareKeycode == aHardwareKeycode) {
317       return &key;
318     }
319   }
320   return nullptr;
321 }
322 
323 /* static */
GetInstance()324 KeymapWrapper* KeymapWrapper::GetInstance() {
325   if (sInstance) {
326     sInstance->Init();
327     return sInstance;
328   }
329 
330   sInstance = new KeymapWrapper();
331   return sInstance;
332 }
333 
334 #ifdef MOZ_WAYLAND
EnsureInstance()335 void KeymapWrapper::EnsureInstance() { (void)GetInstance(); }
336 #endif
337 
338 /* static */
Shutdown()339 void KeymapWrapper::Shutdown() {
340   if (sInstance) {
341     delete sInstance;
342     sInstance = nullptr;
343   }
344 }
345 
KeymapWrapper()346 KeymapWrapper::KeymapWrapper()
347     : mInitialized(false),
348       mGdkKeymap(gdk_keymap_get_default()),
349       mXKBBaseEventCode(0),
350       mOnKeysChangedSignalHandle(0),
351       mOnDirectionChangedSignalHandle(0) {
352   MOZ_LOG(gKeyLog, LogLevel::Info,
353           ("%p Constructor, mGdkKeymap=%p", this, mGdkKeymap));
354 
355   g_object_ref(mGdkKeymap);
356 
357   if (GdkIsX11Display()) {
358     InitXKBExtension();
359   }
360 
361   Init();
362 }
363 
Init()364 void KeymapWrapper::Init() {
365   if (mInitialized) {
366     return;
367   }
368   mInitialized = true;
369 
370   MOZ_LOG(gKeyLog, LogLevel::Info,
371           ("%p Init, mGdkKeymap=%p", this, mGdkKeymap));
372 
373   mModifierKeys.Clear();
374   memset(mModifierMasks, 0, sizeof(mModifierMasks));
375 
376   if (GdkIsX11Display()) {
377     InitBySystemSettingsX11();
378   }
379 #ifdef MOZ_WAYLAND
380   else {
381     InitBySystemSettingsWayland();
382   }
383 #endif
384 
385   gdk_window_add_filter(nullptr, FilterEvents, this);
386 
387   MOZ_LOG(gKeyLog, LogLevel::Info,
388           ("%p Init, CapsLock=0x%X, NumLock=0x%X, "
389            "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
390            "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X",
391            this, GetModifierMask(CAPS_LOCK), GetModifierMask(NUM_LOCK),
392            GetModifierMask(SCROLL_LOCK), GetModifierMask(LEVEL3),
393            GetModifierMask(LEVEL5), GetModifierMask(SHIFT),
394            GetModifierMask(CTRL), GetModifierMask(ALT), GetModifierMask(META),
395            GetModifierMask(SUPER), GetModifierMask(HYPER)));
396 }
397 
InitXKBExtension()398 void KeymapWrapper::InitXKBExtension() {
399   PodZero(&mKeyboardState);
400 
401   int xkbMajorVer = XkbMajorVersion;
402   int xkbMinorVer = XkbMinorVersion;
403   if (!XkbLibraryVersion(&xkbMajorVer, &xkbMinorVer)) {
404     MOZ_LOG(gKeyLog, LogLevel::Info,
405             ("%p InitXKBExtension failed due to failure of "
406              "XkbLibraryVersion()",
407              this));
408     return;
409   }
410 
411   Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());
412 
413   // XkbLibraryVersion() set xkbMajorVer and xkbMinorVer to that of the
414   // library, which may be newer than what is required of the server in
415   // XkbQueryExtension(), so these variables should be reset to
416   // XkbMajorVersion and XkbMinorVersion before the XkbQueryExtension call.
417   xkbMajorVer = XkbMajorVersion;
418   xkbMinorVer = XkbMinorVersion;
419   int opcode, baseErrorCode;
420   if (!XkbQueryExtension(display, &opcode, &mXKBBaseEventCode, &baseErrorCode,
421                          &xkbMajorVer, &xkbMinorVer)) {
422     MOZ_LOG(gKeyLog, LogLevel::Info,
423             ("%p   InitXKBExtension failed due to failure of "
424              "XkbQueryExtension(), display=0x%p",
425              this, display));
426     return;
427   }
428 
429   if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotify,
430                              XkbModifierStateMask, XkbModifierStateMask)) {
431     MOZ_LOG(gKeyLog, LogLevel::Info,
432             ("%p   InitXKBExtension failed due to failure of "
433              "XkbSelectEventDetails() for XModifierStateMask, display=0x%p",
434              this, display));
435     return;
436   }
437 
438   if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbControlsNotify,
439                              XkbPerKeyRepeatMask, XkbPerKeyRepeatMask)) {
440     MOZ_LOG(gKeyLog, LogLevel::Info,
441             ("%p   InitXKBExtension failed due to failure of "
442              "XkbSelectEventDetails() for XkbControlsNotify, display=0x%p",
443              this, display));
444     return;
445   }
446 
447   if (!XGetKeyboardControl(display, &mKeyboardState)) {
448     MOZ_LOG(gKeyLog, LogLevel::Info,
449             ("%p   InitXKBExtension failed due to failure of "
450              "XGetKeyboardControl(), display=0x%p",
451              this, display));
452     return;
453   }
454 
455   MOZ_LOG(gKeyLog, LogLevel::Info, ("%p   InitXKBExtension, Succeeded", this));
456 }
457 
InitBySystemSettingsX11()458 void KeymapWrapper::InitBySystemSettingsX11() {
459   MOZ_LOG(gKeyLog, LogLevel::Info,
460           ("%p InitBySystemSettingsX11, mGdkKeymap=%p", this, mGdkKeymap));
461 
462   if (!mOnKeysChangedSignalHandle) {
463     mOnKeysChangedSignalHandle = g_signal_connect(
464         mGdkKeymap, "keys-changed", (GCallback)OnKeysChanged, this);
465   }
466   if (!mOnDirectionChangedSignalHandle) {
467     mOnDirectionChangedSignalHandle = g_signal_connect(
468         mGdkKeymap, "direction-changed", (GCallback)OnDirectionChanged, this);
469   }
470 
471   Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());
472 
473   int min_keycode = 0;
474   int max_keycode = 0;
475   XDisplayKeycodes(display, &min_keycode, &max_keycode);
476 
477   int keysyms_per_keycode = 0;
478   KeySym* xkeymap =
479       XGetKeyboardMapping(display, min_keycode, max_keycode - min_keycode + 1,
480                           &keysyms_per_keycode);
481   if (!xkeymap) {
482     MOZ_LOG(gKeyLog, LogLevel::Info,
483             ("%p   InitBySystemSettings, "
484              "Failed due to null xkeymap",
485              this));
486     return;
487   }
488 
489   XModifierKeymap* xmodmap = XGetModifierMapping(display);
490   if (!xmodmap) {
491     MOZ_LOG(gKeyLog, LogLevel::Info,
492             ("%p   InitBySystemSettings, "
493              "Failed due to null xmodmap",
494              this));
495     XFree(xkeymap);
496     return;
497   }
498   MOZ_LOG(gKeyLog, LogLevel::Info,
499           ("%p   InitBySystemSettings, min_keycode=%d, "
500            "max_keycode=%d, keysyms_per_keycode=%d, max_keypermod=%d",
501            this, min_keycode, max_keycode, keysyms_per_keycode,
502            xmodmap->max_keypermod));
503 
504   // The modifiermap member of the XModifierKeymap structure contains 8 sets
505   // of max_keypermod KeyCodes, one for each modifier in the order Shift,
506   // Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5.
507   // Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are
508   // ignored.
509 
510   // Note that two or more modifiers may use one modifier flag.  E.g.,
511   // on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings.
512   // And also Super and Hyper share the Mod4. In such cases, we need to
513   // decide which modifier flag means one of DOM modifiers.
514 
515   // mod[0] is Modifier introduced by Mod1.
516   Modifier mod[5];
517   int32_t foundLevel[5];
518   for (uint32_t i = 0; i < ArrayLength(mod); i++) {
519     mod[i] = NOT_MODIFIER;
520     foundLevel[i] = INT32_MAX;
521   }
522   const uint32_t map_size = 8 * xmodmap->max_keypermod;
523   for (uint32_t i = 0; i < map_size; i++) {
524     KeyCode keycode = xmodmap->modifiermap[i];
525     MOZ_LOG(gKeyLog, LogLevel::Info,
526             ("%p   InitBySystemSettings, "
527              "  i=%d, keycode=0x%08X",
528              this, i, keycode));
529     if (!keycode || keycode < min_keycode || keycode > max_keycode) {
530       continue;
531     }
532 
533     ModifierKey* modifierKey = GetModifierKey(keycode);
534     if (!modifierKey) {
535       modifierKey = mModifierKeys.AppendElement(ModifierKey(keycode));
536     }
537 
538     const KeySym* syms =
539         xkeymap + (keycode - min_keycode) * keysyms_per_keycode;
540     const uint32_t bit = i / xmodmap->max_keypermod;
541     modifierKey->mMask |= 1 << bit;
542 
543     // We need to know the meaning of Mod1, Mod2, Mod3, Mod4 and Mod5.
544     // Let's skip if current map is for others.
545     if (bit < 3) {
546       continue;
547     }
548 
549     const int32_t modIndex = bit - 3;
550     for (int32_t j = 0; j < keysyms_per_keycode; j++) {
551       Modifier modifier = GetModifierForGDKKeyval(syms[j]);
552       MOZ_LOG(gKeyLog, LogLevel::Info,
553               ("%p   InitBySystemSettings, "
554                "    Mod%d, j=%d, syms[j]=%s(0x%lX), modifier=%s",
555                this, modIndex + 1, j, gdk_keyval_name(syms[j]), syms[j],
556                GetModifierName(modifier)));
557 
558       switch (modifier) {
559         case NOT_MODIFIER:
560           // Don't overwrite the stored information with
561           // NOT_MODIFIER.
562           break;
563         case CAPS_LOCK:
564         case SHIFT:
565         case CTRL:
566           // Ignore the modifiers defined in GDK spec. They shouldn't
567           // be mapped to Mod1-5 because they must not work on native
568           // GTK applications.
569           break;
570         default:
571           // If new modifier is found in higher level than stored
572           // value, we don't need to overwrite it.
573           if (j > foundLevel[modIndex]) {
574             break;
575           }
576           // If new modifier is more important than stored value,
577           // we should overwrite it with new modifier.
578           if (j == foundLevel[modIndex]) {
579             mod[modIndex] = std::min(modifier, mod[modIndex]);
580             break;
581           }
582           foundLevel[modIndex] = j;
583           mod[modIndex] = modifier;
584           break;
585       }
586     }
587   }
588 
589   for (uint32_t i = 0; i < COUNT_OF_MODIFIER_INDEX; i++) {
590     Modifier modifier;
591     switch (i) {
592       case INDEX_NUM_LOCK:
593         modifier = NUM_LOCK;
594         break;
595       case INDEX_SCROLL_LOCK:
596         modifier = SCROLL_LOCK;
597         break;
598       case INDEX_ALT:
599         modifier = ALT;
600         break;
601       case INDEX_META:
602         modifier = META;
603         break;
604       case INDEX_SUPER:
605         modifier = SUPER;
606         break;
607       case INDEX_HYPER:
608         modifier = HYPER;
609         break;
610       case INDEX_LEVEL3:
611         modifier = LEVEL3;
612         break;
613       case INDEX_LEVEL5:
614         modifier = LEVEL5;
615         break;
616       default:
617         MOZ_CRASH("All indexes must be handled here");
618     }
619     for (uint32_t j = 0; j < ArrayLength(mod); j++) {
620       if (modifier == mod[j]) {
621         mModifierMasks[i] |= 1 << (j + 3);
622       }
623     }
624   }
625 
626   XFreeModifiermap(xmodmap);
627   XFree(xkeymap);
628 }
629 
630 #ifdef MOZ_WAYLAND
SetModifierMask(xkb_keymap * aKeymap,ModifierIndex aModifierIndex,const char * aModifierName)631 void KeymapWrapper::SetModifierMask(xkb_keymap* aKeymap,
632                                     ModifierIndex aModifierIndex,
633                                     const char* aModifierName) {
634   static auto sXkbKeymapModGetIndex =
635       (xkb_mod_index_t(*)(struct xkb_keymap*, const char*))dlsym(
636           RTLD_DEFAULT, "xkb_keymap_mod_get_index");
637 
638   xkb_mod_index_t index = sXkbKeymapModGetIndex(aKeymap, aModifierName);
639   if (index != XKB_MOD_INVALID) {
640     mModifierMasks[aModifierIndex] = (1 << index);
641   }
642 }
643 
SetModifierMasks(xkb_keymap * aKeymap)644 void KeymapWrapper::SetModifierMasks(xkb_keymap* aKeymap) {
645   KeymapWrapper* keymapWrapper = GetInstance();
646 
647   // This mapping is derived from get_xkb_modifiers() at gdkkeys-wayland.c
648   keymapWrapper->SetModifierMask(aKeymap, INDEX_NUM_LOCK, XKB_MOD_NAME_NUM);
649   keymapWrapper->SetModifierMask(aKeymap, INDEX_ALT, XKB_MOD_NAME_ALT);
650   keymapWrapper->SetModifierMask(aKeymap, INDEX_META, "Meta");
651   keymapWrapper->SetModifierMask(aKeymap, INDEX_SUPER, "Super");
652   keymapWrapper->SetModifierMask(aKeymap, INDEX_HYPER, "Hyper");
653 
654   keymapWrapper->SetModifierMask(aKeymap, INDEX_SCROLL_LOCK, "ScrollLock");
655   keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL3, "Level3");
656   keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL5, "Level5");
657 
658   MOZ_LOG(gKeyLog, LogLevel::Info,
659           ("%p KeymapWrapper::SetModifierMasks, CapsLock=0x%X, NumLock=0x%X, "
660            "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
661            "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X",
662            keymapWrapper, keymapWrapper->GetModifierMask(CAPS_LOCK),
663            keymapWrapper->GetModifierMask(NUM_LOCK),
664            keymapWrapper->GetModifierMask(SCROLL_LOCK),
665            keymapWrapper->GetModifierMask(LEVEL3),
666            keymapWrapper->GetModifierMask(LEVEL5),
667            keymapWrapper->GetModifierMask(SHIFT),
668            keymapWrapper->GetModifierMask(CTRL),
669            keymapWrapper->GetModifierMask(ALT),
670            keymapWrapper->GetModifierMask(META),
671            keymapWrapper->GetModifierMask(SUPER),
672            keymapWrapper->GetModifierMask(HYPER)));
673 }
674 
675 /* This keymap routine is derived from weston-2.0.0/clients/simple-im.c
676  */
keyboard_handle_keymap(void * data,struct wl_keyboard * wl_keyboard,uint32_t format,int fd,uint32_t size)677 static void keyboard_handle_keymap(void* data, struct wl_keyboard* wl_keyboard,
678                                    uint32_t format, int fd, uint32_t size) {
679   KeymapWrapper::ResetKeyboard();
680 
681   if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
682     close(fd);
683     return;
684   }
685 
686   char* mapString = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
687   if (mapString == MAP_FAILED) {
688     close(fd);
689     return;
690   }
691 
692   static auto sXkbContextNew =
693       (struct xkb_context * (*)(enum xkb_context_flags))
694           dlsym(RTLD_DEFAULT, "xkb_context_new");
695   static auto sXkbKeymapNewFromString =
696       (struct xkb_keymap * (*)(struct xkb_context*, const char*,
697                                enum xkb_keymap_format,
698                                enum xkb_keymap_compile_flags))
699           dlsym(RTLD_DEFAULT, "xkb_keymap_new_from_string");
700 
701   struct xkb_context* xkb_context = sXkbContextNew(XKB_CONTEXT_NO_FLAGS);
702   struct xkb_keymap* keymap =
703       sXkbKeymapNewFromString(xkb_context, mapString, XKB_KEYMAP_FORMAT_TEXT_V1,
704                               XKB_KEYMAP_COMPILE_NO_FLAGS);
705 
706   munmap(mapString, size);
707   close(fd);
708 
709   if (!keymap) {
710     NS_WARNING("keyboard_handle_keymap(): Failed to compile keymap!\n");
711     return;
712   }
713 
714   KeymapWrapper::SetModifierMasks(keymap);
715 
716   static auto sXkbKeymapUnRef =
717       (void (*)(struct xkb_keymap*))dlsym(RTLD_DEFAULT, "xkb_keymap_unref");
718   sXkbKeymapUnRef(keymap);
719 
720   static auto sXkbContextUnref =
721       (void (*)(struct xkb_context*))dlsym(RTLD_DEFAULT, "xkb_context_unref");
722   sXkbContextUnref(xkb_context);
723 }
724 
keyboard_handle_enter(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)725 static void keyboard_handle_enter(void* data, struct wl_keyboard* keyboard,
726                                   uint32_t serial, struct wl_surface* surface,
727                                   struct wl_array* keys) {
728   KeymapWrapper::SetFocusIn(surface, serial);
729 }
730 
keyboard_handle_leave(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface)731 static void keyboard_handle_leave(void* data, struct wl_keyboard* keyboard,
732                                   uint32_t serial, struct wl_surface* surface) {
733   KeymapWrapper::SetFocusOut(surface);
734 }
735 
keyboard_handle_key(void * data,struct wl_keyboard * keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state)736 static void keyboard_handle_key(void* data, struct wl_keyboard* keyboard,
737                                 uint32_t serial, uint32_t time, uint32_t key,
738                                 uint32_t state) {}
keyboard_handle_modifiers(void * data,struct wl_keyboard * keyboard,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)739 static void keyboard_handle_modifiers(void* data, struct wl_keyboard* keyboard,
740                                       uint32_t serial, uint32_t mods_depressed,
741                                       uint32_t mods_latched,
742                                       uint32_t mods_locked, uint32_t group) {}
743 
744 static const struct wl_keyboard_listener keyboard_listener = {
745     keyboard_handle_keymap, keyboard_handle_enter,     keyboard_handle_leave,
746     keyboard_handle_key,    keyboard_handle_modifiers,
747 };
748 
seat_handle_capabilities(void * data,struct wl_seat * seat,unsigned int caps)749 static void seat_handle_capabilities(void* data, struct wl_seat* seat,
750                                      unsigned int caps) {
751   static wl_keyboard* keyboard = nullptr;
752 
753   if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard) {
754     keyboard = wl_seat_get_keyboard(seat);
755     wl_keyboard_add_listener(keyboard, &keyboard_listener, nullptr);
756   } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard) {
757     wl_keyboard_destroy(keyboard);
758     keyboard = nullptr;
759   }
760 }
761 
762 static const struct wl_seat_listener seat_listener = {
763     seat_handle_capabilities,
764 };
765 
gdk_registry_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)766 static void gdk_registry_handle_global(void* data, struct wl_registry* registry,
767                                        uint32_t id, const char* interface,
768                                        uint32_t version) {
769   if (strcmp(interface, "wl_seat") == 0) {
770     auto* seat =
771         WaylandRegistryBind<wl_seat>(registry, id, &wl_seat_interface, 1);
772     KeymapWrapper::SetSeat(seat);
773     wl_seat_add_listener(seat, &seat_listener, data);
774   }
775 }
776 
gdk_registry_handle_global_remove(void * data,struct wl_registry * registry,uint32_t id)777 static void gdk_registry_handle_global_remove(void* data,
778                                               struct wl_registry* registry,
779                                               uint32_t id) {}
780 
781 static const struct wl_registry_listener keyboard_registry_listener = {
782     gdk_registry_handle_global, gdk_registry_handle_global_remove};
783 
InitBySystemSettingsWayland()784 void KeymapWrapper::InitBySystemSettingsWayland() {
785   wl_display* display = WaylandDisplayGetWLDisplay();
786   wl_registry_add_listener(wl_display_get_registry(display),
787                            &keyboard_registry_listener, this);
788 }
789 #endif
790 
~KeymapWrapper()791 KeymapWrapper::~KeymapWrapper() {
792   gdk_window_remove_filter(nullptr, FilterEvents, this);
793   if (mOnKeysChangedSignalHandle) {
794     g_signal_handler_disconnect(mGdkKeymap, mOnKeysChangedSignalHandle);
795   }
796   if (mOnDirectionChangedSignalHandle) {
797     g_signal_handler_disconnect(mGdkKeymap, mOnDirectionChangedSignalHandle);
798   }
799   g_object_unref(mGdkKeymap);
800   MOZ_LOG(gKeyLog, LogLevel::Info, ("%p Destructor", this));
801 }
802 
803 /* static */
FilterEvents(GdkXEvent * aXEvent,GdkEvent * aGdkEvent,gpointer aData)804 GdkFilterReturn KeymapWrapper::FilterEvents(GdkXEvent* aXEvent,
805                                             GdkEvent* aGdkEvent,
806                                             gpointer aData) {
807   XEvent* xEvent = static_cast<XEvent*>(aXEvent);
808   switch (xEvent->type) {
809     case KeyPress: {
810       // If the key doesn't support auto repeat, ignore the event because
811       // even if such key (e.g., Shift) is pressed during auto repeat of
812       // anoter key, it doesn't stop the auto repeat.
813       KeymapWrapper* self = static_cast<KeymapWrapper*>(aData);
814       if (!self->IsAutoRepeatableKey(xEvent->xkey.keycode)) {
815         break;
816       }
817       if (sRepeatState == NOT_PRESSED) {
818         sRepeatState = FIRST_PRESS;
819         MOZ_LOG(gKeyLog, LogLevel::Info,
820                 ("FilterEvents(aXEvent={ type=KeyPress, "
821                  "xkey={ keycode=0x%08X, state=0x%08X, time=%lu } }, "
822                  "aGdkEvent={ state=0x%08X }), "
823                  "detected first keypress",
824                  xEvent->xkey.keycode, xEvent->xkey.state, xEvent->xkey.time,
825                  reinterpret_cast<GdkEventKey*>(aGdkEvent)->state));
826       } else if (sLastRepeatableHardwareKeyCode == xEvent->xkey.keycode) {
827         if (sLastRepeatableKeyTime == xEvent->xkey.time &&
828             sLastRepeatableHardwareKeyCode ==
829                 IMContextWrapper::
830                     GetWaitingSynthesizedKeyPressHardwareKeyCode()) {
831           // On some environment, IM may generate duplicated KeyPress event
832           // without any special state flags.  In such case, we shouldn't
833           // treat the event as "repeated".
834           MOZ_LOG(gKeyLog, LogLevel::Info,
835                   ("FilterEvents(aXEvent={ type=KeyPress, "
836                    "xkey={ keycode=0x%08X, state=0x%08X, time=%lu } }, "
837                    "aGdkEvent={ state=0x%08X }), "
838                    "igored keypress since it must be synthesized by IME",
839                    xEvent->xkey.keycode, xEvent->xkey.state, xEvent->xkey.time,
840                    reinterpret_cast<GdkEventKey*>(aGdkEvent)->state));
841           break;
842         }
843         sRepeatState = REPEATING;
844         MOZ_LOG(gKeyLog, LogLevel::Info,
845                 ("FilterEvents(aXEvent={ type=KeyPress, "
846                  "xkey={ keycode=0x%08X, state=0x%08X, time=%lu } }, "
847                  "aGdkEvent={ state=0x%08X }), "
848                  "detected repeating keypress",
849                  xEvent->xkey.keycode, xEvent->xkey.state, xEvent->xkey.time,
850                  reinterpret_cast<GdkEventKey*>(aGdkEvent)->state));
851       } else {
852         // If a different key is pressed while another key is pressed,
853         // auto repeat system repeats only the last pressed key.
854         // So, setting new keycode and setting repeat state as first key
855         // press should work fine.
856         sRepeatState = FIRST_PRESS;
857         MOZ_LOG(gKeyLog, LogLevel::Info,
858                 ("FilterEvents(aXEvent={ type=KeyPress, "
859                  "xkey={ keycode=0x%08X, state=0x%08X, time=%lu } }, "
860                  "aGdkEvent={ state=0x%08X }), "
861                  "detected different keypress",
862                  xEvent->xkey.keycode, xEvent->xkey.state, xEvent->xkey.time,
863                  reinterpret_cast<GdkEventKey*>(aGdkEvent)->state));
864       }
865       sLastRepeatableHardwareKeyCode = xEvent->xkey.keycode;
866       sLastRepeatableKeyTime = xEvent->xkey.time;
867       break;
868     }
869     case KeyRelease: {
870       if (sLastRepeatableHardwareKeyCode != xEvent->xkey.keycode) {
871         // This case means the key release event is caused by
872         // a non-repeatable key such as Shift or a repeatable key that
873         // was pressed before sLastRepeatableHardwareKeyCode was
874         // pressed.
875         break;
876       }
877       sRepeatState = NOT_PRESSED;
878       MOZ_LOG(gKeyLog, LogLevel::Info,
879               ("FilterEvents(aXEvent={ type=KeyRelease, "
880                "xkey={ keycode=0x%08X, state=0x%08X, time=%lu } }, "
881                "aGdkEvent={ state=0x%08X }), "
882                "detected key release",
883                xEvent->xkey.keycode, xEvent->xkey.state, xEvent->xkey.time,
884                reinterpret_cast<GdkEventKey*>(aGdkEvent)->state));
885       break;
886     }
887     case FocusOut: {
888       // At moving focus, we should reset keyboard repeat state.
889       // Strictly, this causes incorrect behavior.  However, this
890       // correctness must be enough for web applications.
891       sRepeatState = NOT_PRESSED;
892       break;
893     }
894     default: {
895       KeymapWrapper* self = static_cast<KeymapWrapper*>(aData);
896       if (xEvent->type != self->mXKBBaseEventCode) {
897         break;
898       }
899       XkbEvent* xkbEvent = (XkbEvent*)xEvent;
900       if (xkbEvent->any.xkb_type != XkbControlsNotify ||
901           !(xkbEvent->ctrls.changed_ctrls & XkbPerKeyRepeatMask)) {
902         break;
903       }
904       if (!XGetKeyboardControl(xkbEvent->any.display, &self->mKeyboardState)) {
905         MOZ_LOG(gKeyLog, LogLevel::Info,
906                 ("%p FilterEvents failed due to failure "
907                  "of XGetKeyboardControl(), display=0x%p",
908                  self, xkbEvent->any.display));
909       }
910       break;
911     }
912   }
913 
914   return GDK_FILTER_CONTINUE;
915 }
916 
ResetBidiKeyboard()917 static void ResetBidiKeyboard() {
918   // Reset the bidi keyboard settings for the new GdkKeymap
919   nsCOMPtr<nsIBidiKeyboard> bidiKeyboard = nsContentUtils::GetBidiKeyboard();
920   if (bidiKeyboard) {
921     bidiKeyboard->Reset();
922   }
923   WidgetUtils::SendBidiKeyboardInfoToContent();
924 }
925 
926 /* static */
ResetKeyboard()927 void KeymapWrapper::ResetKeyboard() {
928   sInstance->mInitialized = false;
929   ResetBidiKeyboard();
930 }
931 
932 /* static */
OnKeysChanged(GdkKeymap * aGdkKeymap,KeymapWrapper * aKeymapWrapper)933 void KeymapWrapper::OnKeysChanged(GdkKeymap* aGdkKeymap,
934                                   KeymapWrapper* aKeymapWrapper) {
935   MOZ_LOG(gKeyLog, LogLevel::Info,
936           ("OnKeysChanged, aGdkKeymap=%p, aKeymapWrapper=%p", aGdkKeymap,
937            aKeymapWrapper));
938 
939   MOZ_ASSERT(sInstance == aKeymapWrapper,
940              "This instance must be the singleton instance");
941 
942   // We cannot reintialize here becasue we don't have GdkWindow which is using
943   // the GdkKeymap.  We'll reinitialize it when next GetInstance() is called.
944   ResetKeyboard();
945 }
946 
947 // static
OnDirectionChanged(GdkKeymap * aGdkKeymap,KeymapWrapper * aKeymapWrapper)948 void KeymapWrapper::OnDirectionChanged(GdkKeymap* aGdkKeymap,
949                                        KeymapWrapper* aKeymapWrapper) {
950   // XXX
951   // A lot of diretion-changed signal might be fired on switching bidi
952   // keyboard when using both ibus (with arabic layout) and fcitx (with IME).
953   // See https://github.com/fcitx/fcitx/issues/257
954   //
955   // Also, when using ibus, switching to IM might not cause this signal.
956   // See https://github.com/ibus/ibus/issues/1848
957 
958   MOZ_LOG(gKeyLog, LogLevel::Info,
959           ("OnDirectionChanged, aGdkKeymap=%p, aKeymapWrapper=%p", aGdkKeymap,
960            aKeymapWrapper));
961 
962   ResetBidiKeyboard();
963 }
964 
965 /* static */
GetCurrentModifierState()966 guint KeymapWrapper::GetCurrentModifierState() {
967   GdkModifierType modifiers;
968   GdkDisplay* display = gdk_display_get_default();
969   GdkScreen* screen = gdk_display_get_default_screen(display);
970   GdkWindow* window = gdk_screen_get_root_window(screen);
971   gdk_window_get_device_position(window, GdkGetPointer(), nullptr, nullptr,
972                                  &modifiers);
973   return static_cast<guint>(modifiers);
974 }
975 
976 /* static */
AreModifiersCurrentlyActive(Modifiers aModifiers)977 bool KeymapWrapper::AreModifiersCurrentlyActive(Modifiers aModifiers) {
978   guint modifierState = GetCurrentModifierState();
979   return AreModifiersActive(aModifiers, modifierState);
980 }
981 
982 /* static */
AreModifiersActive(Modifiers aModifiers,guint aModifierState)983 bool KeymapWrapper::AreModifiersActive(Modifiers aModifiers,
984                                        guint aModifierState) {
985   NS_ENSURE_TRUE(aModifiers, false);
986 
987   KeymapWrapper* keymapWrapper = GetInstance();
988   for (uint32_t i = 0; i < sizeof(Modifier) * 8 && aModifiers; i++) {
989     Modifier modifier = static_cast<Modifier>(1 << i);
990     if (!(aModifiers & modifier)) {
991       continue;
992     }
993     if (!(aModifierState & keymapWrapper->GetModifierMask(modifier))) {
994       return false;
995     }
996     aModifiers &= ~modifier;
997   }
998   return true;
999 }
1000 
1001 /* static */
ComputeCurrentKeyModifiers()1002 uint32_t KeymapWrapper::ComputeCurrentKeyModifiers() {
1003   return ComputeKeyModifiers(GetCurrentModifierState());
1004 }
1005 
1006 /* static */
ComputeKeyModifiers(guint aModifierState)1007 uint32_t KeymapWrapper::ComputeKeyModifiers(guint aModifierState) {
1008   KeymapWrapper* keymapWrapper = GetInstance();
1009 
1010   uint32_t keyModifiers = 0;
1011   // DOM Meta key should be TRUE only on Mac.  We need to discuss this
1012   // issue later.
1013   if (keymapWrapper->AreModifiersActive(SHIFT, aModifierState)) {
1014     keyModifiers |= MODIFIER_SHIFT;
1015   }
1016   if (keymapWrapper->AreModifiersActive(CTRL, aModifierState)) {
1017     keyModifiers |= MODIFIER_CONTROL;
1018   }
1019   if (keymapWrapper->AreModifiersActive(ALT, aModifierState)) {
1020     keyModifiers |= MODIFIER_ALT;
1021   }
1022   if (keymapWrapper->AreModifiersActive(META, aModifierState)) {
1023     keyModifiers |= MODIFIER_META;
1024   }
1025   if (keymapWrapper->AreModifiersActive(SUPER, aModifierState) ||
1026       keymapWrapper->AreModifiersActive(HYPER, aModifierState)) {
1027     keyModifiers |= MODIFIER_OS;
1028   }
1029   if (keymapWrapper->AreModifiersActive(LEVEL3, aModifierState) ||
1030       keymapWrapper->AreModifiersActive(LEVEL5, aModifierState)) {
1031     keyModifiers |= MODIFIER_ALTGRAPH;
1032   }
1033   if (keymapWrapper->AreModifiersActive(CAPS_LOCK, aModifierState)) {
1034     keyModifiers |= MODIFIER_CAPSLOCK;
1035   }
1036   if (keymapWrapper->AreModifiersActive(NUM_LOCK, aModifierState)) {
1037     keyModifiers |= MODIFIER_NUMLOCK;
1038   }
1039   if (keymapWrapper->AreModifiersActive(SCROLL_LOCK, aModifierState)) {
1040     keyModifiers |= MODIFIER_SCROLLLOCK;
1041   }
1042   return keyModifiers;
1043 }
1044 
1045 /* static */
ConvertWidgetModifierToGdkState(nsIWidget::Modifiers aNativeModifiers)1046 guint KeymapWrapper::ConvertWidgetModifierToGdkState(
1047     nsIWidget::Modifiers aNativeModifiers) {
1048   if (!aNativeModifiers) {
1049     return 0;
1050   }
1051   struct ModifierMapEntry {
1052     nsIWidget::Modifiers mWidgetModifier;
1053     Modifier mModifier;
1054   };
1055   // TODO: Currently, we don't treat L/R of each modifier on Linux.
1056   // TODO: No proper native modifier for Level5.
1057   static constexpr ModifierMapEntry sModifierMap[] = {
1058       {nsIWidget::CAPS_LOCK, Modifier::CAPS_LOCK},
1059       {nsIWidget::NUM_LOCK, Modifier::NUM_LOCK},
1060       {nsIWidget::SHIFT_L, Modifier::SHIFT},
1061       {nsIWidget::SHIFT_R, Modifier::SHIFT},
1062       {nsIWidget::CTRL_L, Modifier::CTRL},
1063       {nsIWidget::CTRL_R, Modifier::CTRL},
1064       {nsIWidget::ALT_L, Modifier::ALT},
1065       {nsIWidget::ALT_R, Modifier::ALT},
1066       {nsIWidget::ALTGRAPH, Modifier::LEVEL3},
1067       {nsIWidget::COMMAND_L, Modifier::SUPER},
1068       {nsIWidget::COMMAND_R, Modifier::SUPER}};
1069 
1070   guint state = 0;
1071   KeymapWrapper* instance = GetInstance();
1072   for (const ModifierMapEntry& entry : sModifierMap) {
1073     if (aNativeModifiers & entry.mWidgetModifier) {
1074       state |= instance->GetModifierMask(entry.mModifier);
1075     }
1076   }
1077   return state;
1078 }
1079 
1080 /* static */
InitInputEvent(WidgetInputEvent & aInputEvent,guint aModifierState)1081 void KeymapWrapper::InitInputEvent(WidgetInputEvent& aInputEvent,
1082                                    guint aModifierState) {
1083   KeymapWrapper* keymapWrapper = GetInstance();
1084 
1085   aInputEvent.mModifiers = ComputeKeyModifiers(aModifierState);
1086 
1087   // Don't log this method for non-important events because e.g., eMouseMove is
1088   // just noisy and there is no reason to log it.
1089   bool doLog = aInputEvent.mMessage != eMouseMove;
1090   if (doLog) {
1091     MOZ_LOG(gKeyLog, LogLevel::Debug,
1092             ("%p InitInputEvent, aModifierState=0x%08X, "
1093              "aInputEvent={ mMessage=%s, mModifiers=0x%04X (Shift: %s, "
1094              "Control: %s, Alt: %s, "
1095              "Meta: %s, OS: %s, AltGr: %s, "
1096              "CapsLock: %s, NumLock: %s, ScrollLock: %s })",
1097              keymapWrapper, aModifierState, ToChar(aInputEvent.mMessage),
1098              aInputEvent.mModifiers,
1099              GetBoolName(aInputEvent.mModifiers & MODIFIER_SHIFT),
1100              GetBoolName(aInputEvent.mModifiers & MODIFIER_CONTROL),
1101              GetBoolName(aInputEvent.mModifiers & MODIFIER_ALT),
1102              GetBoolName(aInputEvent.mModifiers & MODIFIER_META),
1103              GetBoolName(aInputEvent.mModifiers & MODIFIER_OS),
1104              GetBoolName(aInputEvent.mModifiers & MODIFIER_ALTGRAPH),
1105              GetBoolName(aInputEvent.mModifiers & MODIFIER_CAPSLOCK),
1106              GetBoolName(aInputEvent.mModifiers & MODIFIER_NUMLOCK),
1107              GetBoolName(aInputEvent.mModifiers & MODIFIER_SCROLLLOCK)));
1108   }
1109 
1110   switch (aInputEvent.mClass) {
1111     case eMouseEventClass:
1112     case eMouseScrollEventClass:
1113     case eWheelEventClass:
1114     case eDragEventClass:
1115     case eSimpleGestureEventClass:
1116       break;
1117     default:
1118       return;
1119   }
1120 
1121   WidgetMouseEventBase& mouseEvent = *aInputEvent.AsMouseEventBase();
1122   mouseEvent.mButtons = 0;
1123   if (aModifierState & GDK_BUTTON1_MASK) {
1124     mouseEvent.mButtons |= MouseButtonsFlag::ePrimaryFlag;
1125   }
1126   if (aModifierState & GDK_BUTTON3_MASK) {
1127     mouseEvent.mButtons |= MouseButtonsFlag::eSecondaryFlag;
1128   }
1129   if (aModifierState & GDK_BUTTON2_MASK) {
1130     mouseEvent.mButtons |= MouseButtonsFlag::eMiddleFlag;
1131   }
1132 
1133   if (doLog) {
1134     MOZ_LOG(
1135         gKeyLog, LogLevel::Debug,
1136         ("%p   InitInputEvent, aInputEvent has mButtons, "
1137          "aInputEvent.mButtons=0x%04X (Left: %s, Right: %s, Middle: %s, "
1138          "4th (BACK): %s, 5th (FORWARD): %s)",
1139          keymapWrapper, mouseEvent.mButtons,
1140          GetBoolName(mouseEvent.mButtons & MouseButtonsFlag::ePrimaryFlag),
1141          GetBoolName(mouseEvent.mButtons & MouseButtonsFlag::eSecondaryFlag),
1142          GetBoolName(mouseEvent.mButtons & MouseButtonsFlag::eMiddleFlag),
1143          GetBoolName(mouseEvent.mButtons & MouseButtonsFlag::e4thFlag),
1144          GetBoolName(mouseEvent.mButtons & MouseButtonsFlag::e5thFlag)));
1145   }
1146 }
1147 
1148 /* static */
ComputeDOMKeyCode(const GdkEventKey * aGdkKeyEvent)1149 uint32_t KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent) {
1150   // If the keyval indicates it's a modifier key, we should use unshifted
1151   // key's modifier keyval.
1152   guint keyval = aGdkKeyEvent->keyval;
1153   if (GetModifierForGDKKeyval(keyval)) {
1154     // But if the keyval without modifiers isn't a modifier key, we
1155     // shouldn't use it.  E.g., Japanese keyboard layout's
1156     // Shift + Eisu-Toggle key is CapsLock.  This is an actual rare case,
1157     // Windows uses different keycode for a physical key for different
1158     // shift key state.
1159     guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent);
1160     if (GetModifierForGDKKeyval(keyvalWithoutModifier)) {
1161       keyval = keyvalWithoutModifier;
1162     }
1163     // Note that the modifier keycode and activating or deactivating
1164     // modifier flag may be mismatched, but it's okay.  If a DOM key
1165     // event handler is testing a keydown event, it's more likely being
1166     // used to test which key is being pressed than to test which
1167     // modifier will become active.  So, if we computed DOM keycode
1168     // from modifier flag which were changing by the physical key, then
1169     // there would be no other way for the user to generate the original
1170     // keycode.
1171     uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval);
1172     NS_ASSERTION(DOMKeyCode, "All modifier keys must have a DOM keycode");
1173     return DOMKeyCode;
1174   }
1175 
1176   // If the key isn't printable, let's look at the key pairs.
1177   uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
1178   if (!charCode) {
1179     // Note that any key may be a function key because of some unusual keyboard
1180     // layouts.  I.e., even if the pressed key is a printable key of en-US
1181     // keyboard layout, we should expose the function key's keyCode value to
1182     // web apps because web apps should handle the keydown/keyup events as
1183     // inputted by usual keyboard layout.  For example, Hatchak keyboard
1184     // maps Tab key to "Digit3" key and Level3 Shift makes it "Backspace".
1185     // In this case, we should expose DOM_VK_BACK_SPACE (8).
1186     uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval);
1187     if (DOMKeyCode) {
1188       // XXX If DOMKeyCode is a function key's keyCode value, it might be
1189       //     better to consume necessary modifiers.  For example, if there is
1190       //     no Control Pad section on keyboard like notebook, Delete key is
1191       //     available only with Level3 Shift+"Backspace" key if using Hatchak.
1192       //     If web apps accept Delete key operation only when no modifiers are
1193       //     active, such users cannot use Delete key to do it.  However,
1194       //     Chromium doesn't consume such necessary modifiers.  So, our default
1195       //     behavior should keep not touching modifiers for compatibility, but
1196       //     it might be better to add a pref to consume necessary modifiers.
1197       return DOMKeyCode;
1198     }
1199     // If aGdkKeyEvent cannot be mapped to a DOM keyCode value, we should
1200     // refer keyCode value without modifiers because web apps should be
1201     // able to identify the key as far as possible.
1202     guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent);
1203     return GetDOMKeyCodeFromKeyPairs(keyvalWithoutModifier);
1204   }
1205 
1206   // printable numpad keys should be resolved here.
1207   switch (keyval) {
1208     case GDK_KP_Multiply:
1209       return NS_VK_MULTIPLY;
1210     case GDK_KP_Add:
1211       return NS_VK_ADD;
1212     case GDK_KP_Separator:
1213       return NS_VK_SEPARATOR;
1214     case GDK_KP_Subtract:
1215       return NS_VK_SUBTRACT;
1216     case GDK_KP_Decimal:
1217       return NS_VK_DECIMAL;
1218     case GDK_KP_Divide:
1219       return NS_VK_DIVIDE;
1220     case GDK_KP_0:
1221       return NS_VK_NUMPAD0;
1222     case GDK_KP_1:
1223       return NS_VK_NUMPAD1;
1224     case GDK_KP_2:
1225       return NS_VK_NUMPAD2;
1226     case GDK_KP_3:
1227       return NS_VK_NUMPAD3;
1228     case GDK_KP_4:
1229       return NS_VK_NUMPAD4;
1230     case GDK_KP_5:
1231       return NS_VK_NUMPAD5;
1232     case GDK_KP_6:
1233       return NS_VK_NUMPAD6;
1234     case GDK_KP_7:
1235       return NS_VK_NUMPAD7;
1236     case GDK_KP_8:
1237       return NS_VK_NUMPAD8;
1238     case GDK_KP_9:
1239       return NS_VK_NUMPAD9;
1240   }
1241 
1242   KeymapWrapper* keymapWrapper = GetInstance();
1243 
1244   // Ignore all modifier state except NumLock.
1245   guint baseState =
1246       (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK));
1247 
1248   // Basically, we should use unmodified character for deciding our keyCode.
1249   uint32_t unmodifiedChar = keymapWrapper->GetCharCodeFor(
1250       aGdkKeyEvent, baseState, aGdkKeyEvent->group);
1251   if (IsBasicLatinLetterOrNumeral(unmodifiedChar)) {
1252     // If the unmodified character is an ASCII alphabet or an ASCII
1253     // numeric, it's the best hint for deciding our keyCode.
1254     return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar);
1255   }
1256 
1257   // If the unmodified character is not an ASCII character, that means we
1258   // couldn't find the hint. We should reset it.
1259   if (!IsPrintableASCIICharacter(unmodifiedChar)) {
1260     unmodifiedChar = 0;
1261   }
1262 
1263   // Retry with shifted keycode.
1264   guint shiftState = (baseState | keymapWrapper->GetModifierMask(SHIFT));
1265   uint32_t shiftedChar = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState,
1266                                                        aGdkKeyEvent->group);
1267   if (IsBasicLatinLetterOrNumeral(shiftedChar)) {
1268     // A shifted character can be an ASCII alphabet on Hebrew keyboard
1269     // layout. And also shifted character can be an ASCII numeric on
1270     // AZERTY keyboad layout.  Then, it's a good hint for deciding our
1271     // keyCode.
1272     return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar);
1273   }
1274 
1275   // If the shifted unmodified character isn't an ASCII character, we should
1276   // discard it too.
1277   if (!IsPrintableASCIICharacter(shiftedChar)) {
1278     shiftedChar = 0;
1279   }
1280 
1281   // If current keyboard layout isn't ASCII alphabet inputtable layout,
1282   // look for ASCII alphabet inputtable keyboard layout.  If the key
1283   // inputs an ASCII alphabet or an ASCII numeric, we should use it
1284   // for deciding our keyCode.
1285   uint32_t unmodCharLatin = 0;
1286   uint32_t shiftedCharLatin = 0;
1287   if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) {
1288     gint minGroup = keymapWrapper->GetFirstLatinGroup();
1289     if (minGroup >= 0) {
1290       unmodCharLatin =
1291           keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, minGroup);
1292       if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) {
1293         // If the unmodified character is an ASCII alphabet or
1294         // an ASCII numeric, we should use it for the keyCode.
1295         return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin);
1296       }
1297       // If the unmodified character in the alternative ASCII capable
1298       // keyboard layout isn't an ASCII character, that means we couldn't
1299       // find the hint. We should reset it.
1300       if (!IsPrintableASCIICharacter(unmodCharLatin)) {
1301         unmodCharLatin = 0;
1302       }
1303       shiftedCharLatin =
1304           keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, minGroup);
1305       if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) {
1306         // If the shifted character is an ASCII alphabet or an ASCII
1307         // numeric, we should use it for the keyCode.
1308         return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin);
1309       }
1310       // If the shifted unmodified character in the alternative ASCII
1311       // capable keyboard layout isn't an ASCII character, we should
1312       // discard it too.
1313       if (!IsPrintableASCIICharacter(shiftedCharLatin)) {
1314         shiftedCharLatin = 0;
1315       }
1316     }
1317   }
1318 
1319   // If the key itself or with Shift state on active keyboard layout produces
1320   // an ASCII punctuation character, we should decide keyCode value with it.
1321   if (unmodifiedChar || shiftedChar) {
1322     return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar ? unmodifiedChar
1323                                                               : shiftedChar);
1324   }
1325 
1326   // If the key itself or with Shift state on alternative ASCII capable
1327   // keyboard layout produces an ASCII punctuation character, we should
1328   // decide keyCode value with it.  Note that We've returned 0 for long
1329   // time if keyCode isn't for an alphabet keys or a numeric key even in
1330   // alternative ASCII capable keyboard layout because we decided that we
1331   // should avoid setting same keyCode value to 2 or more keys since active
1332   // keyboard layout may have a key to input the punctuation with different
1333   // key.  However, setting keyCode to 0 makes some web applications which
1334   // are aware of neither KeyboardEvent.key nor KeyboardEvent.code not work
1335   // with Firefox when user selects non-ASCII capable keyboard layout such
1336   // as Russian and Thai.  So, if alternative ASCII capable keyboard layout
1337   // has keyCode value for the key, we should use it.  In other words, this
1338   // behavior means that non-ASCII capable keyboard layout overrides some
1339   // keys' keyCode value only if the key produces ASCII character by itself
1340   // or with Shift key.
1341   if (unmodCharLatin || shiftedCharLatin) {
1342     return WidgetUtils::ComputeKeyCodeFromChar(
1343         unmodCharLatin ? unmodCharLatin : shiftedCharLatin);
1344   }
1345 
1346   // Otherwise, let's decide keyCode value from the hardware_keycode
1347   // value on major keyboard layout.
1348   CodeNameIndex code = ComputeDOMCodeNameIndex(aGdkKeyEvent);
1349   return WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(code);
1350 }
1351 
ComputeDOMKeyNameIndex(const GdkEventKey * aGdkKeyEvent)1352 KeyNameIndex KeymapWrapper::ComputeDOMKeyNameIndex(
1353     const GdkEventKey* aGdkKeyEvent) {
1354   switch (aGdkKeyEvent->keyval) {
1355 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
1356   case aNativeKey:                                                     \
1357     return aKeyNameIndex;
1358 
1359 #include "NativeKeyToDOMKeyName.h"
1360 
1361 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
1362 
1363     default:
1364       break;
1365   }
1366 
1367   return KEY_NAME_INDEX_Unidentified;
1368 }
1369 
1370 /* static */
ComputeDOMCodeNameIndex(const GdkEventKey * aGdkKeyEvent)1371 CodeNameIndex KeymapWrapper::ComputeDOMCodeNameIndex(
1372     const GdkEventKey* aGdkKeyEvent) {
1373   switch (aGdkKeyEvent->hardware_keycode) {
1374 #define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, aCodeNameIndex) \
1375   case aNativeKey:                                                       \
1376     return aCodeNameIndex;
1377 
1378 #include "NativeKeyToDOMCodeName.h"
1379 
1380 #undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX
1381 
1382     default:
1383       break;
1384   }
1385 
1386   return CODE_NAME_INDEX_UNKNOWN;
1387 }
1388 
1389 /* static */
DispatchKeyDownOrKeyUpEvent(nsWindow * aWindow,GdkEventKey * aGdkKeyEvent,bool aIsProcessedByIME,bool * aIsCancelled)1390 bool KeymapWrapper::DispatchKeyDownOrKeyUpEvent(nsWindow* aWindow,
1391                                                 GdkEventKey* aGdkKeyEvent,
1392                                                 bool aIsProcessedByIME,
1393                                                 bool* aIsCancelled) {
1394   MOZ_ASSERT(aIsCancelled, "aIsCancelled must not be nullptr");
1395 
1396   *aIsCancelled = false;
1397 
1398   if (aGdkKeyEvent->type == GDK_KEY_PRESS && aGdkKeyEvent->keyval == GDK_Tab &&
1399       AreModifiersActive(CTRL | ALT, aGdkKeyEvent->state)) {
1400     MOZ_LOG(gKeyLog, LogLevel::Info,
1401             ("  DispatchKeyDownOrKeyUpEvent(), didn't dispatch keyboard events "
1402              "because it's Ctrl + Alt + Tab"));
1403     return false;
1404   }
1405 
1406   EventMessage message =
1407       aGdkKeyEvent->type == GDK_KEY_PRESS ? eKeyDown : eKeyUp;
1408   WidgetKeyboardEvent keyEvent(true, message, aWindow);
1409   KeymapWrapper::InitKeyEvent(keyEvent, aGdkKeyEvent, aIsProcessedByIME);
1410   return DispatchKeyDownOrKeyUpEvent(aWindow, keyEvent, aIsCancelled);
1411 }
1412 
1413 /* static */
DispatchKeyDownOrKeyUpEvent(nsWindow * aWindow,WidgetKeyboardEvent & aKeyboardEvent,bool * aIsCancelled)1414 bool KeymapWrapper::DispatchKeyDownOrKeyUpEvent(
1415     nsWindow* aWindow, WidgetKeyboardEvent& aKeyboardEvent,
1416     bool* aIsCancelled) {
1417   MOZ_ASSERT(aIsCancelled, "aIsCancelled must not be nullptr");
1418 
1419   *aIsCancelled = false;
1420 
1421   RefPtr<TextEventDispatcher> dispatcher = aWindow->GetTextEventDispatcher();
1422   nsresult rv = dispatcher->BeginNativeInputTransaction();
1423   if (NS_WARN_IF(NS_FAILED(rv))) {
1424     MOZ_LOG(gKeyLog, LogLevel::Error,
1425             ("  DispatchKeyDownOrKeyUpEvent(), stopped dispatching %s event "
1426              "because of failed to initialize TextEventDispatcher",
1427              ToChar(aKeyboardEvent.mMessage)));
1428     return FALSE;
1429   }
1430 
1431   nsEventStatus status = nsEventStatus_eIgnore;
1432   bool dispatched = dispatcher->DispatchKeyboardEvent(
1433       aKeyboardEvent.mMessage, aKeyboardEvent, status, nullptr);
1434   *aIsCancelled = (status == nsEventStatus_eConsumeNoDefault);
1435   return dispatched;
1436 }
1437 
1438 /* static */
MaybeDispatchContextMenuEvent(nsWindow * aWindow,const GdkEventKey * aEvent)1439 bool KeymapWrapper::MaybeDispatchContextMenuEvent(nsWindow* aWindow,
1440                                                   const GdkEventKey* aEvent) {
1441   KeyNameIndex keyNameIndex = ComputeDOMKeyNameIndex(aEvent);
1442 
1443   // Shift+F10 and ContextMenu should cause eContextMenu event.
1444   if (keyNameIndex != KEY_NAME_INDEX_F10 &&
1445       keyNameIndex != KEY_NAME_INDEX_ContextMenu) {
1446     return false;
1447   }
1448 
1449   WidgetMouseEvent contextMenuEvent(true, eContextMenu, aWindow,
1450                                     WidgetMouseEvent::eReal,
1451                                     WidgetMouseEvent::eContextMenuKey);
1452 
1453   contextMenuEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
1454   contextMenuEvent.AssignEventTime(aWindow->GetWidgetEventTime(aEvent->time));
1455   contextMenuEvent.mClickCount = 1;
1456   KeymapWrapper::InitInputEvent(contextMenuEvent, aEvent->state);
1457 
1458   if (contextMenuEvent.IsControl() || contextMenuEvent.IsMeta() ||
1459       contextMenuEvent.IsAlt()) {
1460     return false;
1461   }
1462 
1463   // If the key is ContextMenu, then an eContextMenu mouse event is
1464   // dispatched regardless of the state of the Shift modifier.  When it is
1465   // pressed without the Shift modifier, a web page can prevent the default
1466   // context menu action.  When pressed with the Shift modifier, the web page
1467   // cannot prevent the default context menu action.
1468   // (PresShell::HandleEventInternal() sets mOnlyChromeDispatch to true.)
1469 
1470   // If the key is F10, it needs Shift state because Shift+F10 is well-known
1471   // shortcut key on Linux.  However, eContextMenu with Shift state is
1472   // special.  It won't fire "contextmenu" event in the web content for
1473   // blocking web page to prevent its default.  Therefore, this combination
1474   // should work same as ContextMenu key.
1475   // XXX Should we allow to block web page to prevent its default with
1476   //     Ctrl+Shift+F10 or Alt+Shift+F10 instead?
1477   if (keyNameIndex == KEY_NAME_INDEX_F10) {
1478     if (!contextMenuEvent.IsShift()) {
1479       return false;
1480     }
1481     contextMenuEvent.mModifiers &= ~MODIFIER_SHIFT;
1482   }
1483 
1484   aWindow->DispatchInputEvent(&contextMenuEvent);
1485   return true;
1486 }
1487 
1488 /* static*/
HandleKeyPressEvent(nsWindow * aWindow,GdkEventKey * aGdkKeyEvent)1489 void KeymapWrapper::HandleKeyPressEvent(nsWindow* aWindow,
1490                                         GdkEventKey* aGdkKeyEvent) {
1491   MOZ_LOG(gKeyLog, LogLevel::Info,
1492           ("HandleKeyPressEvent(aWindow=%p, aGdkKeyEvent={ type=%s, "
1493            "keyval=%s(0x%X), state=0x%08X, hardware_keycode=0x%08X, "
1494            "time=%u, is_modifier=%s })",
1495            aWindow,
1496            ((aGdkKeyEvent->type == GDK_KEY_PRESS) ? "GDK_KEY_PRESS"
1497                                                   : "GDK_KEY_RELEASE"),
1498            gdk_keyval_name(aGdkKeyEvent->keyval), aGdkKeyEvent->keyval,
1499            aGdkKeyEvent->state, aGdkKeyEvent->hardware_keycode,
1500            aGdkKeyEvent->time, GetBoolName(aGdkKeyEvent->is_modifier)));
1501 
1502   // if we are in the middle of composing text, XIM gets to see it
1503   // before mozilla does.
1504   // FYI: Don't dispatch keydown event before notifying IME of the event
1505   //      because IME may send a key event synchronously and consume the
1506   //      original event.
1507   bool IMEWasEnabled = false;
1508   KeyHandlingState handlingState = KeyHandlingState::eNotHandled;
1509   RefPtr<IMContextWrapper> imContext = aWindow->GetIMContext();
1510   if (imContext) {
1511     IMEWasEnabled = imContext->IsEnabled();
1512     handlingState = imContext->OnKeyEvent(aWindow, aGdkKeyEvent);
1513     if (handlingState == KeyHandlingState::eHandled) {
1514       MOZ_LOG(gKeyLog, LogLevel::Info,
1515               ("  HandleKeyPressEvent(), the event was handled by "
1516                "IMContextWrapper"));
1517       return;
1518     }
1519   }
1520 
1521   // work around for annoying things.
1522   if (aGdkKeyEvent->keyval == GDK_Tab &&
1523       AreModifiersActive(CTRL | ALT, aGdkKeyEvent->state)) {
1524     MOZ_LOG(gKeyLog, LogLevel::Info,
1525             ("  HandleKeyPressEvent(), didn't dispatch keyboard events "
1526              "because it's Ctrl + Alt + Tab"));
1527     return;
1528   }
1529 
1530   // Dispatch keydown event always.  At auto repeating, we should send
1531   // KEYDOWN -> KEYPRESS -> KEYDOWN -> KEYPRESS ... -> KEYUP
1532   // However, old distributions (e.g., Ubuntu 9.10) sent native key
1533   // release event, so, on such platform, the DOM events will be:
1534   // KEYDOWN -> KEYPRESS -> KEYUP -> KEYDOWN -> KEYPRESS -> KEYUP...
1535 
1536   bool isKeyDownCancelled = false;
1537   if (handlingState == KeyHandlingState::eNotHandled) {
1538     if (DispatchKeyDownOrKeyUpEvent(aWindow, aGdkKeyEvent, false,
1539                                     &isKeyDownCancelled) &&
1540         (MOZ_UNLIKELY(aWindow->IsDestroyed()) || isKeyDownCancelled)) {
1541       MOZ_LOG(gKeyLog, LogLevel::Info,
1542               ("  HandleKeyPressEvent(), dispatched eKeyDown event and "
1543                "stopped handling the event because %s",
1544                aWindow->IsDestroyed() ? "the window has been destroyed"
1545                                       : "the event was consumed"));
1546       return;
1547     }
1548     MOZ_LOG(gKeyLog, LogLevel::Info,
1549             ("  HandleKeyPressEvent(), dispatched eKeyDown event and "
1550              "it wasn't consumed"));
1551     handlingState = KeyHandlingState::eNotHandledButEventDispatched;
1552   }
1553 
1554   // If a keydown event handler causes to enable IME, i.e., it moves
1555   // focus from IME unusable content to IME usable editor, we should
1556   // send the native key event to IME for the first input on the editor.
1557   imContext = aWindow->GetIMContext();
1558   if (!IMEWasEnabled && imContext && imContext->IsEnabled()) {
1559     // Notice our keydown event was already dispatched.  This prevents
1560     // unnecessary DOM keydown event in the editor.
1561     handlingState = imContext->OnKeyEvent(aWindow, aGdkKeyEvent, true);
1562     if (handlingState == KeyHandlingState::eHandled) {
1563       MOZ_LOG(gKeyLog, LogLevel::Info,
1564               ("  HandleKeyPressEvent(), the event was handled by "
1565                "IMContextWrapper which was enabled by the preceding eKeyDown "
1566                "event"));
1567       return;
1568     }
1569   }
1570 
1571   // Look for specialized app-command keys
1572   switch (aGdkKeyEvent->keyval) {
1573     case GDK_Back:
1574       aWindow->DispatchCommandEvent(nsGkAtoms::Back);
1575       MOZ_LOG(gKeyLog, LogLevel::Info,
1576               ("  HandleKeyPressEvent(), dispatched \"Back\" command event"));
1577       return;
1578     case GDK_Forward:
1579       aWindow->DispatchCommandEvent(nsGkAtoms::Forward);
1580       MOZ_LOG(gKeyLog, LogLevel::Info,
1581               ("  HandleKeyPressEvent(), dispatched \"Forward\" command "
1582                "event"));
1583       return;
1584     case GDK_Reload:
1585     case GDK_Refresh:
1586       aWindow->DispatchCommandEvent(nsGkAtoms::Reload);
1587       return;
1588     case GDK_Stop:
1589       aWindow->DispatchCommandEvent(nsGkAtoms::Stop);
1590       MOZ_LOG(gKeyLog, LogLevel::Info,
1591               ("  HandleKeyPressEvent(), dispatched \"Stop\" command event"));
1592       return;
1593     case GDK_Search:
1594       aWindow->DispatchCommandEvent(nsGkAtoms::Search);
1595       MOZ_LOG(gKeyLog, LogLevel::Info,
1596               ("  HandleKeyPressEvent(), dispatched \"Search\" command event"));
1597       return;
1598     case GDK_Favorites:
1599       aWindow->DispatchCommandEvent(nsGkAtoms::Bookmarks);
1600       MOZ_LOG(gKeyLog, LogLevel::Info,
1601               ("  HandleKeyPressEvent(), dispatched \"Bookmarks\" command "
1602                "event"));
1603       return;
1604     case GDK_HomePage:
1605       aWindow->DispatchCommandEvent(nsGkAtoms::Home);
1606       return;
1607     case GDK_Copy:
1608     case GDK_F16:  // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
1609       aWindow->DispatchContentCommandEvent(eContentCommandCopy);
1610       MOZ_LOG(gKeyLog, LogLevel::Info,
1611               ("  HandleKeyPressEvent(), dispatched \"Copy\" content command "
1612                "event"));
1613       return;
1614     case GDK_Cut:
1615     case GDK_F20:
1616       aWindow->DispatchContentCommandEvent(eContentCommandCut);
1617       MOZ_LOG(gKeyLog, LogLevel::Info,
1618               ("  HandleKeyPressEvent(), dispatched \"Cut\" content command "
1619                "event"));
1620       return;
1621     case GDK_Paste:
1622     case GDK_F18:
1623       aWindow->DispatchContentCommandEvent(eContentCommandPaste);
1624       MOZ_LOG(gKeyLog, LogLevel::Info,
1625               ("  HandleKeyPressEvent(), dispatched \"Paste\" content command "
1626                "event"));
1627       return;
1628     case GDK_Redo:
1629       aWindow->DispatchContentCommandEvent(eContentCommandRedo);
1630       return;
1631     case GDK_Undo:
1632     case GDK_F14:
1633       aWindow->DispatchContentCommandEvent(eContentCommandUndo);
1634       MOZ_LOG(gKeyLog, LogLevel::Info,
1635               ("  HandleKeyPressEvent(), dispatched \"Undo\" content command "
1636                "event"));
1637       return;
1638     default:
1639       break;
1640   }
1641 
1642   // before we dispatch a key, check if it's the context menu key.
1643   // If so, send a context menu key event instead.
1644   if (MaybeDispatchContextMenuEvent(aWindow, aGdkKeyEvent)) {
1645     MOZ_LOG(gKeyLog, LogLevel::Info,
1646             ("  HandleKeyPressEvent(), stopped dispatching eKeyPress event "
1647              "because eContextMenu event was dispatched"));
1648     return;
1649   }
1650 
1651   RefPtr<TextEventDispatcher> textEventDispatcher =
1652       aWindow->GetTextEventDispatcher();
1653   nsresult rv = textEventDispatcher->BeginNativeInputTransaction();
1654   if (NS_WARN_IF(NS_FAILED(rv))) {
1655     MOZ_LOG(gKeyLog, LogLevel::Error,
1656             ("  HandleKeyPressEvent(), stopped dispatching eKeyPress event "
1657              "because of failed to initialize TextEventDispatcher"));
1658     return;
1659   }
1660 
1661   // If the character code is in the BMP, send the key press event.
1662   // Otherwise, send a compositionchange event with the equivalent UTF-16
1663   // string.
1664   // TODO: Investigate other browser's behavior in this case because
1665   //       this hack is odd for UI Events.
1666   WidgetKeyboardEvent keypressEvent(true, eKeyPress, aWindow);
1667   KeymapWrapper::InitKeyEvent(keypressEvent, aGdkKeyEvent, false);
1668   nsEventStatus status = nsEventStatus_eIgnore;
1669   if (keypressEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ||
1670       keypressEvent.mKeyValue.Length() == 1) {
1671     if (textEventDispatcher->MaybeDispatchKeypressEvents(keypressEvent, status,
1672                                                          aGdkKeyEvent)) {
1673       MOZ_LOG(gKeyLog, LogLevel::Info,
1674               ("  HandleKeyPressEvent(), dispatched eKeyPress event "
1675                "(status=%s)",
1676                GetStatusName(status)));
1677     } else {
1678       MOZ_LOG(gKeyLog, LogLevel::Info,
1679               ("  HandleKeyPressEvent(), didn't dispatch eKeyPress event "
1680                "(status=%s)",
1681                GetStatusName(status)));
1682     }
1683   } else {
1684     WidgetEventTime eventTime = aWindow->GetWidgetEventTime(aGdkKeyEvent->time);
1685     textEventDispatcher->CommitComposition(status, &keypressEvent.mKeyValue,
1686                                            &eventTime);
1687     MOZ_LOG(gKeyLog, LogLevel::Info,
1688             ("  HandleKeyPressEvent(), dispatched a set of composition "
1689              "events"));
1690   }
1691 }
1692 
1693 /* static */
HandleKeyReleaseEvent(nsWindow * aWindow,GdkEventKey * aGdkKeyEvent)1694 bool KeymapWrapper::HandleKeyReleaseEvent(nsWindow* aWindow,
1695                                           GdkEventKey* aGdkKeyEvent) {
1696   MOZ_LOG(gKeyLog, LogLevel::Info,
1697           ("HandleKeyReleaseEvent(aWindow=%p, aGdkKeyEvent={ type=%s, "
1698            "keyval=%s(0x%X), state=0x%08X, hardware_keycode=0x%08X, "
1699            "time=%u, is_modifier=%s })",
1700            aWindow,
1701            ((aGdkKeyEvent->type == GDK_KEY_PRESS) ? "GDK_KEY_PRESS"
1702                                                   : "GDK_KEY_RELEASE"),
1703            gdk_keyval_name(aGdkKeyEvent->keyval), aGdkKeyEvent->keyval,
1704            aGdkKeyEvent->state, aGdkKeyEvent->hardware_keycode,
1705            aGdkKeyEvent->time, GetBoolName(aGdkKeyEvent->is_modifier)));
1706 
1707   RefPtr<IMContextWrapper> imContext = aWindow->GetIMContext();
1708   if (imContext) {
1709     KeyHandlingState handlingState =
1710         imContext->OnKeyEvent(aWindow, aGdkKeyEvent);
1711     if (handlingState != KeyHandlingState::eNotHandled) {
1712       MOZ_LOG(gKeyLog, LogLevel::Info,
1713               ("  HandleKeyReleaseEvent(), the event was handled by "
1714                "IMContextWrapper"));
1715       return true;
1716     }
1717   }
1718 
1719   bool isCancelled = false;
1720   if (NS_WARN_IF(!DispatchKeyDownOrKeyUpEvent(aWindow, aGdkKeyEvent, false,
1721                                               &isCancelled))) {
1722     MOZ_LOG(gKeyLog, LogLevel::Error,
1723             ("  HandleKeyReleaseEvent(), didn't dispatch eKeyUp event"));
1724     return false;
1725   }
1726 
1727   MOZ_LOG(gKeyLog, LogLevel::Info,
1728           ("  HandleKeyReleaseEvent(), dispatched eKeyUp event "
1729            "(isCancelled=%s)",
1730            GetBoolName(isCancelled)));
1731   return true;
1732 }
1733 
1734 /* static */
InitKeyEvent(WidgetKeyboardEvent & aKeyEvent,GdkEventKey * aGdkKeyEvent,bool aIsProcessedByIME)1735 void KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
1736                                  GdkEventKey* aGdkKeyEvent,
1737                                  bool aIsProcessedByIME) {
1738   MOZ_ASSERT(
1739       !aIsProcessedByIME || aKeyEvent.mMessage != eKeyPress,
1740       "If the key event is handled by IME, keypress event shouldn't be fired");
1741 
1742   KeymapWrapper* keymapWrapper = GetInstance();
1743 
1744   aKeyEvent.mCodeNameIndex = ComputeDOMCodeNameIndex(aGdkKeyEvent);
1745   MOZ_ASSERT(aKeyEvent.mCodeNameIndex != CODE_NAME_INDEX_USE_STRING);
1746   aKeyEvent.mKeyNameIndex =
1747       aIsProcessedByIME ? KEY_NAME_INDEX_Process
1748                         : keymapWrapper->ComputeDOMKeyNameIndex(aGdkKeyEvent);
1749   if (aKeyEvent.mKeyNameIndex == KEY_NAME_INDEX_Unidentified) {
1750     uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
1751     if (!charCode) {
1752       charCode = keymapWrapper->GetUnmodifiedCharCodeFor(aGdkKeyEvent);
1753     }
1754     if (charCode) {
1755       aKeyEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
1756       MOZ_ASSERT(aKeyEvent.mKeyValue.IsEmpty(),
1757                  "Uninitialized mKeyValue must be empty");
1758       AppendUCS4ToUTF16(charCode, aKeyEvent.mKeyValue);
1759     }
1760   }
1761 
1762   if (aIsProcessedByIME) {
1763     aKeyEvent.mKeyCode = NS_VK_PROCESSKEY;
1764   } else if (aKeyEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ||
1765              aKeyEvent.mMessage != eKeyPress) {
1766     aKeyEvent.mKeyCode = ComputeDOMKeyCode(aGdkKeyEvent);
1767   } else {
1768     aKeyEvent.mKeyCode = 0;
1769   }
1770 
1771   // NOTE: The state of given key event indicates adjacent state of
1772   // modifier keys.  E.g., even if the event is Shift key press event,
1773   // the bit for Shift is still false.  By the same token, even if the
1774   // event is Shift key release event, the bit for Shift is still true.
1775   // Unfortunately, gdk_keyboard_get_modifiers() returns current modifier
1776   // state.  It means if there're some pending modifier key press or
1777   // key release events, the result isn't what we want.
1778   guint modifierState = aGdkKeyEvent->state;
1779   GdkDisplay* gdkDisplay = gdk_display_get_default();
1780   if (aGdkKeyEvent->is_modifier && GdkIsX11Display(gdkDisplay)) {
1781     Display* display = gdk_x11_display_get_xdisplay(gdkDisplay);
1782     if (XEventsQueued(display, QueuedAfterReading)) {
1783       XEvent nextEvent;
1784       XPeekEvent(display, &nextEvent);
1785       if (nextEvent.type == keymapWrapper->mXKBBaseEventCode) {
1786         XkbEvent* XKBEvent = (XkbEvent*)&nextEvent;
1787         if (XKBEvent->any.xkb_type == XkbStateNotify) {
1788           XkbStateNotifyEvent* stateNotifyEvent =
1789               (XkbStateNotifyEvent*)XKBEvent;
1790           modifierState &= ~0xFF;
1791           modifierState |= stateNotifyEvent->lookup_mods;
1792         }
1793       }
1794     }
1795   }
1796   InitInputEvent(aKeyEvent, modifierState);
1797 
1798   switch (aGdkKeyEvent->keyval) {
1799     case GDK_Shift_L:
1800     case GDK_Control_L:
1801     case GDK_Alt_L:
1802     case GDK_Super_L:
1803     case GDK_Hyper_L:
1804     case GDK_Meta_L:
1805       aKeyEvent.mLocation = eKeyLocationLeft;
1806       break;
1807 
1808     case GDK_Shift_R:
1809     case GDK_Control_R:
1810     case GDK_Alt_R:
1811     case GDK_Super_R:
1812     case GDK_Hyper_R:
1813     case GDK_Meta_R:
1814       aKeyEvent.mLocation = eKeyLocationRight;
1815       break;
1816 
1817     case GDK_KP_0:
1818     case GDK_KP_1:
1819     case GDK_KP_2:
1820     case GDK_KP_3:
1821     case GDK_KP_4:
1822     case GDK_KP_5:
1823     case GDK_KP_6:
1824     case GDK_KP_7:
1825     case GDK_KP_8:
1826     case GDK_KP_9:
1827     case GDK_KP_Space:
1828     case GDK_KP_Tab:
1829     case GDK_KP_Enter:
1830     case GDK_KP_F1:
1831     case GDK_KP_F2:
1832     case GDK_KP_F3:
1833     case GDK_KP_F4:
1834     case GDK_KP_Home:
1835     case GDK_KP_Left:
1836     case GDK_KP_Up:
1837     case GDK_KP_Right:
1838     case GDK_KP_Down:
1839     case GDK_KP_Prior:  // same as GDK_KP_Page_Up
1840     case GDK_KP_Next:   // same as GDK_KP_Page_Down
1841     case GDK_KP_End:
1842     case GDK_KP_Begin:
1843     case GDK_KP_Insert:
1844     case GDK_KP_Delete:
1845     case GDK_KP_Equal:
1846     case GDK_KP_Multiply:
1847     case GDK_KP_Add:
1848     case GDK_KP_Separator:
1849     case GDK_KP_Subtract:
1850     case GDK_KP_Decimal:
1851     case GDK_KP_Divide:
1852       aKeyEvent.mLocation = eKeyLocationNumpad;
1853       break;
1854 
1855     default:
1856       aKeyEvent.mLocation = eKeyLocationStandard;
1857       break;
1858   }
1859 
1860   // The transformations above and in gdk for the keyval are not invertible
1861   // so link to the GdkEvent (which will vanish soon after return from the
1862   // event callback) to give plugins access to hardware_keycode and state.
1863   // (An XEvent would be nice but the GdkEvent is good enough.)
1864   aKeyEvent.mTime = aGdkKeyEvent->time;
1865   aKeyEvent.mNativeKeyEvent = static_cast<void*>(aGdkKeyEvent);
1866   aKeyEvent.mIsRepeat =
1867       sRepeatState == REPEATING &&
1868       aGdkKeyEvent->hardware_keycode == sLastRepeatableHardwareKeyCode;
1869 
1870   MOZ_LOG(
1871       gKeyLog, LogLevel::Info,
1872       ("%p InitKeyEvent, modifierState=0x%08X "
1873        "aKeyEvent={ mMessage=%s, isShift=%s, isControl=%s, "
1874        "isAlt=%s, isMeta=%s , mKeyCode=0x%02X, mCharCode=%s, "
1875        "mKeyNameIndex=%s, mKeyValue=%s, mCodeNameIndex=%s, mCodeValue=%s, "
1876        "mLocation=%s, mIsRepeat=%s }",
1877        keymapWrapper, modifierState, ToChar(aKeyEvent.mMessage),
1878        GetBoolName(aKeyEvent.IsShift()), GetBoolName(aKeyEvent.IsControl()),
1879        GetBoolName(aKeyEvent.IsAlt()), GetBoolName(aKeyEvent.IsMeta()),
1880        aKeyEvent.mKeyCode,
1881        GetCharacterCodeName(static_cast<char16_t>(aKeyEvent.mCharCode)).get(),
1882        ToString(aKeyEvent.mKeyNameIndex).get(),
1883        GetCharacterCodeNames(aKeyEvent.mKeyValue).get(),
1884        ToString(aKeyEvent.mCodeNameIndex).get(),
1885        GetCharacterCodeNames(aKeyEvent.mCodeValue).get(),
1886        GetKeyLocationName(aKeyEvent.mLocation).get(),
1887        GetBoolName(aKeyEvent.mIsRepeat)));
1888 }
1889 
1890 /* static */
GetCharCodeFor(const GdkEventKey * aGdkKeyEvent)1891 uint32_t KeymapWrapper::GetCharCodeFor(const GdkEventKey* aGdkKeyEvent) {
1892   // Anything above 0xf000 is considered a non-printable
1893   // Exception: directly encoded UCS characters
1894   if (aGdkKeyEvent->keyval > 0xf000 &&
1895       (aGdkKeyEvent->keyval & 0xff000000) != 0x01000000) {
1896     // Keypad keys are an exception: they return a value different
1897     // from their non-keypad equivalents, but mozilla doesn't distinguish.
1898     switch (aGdkKeyEvent->keyval) {
1899       case GDK_KP_Space:
1900         return ' ';
1901       case GDK_KP_Equal:
1902         return '=';
1903       case GDK_KP_Multiply:
1904         return '*';
1905       case GDK_KP_Add:
1906         return '+';
1907       case GDK_KP_Separator:
1908         return ',';
1909       case GDK_KP_Subtract:
1910         return '-';
1911       case GDK_KP_Decimal:
1912         return '.';
1913       case GDK_KP_Divide:
1914         return '/';
1915       case GDK_KP_0:
1916         return '0';
1917       case GDK_KP_1:
1918         return '1';
1919       case GDK_KP_2:
1920         return '2';
1921       case GDK_KP_3:
1922         return '3';
1923       case GDK_KP_4:
1924         return '4';
1925       case GDK_KP_5:
1926         return '5';
1927       case GDK_KP_6:
1928         return '6';
1929       case GDK_KP_7:
1930         return '7';
1931       case GDK_KP_8:
1932         return '8';
1933       case GDK_KP_9:
1934         return '9';
1935       default:
1936         return 0;  // non-printables
1937     }
1938   }
1939 
1940   static const long MAX_UNICODE = 0x10FFFF;
1941 
1942   // we're supposedly printable, let's try to convert
1943   long ucs = keysym2ucs(aGdkKeyEvent->keyval);
1944   if ((ucs != -1) && (ucs < MAX_UNICODE)) {
1945     return ucs;
1946   }
1947 
1948   // I guess we couldn't convert
1949   return 0;
1950 }
1951 
GetCharCodeFor(const GdkEventKey * aGdkKeyEvent,guint aModifierState,gint aGroup)1952 uint32_t KeymapWrapper::GetCharCodeFor(const GdkEventKey* aGdkKeyEvent,
1953                                        guint aModifierState, gint aGroup) {
1954   guint keyval;
1955   if (!gdk_keymap_translate_keyboard_state(
1956           mGdkKeymap, aGdkKeyEvent->hardware_keycode,
1957           GdkModifierType(aModifierState), aGroup, &keyval, nullptr, nullptr,
1958           nullptr)) {
1959     return 0;
1960   }
1961   GdkEventKey tmpEvent = *aGdkKeyEvent;
1962   tmpEvent.state = aModifierState;
1963   tmpEvent.keyval = keyval;
1964   tmpEvent.group = aGroup;
1965   return GetCharCodeFor(&tmpEvent);
1966 }
1967 
GetUnmodifiedCharCodeFor(const GdkEventKey * aGdkKeyEvent)1968 uint32_t KeymapWrapper::GetUnmodifiedCharCodeFor(
1969     const GdkEventKey* aGdkKeyEvent) {
1970   guint state = aGdkKeyEvent->state &
1971                 (GetModifierMask(SHIFT) | GetModifierMask(CAPS_LOCK) |
1972                  GetModifierMask(NUM_LOCK) | GetModifierMask(SCROLL_LOCK) |
1973                  GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5));
1974   uint32_t charCode =
1975       GetCharCodeFor(aGdkKeyEvent, GdkModifierType(state), aGdkKeyEvent->group);
1976   if (charCode) {
1977     return charCode;
1978   }
1979   // If no character is mapped to the key when Level3 Shift or Level5 Shift
1980   // is active, let's return a character which is inputted by the key without
1981   // Level3 nor Level5 Shift.
1982   guint stateWithoutAltGraph =
1983       state & ~(GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5));
1984   if (state == stateWithoutAltGraph) {
1985     return 0;
1986   }
1987   return GetCharCodeFor(aGdkKeyEvent, GdkModifierType(stateWithoutAltGraph),
1988                         aGdkKeyEvent->group);
1989 }
1990 
GetKeyLevel(GdkEventKey * aGdkKeyEvent)1991 gint KeymapWrapper::GetKeyLevel(GdkEventKey* aGdkKeyEvent) {
1992   gint level;
1993   if (!gdk_keymap_translate_keyboard_state(
1994           mGdkKeymap, aGdkKeyEvent->hardware_keycode,
1995           GdkModifierType(aGdkKeyEvent->state), aGdkKeyEvent->group, nullptr,
1996           nullptr, &level, nullptr)) {
1997     return -1;
1998   }
1999   return level;
2000 }
2001 
GetFirstLatinGroup()2002 gint KeymapWrapper::GetFirstLatinGroup() {
2003   GdkKeymapKey* keys;
2004   gint count;
2005   gint minGroup = -1;
2006   if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) {
2007     // find the minimum number group for latin inputtable layout
2008     for (gint i = 0; i < count && minGroup != 0; ++i) {
2009       if (keys[i].level != 0 && keys[i].level != 1) {
2010         continue;
2011       }
2012       if (minGroup >= 0 && keys[i].group > minGroup) {
2013         continue;
2014       }
2015       minGroup = keys[i].group;
2016     }
2017     g_free(keys);
2018   }
2019   return minGroup;
2020 }
2021 
IsLatinGroup(guint8 aGroup)2022 bool KeymapWrapper::IsLatinGroup(guint8 aGroup) {
2023   GdkKeymapKey* keys;
2024   gint count;
2025   bool result = false;
2026   if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) {
2027     for (gint i = 0; i < count; ++i) {
2028       if (keys[i].level != 0 && keys[i].level != 1) {
2029         continue;
2030       }
2031       if (keys[i].group == aGroup) {
2032         result = true;
2033         break;
2034       }
2035     }
2036     g_free(keys);
2037   }
2038   return result;
2039 }
2040 
IsAutoRepeatableKey(guint aHardwareKeyCode)2041 bool KeymapWrapper::IsAutoRepeatableKey(guint aHardwareKeyCode) {
2042   uint8_t indexOfArray = aHardwareKeyCode / 8;
2043   MOZ_ASSERT(indexOfArray < ArrayLength(mKeyboardState.auto_repeats),
2044              "invalid index");
2045   char bitMask = 1 << (aHardwareKeyCode % 8);
2046   return (mKeyboardState.auto_repeats[indexOfArray] & bitMask) != 0;
2047 }
2048 
2049 /* static */
IsBasicLatinLetterOrNumeral(uint32_t aCharCode)2050 bool KeymapWrapper::IsBasicLatinLetterOrNumeral(uint32_t aCharCode) {
2051   return (aCharCode >= 'a' && aCharCode <= 'z') ||
2052          (aCharCode >= 'A' && aCharCode <= 'Z') ||
2053          (aCharCode >= '0' && aCharCode <= '9');
2054 }
2055 
2056 /* static */
GetGDKKeyvalWithoutModifier(const GdkEventKey * aGdkKeyEvent)2057 guint KeymapWrapper::GetGDKKeyvalWithoutModifier(
2058     const GdkEventKey* aGdkKeyEvent) {
2059   KeymapWrapper* keymapWrapper = GetInstance();
2060   guint state =
2061       (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK));
2062   guint keyval;
2063   if (!gdk_keymap_translate_keyboard_state(
2064           keymapWrapper->mGdkKeymap, aGdkKeyEvent->hardware_keycode,
2065           GdkModifierType(state), aGdkKeyEvent->group, &keyval, nullptr,
2066           nullptr, nullptr)) {
2067     return 0;
2068   }
2069   return keyval;
2070 }
2071 
2072 /* static */
GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval)2073 uint32_t KeymapWrapper::GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval) {
2074   switch (aGdkKeyval) {
2075     case GDK_Cancel:
2076       return NS_VK_CANCEL;
2077     case GDK_BackSpace:
2078       return NS_VK_BACK;
2079     case GDK_Tab:
2080     case GDK_ISO_Left_Tab:
2081       return NS_VK_TAB;
2082     case GDK_Clear:
2083       return NS_VK_CLEAR;
2084     case GDK_Return:
2085       return NS_VK_RETURN;
2086     case GDK_Shift_L:
2087     case GDK_Shift_R:
2088     case GDK_Shift_Lock:
2089       return NS_VK_SHIFT;
2090     case GDK_Control_L:
2091     case GDK_Control_R:
2092       return NS_VK_CONTROL;
2093     case GDK_Alt_L:
2094     case GDK_Alt_R:
2095       return NS_VK_ALT;
2096     case GDK_Meta_L:
2097     case GDK_Meta_R:
2098       return NS_VK_META;
2099 
2100     // Assume that Super or Hyper is always mapped to physical Win key.
2101     case GDK_Super_L:
2102     case GDK_Super_R:
2103     case GDK_Hyper_L:
2104     case GDK_Hyper_R:
2105       return NS_VK_WIN;
2106 
2107     // GTK's AltGraph key is similar to Mac's Option (Alt) key.  However,
2108     // unfortunately, browsers on Mac are using NS_VK_ALT for it even though
2109     // it's really different from Alt key on Windows.
2110     // On the other hand, GTK's AltGrapsh keys are really different from
2111     // Alt key.  However, there is no AltGrapsh key on Windows.  On Windows,
2112     // both Ctrl and Alt keys are pressed internally when AltGr key is
2113     // pressed.  For some languages' users, AltGraph key is important, so,
2114     // web applications on such locale may want to know AltGraph key press.
2115     // Therefore, we should map AltGr keycode for them only on GTK.
2116     case GDK_ISO_Level3_Shift:
2117     case GDK_ISO_Level5_Shift:
2118     // We assume that Mode_switch is always used for level3 shift.
2119     case GDK_Mode_switch:
2120       return NS_VK_ALTGR;
2121 
2122     case GDK_Pause:
2123       return NS_VK_PAUSE;
2124     case GDK_Caps_Lock:
2125       return NS_VK_CAPS_LOCK;
2126     case GDK_Kana_Lock:
2127     case GDK_Kana_Shift:
2128       return NS_VK_KANA;
2129     case GDK_Hangul:
2130       return NS_VK_HANGUL;
2131     // case GDK_XXX:                   return NS_VK_JUNJA;
2132     // case GDK_XXX:                   return NS_VK_FINAL;
2133     case GDK_Hangul_Hanja:
2134       return NS_VK_HANJA;
2135     case GDK_Kanji:
2136       return NS_VK_KANJI;
2137     case GDK_Escape:
2138       return NS_VK_ESCAPE;
2139     case GDK_Henkan:
2140       return NS_VK_CONVERT;
2141     case GDK_Muhenkan:
2142       return NS_VK_NONCONVERT;
2143     // case GDK_XXX:                   return NS_VK_ACCEPT;
2144     // case GDK_XXX:                   return NS_VK_MODECHANGE;
2145     case GDK_Page_Up:
2146       return NS_VK_PAGE_UP;
2147     case GDK_Page_Down:
2148       return NS_VK_PAGE_DOWN;
2149     case GDK_End:
2150       return NS_VK_END;
2151     case GDK_Home:
2152       return NS_VK_HOME;
2153     case GDK_Left:
2154       return NS_VK_LEFT;
2155     case GDK_Up:
2156       return NS_VK_UP;
2157     case GDK_Right:
2158       return NS_VK_RIGHT;
2159     case GDK_Down:
2160       return NS_VK_DOWN;
2161     case GDK_Select:
2162       return NS_VK_SELECT;
2163     case GDK_Print:
2164       return NS_VK_PRINT;
2165     case GDK_Execute:
2166       return NS_VK_EXECUTE;
2167     case GDK_Insert:
2168       return NS_VK_INSERT;
2169     case GDK_Delete:
2170       return NS_VK_DELETE;
2171     case GDK_Help:
2172       return NS_VK_HELP;
2173 
2174     // keypad keys
2175     case GDK_KP_Left:
2176       return NS_VK_LEFT;
2177     case GDK_KP_Right:
2178       return NS_VK_RIGHT;
2179     case GDK_KP_Up:
2180       return NS_VK_UP;
2181     case GDK_KP_Down:
2182       return NS_VK_DOWN;
2183     case GDK_KP_Page_Up:
2184       return NS_VK_PAGE_UP;
2185     // Not sure what these are
2186     // case GDK_KP_Prior:              return NS_VK_;
2187     // case GDK_KP_Next:               return NS_VK_;
2188     case GDK_KP_Begin:
2189       return NS_VK_CLEAR;  // Num-unlocked 5
2190     case GDK_KP_Page_Down:
2191       return NS_VK_PAGE_DOWN;
2192     case GDK_KP_Home:
2193       return NS_VK_HOME;
2194     case GDK_KP_End:
2195       return NS_VK_END;
2196     case GDK_KP_Insert:
2197       return NS_VK_INSERT;
2198     case GDK_KP_Delete:
2199       return NS_VK_DELETE;
2200     case GDK_KP_Enter:
2201       return NS_VK_RETURN;
2202 
2203     case GDK_Num_Lock:
2204       return NS_VK_NUM_LOCK;
2205     case GDK_Scroll_Lock:
2206       return NS_VK_SCROLL_LOCK;
2207 
2208     // Function keys
2209     case GDK_F1:
2210       return NS_VK_F1;
2211     case GDK_F2:
2212       return NS_VK_F2;
2213     case GDK_F3:
2214       return NS_VK_F3;
2215     case GDK_F4:
2216       return NS_VK_F4;
2217     case GDK_F5:
2218       return NS_VK_F5;
2219     case GDK_F6:
2220       return NS_VK_F6;
2221     case GDK_F7:
2222       return NS_VK_F7;
2223     case GDK_F8:
2224       return NS_VK_F8;
2225     case GDK_F9:
2226       return NS_VK_F9;
2227     case GDK_F10:
2228       return NS_VK_F10;
2229     case GDK_F11:
2230       return NS_VK_F11;
2231     case GDK_F12:
2232       return NS_VK_F12;
2233     case GDK_F13:
2234       return NS_VK_F13;
2235     case GDK_F14:
2236       return NS_VK_F14;
2237     case GDK_F15:
2238       return NS_VK_F15;
2239     case GDK_F16:
2240       return NS_VK_F16;
2241     case GDK_F17:
2242       return NS_VK_F17;
2243     case GDK_F18:
2244       return NS_VK_F18;
2245     case GDK_F19:
2246       return NS_VK_F19;
2247     case GDK_F20:
2248       return NS_VK_F20;
2249     case GDK_F21:
2250       return NS_VK_F21;
2251     case GDK_F22:
2252       return NS_VK_F22;
2253     case GDK_F23:
2254       return NS_VK_F23;
2255     case GDK_F24:
2256       return NS_VK_F24;
2257 
2258     // context menu key, keysym 0xff67, typically keycode 117 on 105-key
2259     // (Microsoft) x86 keyboards, located between right 'Windows' key and
2260     // right Ctrl key
2261     case GDK_Menu:
2262       return NS_VK_CONTEXT_MENU;
2263     case GDK_Sleep:
2264       return NS_VK_SLEEP;
2265 
2266     case GDK_3270_Attn:
2267       return NS_VK_ATTN;
2268     case GDK_3270_CursorSelect:
2269       return NS_VK_CRSEL;
2270     case GDK_3270_ExSelect:
2271       return NS_VK_EXSEL;
2272     case GDK_3270_EraseEOF:
2273       return NS_VK_EREOF;
2274     case GDK_3270_Play:
2275       return NS_VK_PLAY;
2276     // case GDK_XXX:                   return NS_VK_ZOOM;
2277     case GDK_3270_PA1:
2278       return NS_VK_PA1;
2279 
2280     // map Sun Keyboard special keysyms on to NS_VK keys
2281 
2282     // Sun F11 key generates SunF36(0x1005ff10) keysym
2283     case 0x1005ff10:
2284       return NS_VK_F11;
2285     // Sun F12 key generates SunF37(0x1005ff11) keysym
2286     case 0x1005ff11:
2287       return NS_VK_F12;
2288     default:
2289       return 0;
2290   }
2291 }
2292 
WillDispatchKeyboardEvent(WidgetKeyboardEvent & aKeyEvent,GdkEventKey * aGdkKeyEvent)2293 void KeymapWrapper::WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyEvent,
2294                                               GdkEventKey* aGdkKeyEvent) {
2295   GetInstance()->WillDispatchKeyboardEventInternal(aKeyEvent, aGdkKeyEvent);
2296 }
2297 
WillDispatchKeyboardEventInternal(WidgetKeyboardEvent & aKeyEvent,GdkEventKey * aGdkKeyEvent)2298 void KeymapWrapper::WillDispatchKeyboardEventInternal(
2299     WidgetKeyboardEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) {
2300   if (!aGdkKeyEvent) {
2301     // If aGdkKeyEvent is nullptr, we're trying to dispatch a fake keyboard
2302     // event in such case, we don't need to set alternative char codes.
2303     // So, we don't need to do nothing here.  This case is typically we're
2304     // dispatching eKeyDown or eKeyUp event during composition.
2305     return;
2306   }
2307 
2308   uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
2309   if (!charCode) {
2310     MOZ_LOG(gKeyLog, LogLevel::Info,
2311             ("%p WillDispatchKeyboardEventInternal, "
2312              "mKeyCode=0x%02X, charCode=0x%08X",
2313              this, aKeyEvent.mKeyCode, aKeyEvent.mCharCode));
2314     return;
2315   }
2316 
2317   // The mCharCode was set from mKeyValue. However, for example, when Ctrl key
2318   // is pressed, its value should indicate an ASCII character for backward
2319   // compatibility rather than inputting character without the modifiers.
2320   // Therefore, we need to modify mCharCode value here.
2321   aKeyEvent.SetCharCode(charCode);
2322 
2323   gint level = GetKeyLevel(aGdkKeyEvent);
2324   if (level != 0 && level != 1) {
2325     MOZ_LOG(gKeyLog, LogLevel::Info,
2326             ("%p WillDispatchKeyboardEventInternal, "
2327              "mKeyCode=0x%02X, mCharCode=0x%08X, level=%d",
2328              this, aKeyEvent.mKeyCode, aKeyEvent.mCharCode, level));
2329     return;
2330   }
2331 
2332   guint baseState =
2333       aGdkKeyEvent->state & ~(GetModifierMask(SHIFT) | GetModifierMask(CTRL) |
2334                               GetModifierMask(ALT) | GetModifierMask(META) |
2335                               GetModifierMask(SUPER) | GetModifierMask(HYPER));
2336 
2337   // We shold send both shifted char and unshifted char, all keyboard layout
2338   // users can use all keys.  Don't change event.mCharCode. On some keyboard
2339   // layouts, Ctrl/Alt/Meta keys are used for inputting some characters.
2340   AlternativeCharCode altCharCodes(0, 0);
2341   // unshifted charcode of current keyboard layout.
2342   altCharCodes.mUnshiftedCharCode =
2343       GetCharCodeFor(aGdkKeyEvent, baseState, aGdkKeyEvent->group);
2344   bool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF);
2345   // shifted charcode of current keyboard layout.
2346   altCharCodes.mShiftedCharCode = GetCharCodeFor(
2347       aGdkKeyEvent, baseState | GetModifierMask(SHIFT), aGdkKeyEvent->group);
2348   isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF);
2349   if (altCharCodes.mUnshiftedCharCode || altCharCodes.mShiftedCharCode) {
2350     aKeyEvent.mAlternativeCharCodes.AppendElement(altCharCodes);
2351   }
2352 
2353   bool needLatinKeyCodes = !isLatin;
2354   if (!needLatinKeyCodes) {
2355     needLatinKeyCodes =
2356         (IS_ASCII_ALPHABETICAL(altCharCodes.mUnshiftedCharCode) !=
2357          IS_ASCII_ALPHABETICAL(altCharCodes.mShiftedCharCode));
2358   }
2359 
2360   // If current keyboard layout can input Latin characters, we don't need
2361   // more information.
2362   if (!needLatinKeyCodes) {
2363     MOZ_LOG(gKeyLog, LogLevel::Info,
2364             ("%p WillDispatchKeyboardEventInternal, "
2365              "mKeyCode=0x%02X, mCharCode=0x%08X, level=%d, altCharCodes={ "
2366              "mUnshiftedCharCode=0x%08X, mShiftedCharCode=0x%08X }",
2367              this, aKeyEvent.mKeyCode, aKeyEvent.mCharCode, level,
2368              altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode));
2369     return;
2370   }
2371 
2372   // Next, find Latin inputtable keyboard layout.
2373   gint minGroup = GetFirstLatinGroup();
2374   if (minGroup < 0) {
2375     MOZ_LOG(gKeyLog, LogLevel::Info,
2376             ("%p WillDispatchKeyboardEventInternal, "
2377              "Latin keyboard layout isn't found: "
2378              "mKeyCode=0x%02X, mCharCode=0x%08X, level=%d, "
2379              "altCharCodes={ mUnshiftedCharCode=0x%08X, "
2380              "mShiftedCharCode=0x%08X }",
2381              this, aKeyEvent.mKeyCode, aKeyEvent.mCharCode, level,
2382              altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode));
2383     return;
2384   }
2385 
2386   AlternativeCharCode altLatinCharCodes(0, 0);
2387   uint32_t unmodifiedCh = aKeyEvent.IsShift() ? altCharCodes.mShiftedCharCode
2388                                               : altCharCodes.mUnshiftedCharCode;
2389 
2390   // unshifted charcode of found keyboard layout.
2391   uint32_t ch = GetCharCodeFor(aGdkKeyEvent, baseState, minGroup);
2392   altLatinCharCodes.mUnshiftedCharCode =
2393       IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
2394   // shifted charcode of found keyboard layout.
2395   ch = GetCharCodeFor(aGdkKeyEvent, baseState | GetModifierMask(SHIFT),
2396                       minGroup);
2397   altLatinCharCodes.mShiftedCharCode = IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
2398   if (altLatinCharCodes.mUnshiftedCharCode ||
2399       altLatinCharCodes.mShiftedCharCode) {
2400     aKeyEvent.mAlternativeCharCodes.AppendElement(altLatinCharCodes);
2401   }
2402   // If the mCharCode is not Latin, and the level is 0 or 1, we should
2403   // replace the mCharCode to Latin char if Alt and Meta keys are not
2404   // pressed. (Alt should be sent the localized char for accesskey
2405   // like handling of Web Applications.)
2406   ch = aKeyEvent.IsShift() ? altLatinCharCodes.mShiftedCharCode
2407                            : altLatinCharCodes.mUnshiftedCharCode;
2408   if (ch && !(aKeyEvent.IsAlt() || aKeyEvent.IsMeta()) &&
2409       charCode == unmodifiedCh) {
2410     aKeyEvent.SetCharCode(ch);
2411   }
2412 
2413   MOZ_LOG(gKeyLog, LogLevel::Info,
2414           ("%p WillDispatchKeyboardEventInternal, "
2415            "mKeyCode=0x%02X, mCharCode=0x%08X, level=%d, minGroup=%d, "
2416            "altCharCodes={ mUnshiftedCharCode=0x%08X, "
2417            "mShiftedCharCode=0x%08X } "
2418            "altLatinCharCodes={ mUnshiftedCharCode=0x%08X, "
2419            "mShiftedCharCode=0x%08X }",
2420            this, aKeyEvent.mKeyCode, aKeyEvent.mCharCode, level, minGroup,
2421            altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode,
2422            altLatinCharCodes.mUnshiftedCharCode,
2423            altLatinCharCodes.mShiftedCharCode));
2424 }
2425 
2426 #ifdef MOZ_WAYLAND
SetFocusIn(wl_surface * aFocusSurface,uint32_t aFocusSerial)2427 void KeymapWrapper::SetFocusIn(wl_surface* aFocusSurface,
2428                                uint32_t aFocusSerial) {
2429   LOGW("KeymapWrapper::SetFocusIn() surface %p ID %d serial %d", aFocusSurface,
2430        aFocusSurface ? wl_proxy_get_id((struct wl_proxy*)aFocusSurface) : 0,
2431        aFocusSerial);
2432 
2433   KeymapWrapper* keymapWrapper = KeymapWrapper::GetInstance();
2434   keymapWrapper->mFocusSurface = aFocusSurface;
2435   keymapWrapper->mFocusSerial = aFocusSerial;
2436 }
2437 
2438 // aFocusSurface can be null in case that focused surface is already destroyed.
SetFocusOut(wl_surface * aFocusSurface)2439 void KeymapWrapper::SetFocusOut(wl_surface* aFocusSurface) {
2440   KeymapWrapper* keymapWrapper = KeymapWrapper::GetInstance();
2441   LOGW("KeymapWrapper::SetFocusOut surface %p ID %d", aFocusSurface,
2442        aFocusSurface ? wl_proxy_get_id((struct wl_proxy*)aFocusSurface) : 0);
2443 
2444   keymapWrapper->mFocusSurface = nullptr;
2445   keymapWrapper->mFocusSerial = 0;
2446 }
2447 
GetFocusInfo(wl_surface ** aFocusSurface,uint32_t * aFocusSerial)2448 void KeymapWrapper::GetFocusInfo(wl_surface** aFocusSurface,
2449                                  uint32_t* aFocusSerial) {
2450   KeymapWrapper* keymapWrapper = KeymapWrapper::GetInstance();
2451   *aFocusSurface = keymapWrapper->mFocusSurface;
2452   *aFocusSerial = keymapWrapper->mFocusSerial;
2453 }
2454 
SetSeat(wl_seat * aSeat)2455 void KeymapWrapper::SetSeat(wl_seat* aSeat) {
2456   KeymapWrapper* keymapWrapper = KeymapWrapper::GetInstance();
2457   keymapWrapper->mSeat = aSeat;
2458 }
2459 
GetSeat()2460 wl_seat* KeymapWrapper::GetSeat() {
2461   KeymapWrapper* keymapWrapper = KeymapWrapper::GetInstance();
2462   return keymapWrapper->mSeat;
2463 }
2464 #endif
2465 
2466 }  // namespace widget
2467 }  // namespace mozilla
2468