LCOV - code coverage report
Current view: top level - widget/gtk - nsGtkKeyUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 186 654 28.4 %
Date: 2017-07-14 16:53:18 Functions: 12 38 31.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13