widget/gtk/nsGtkKeyUtils.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial