widget/gtk/nsGtkKeyUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/gtk/nsGtkKeyUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1467 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim:expandtab:shiftwidth=4:tabstop=4:
     1.6 + */
     1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +#include "prlog.h"
    1.12 +
    1.13 +#include "nsGtkKeyUtils.h"
    1.14 +
    1.15 +#include <gdk/gdkkeysyms.h>
    1.16 +#include <algorithm>
    1.17 +#include <gdk/gdk.h>
    1.18 +#include <gdk/gdkx.h>
    1.19 +#if (MOZ_WIDGET_GTK == 3)
    1.20 +#include <gdk/gdkkeysyms-compat.h>
    1.21 +#endif
    1.22 +#include <X11/XKBlib.h>
    1.23 +#include "WidgetUtils.h"
    1.24 +#include "keysym2ucs.h"
    1.25 +#include "nsIBidiKeyboard.h"
    1.26 +#include "nsServiceManagerUtils.h"
    1.27 +
    1.28 +#ifdef PR_LOGGING
    1.29 +PRLogModuleInfo* gKeymapWrapperLog = nullptr;
    1.30 +#endif // PR_LOGGING
    1.31 +
    1.32 +#include "mozilla/ArrayUtils.h"
    1.33 +#include "mozilla/MouseEvents.h"
    1.34 +#include "mozilla/TextEvents.h"
    1.35 +
    1.36 +namespace mozilla {
    1.37 +namespace widget {
    1.38 +
    1.39 +#define IS_ASCII_ALPHABETICAL(key) \
    1.40 +    ((('a' <= key) && (key <= 'z')) || (('A' <= key) && (key <= 'Z')))
    1.41 +
    1.42 +#define MOZ_MODIFIER_KEYS "MozKeymapWrapper"
    1.43 +
    1.44 +KeymapWrapper* KeymapWrapper::sInstance = nullptr;
    1.45 +guint KeymapWrapper::sLastRepeatableHardwareKeyCode = 0;
    1.46 +KeymapWrapper::RepeatState KeymapWrapper::sRepeatState =
    1.47 +    KeymapWrapper::NOT_PRESSED;
    1.48 +nsIBidiKeyboard* sBidiKeyboard = nullptr;
    1.49 +
    1.50 +#ifdef PR_LOGGING
    1.51 +
    1.52 +static const char* GetBoolName(bool aBool)
    1.53 +{
    1.54 +    return aBool ? "TRUE" : "FALSE";
    1.55 +}
    1.56 +
    1.57 +/* static */ const char*
    1.58 +KeymapWrapper::GetModifierName(Modifier aModifier)
    1.59 +{
    1.60 +    switch (aModifier) {
    1.61 +        case CAPS_LOCK:    return "CapsLock";
    1.62 +        case NUM_LOCK:     return "NumLock";
    1.63 +        case SCROLL_LOCK:  return "ScrollLock";
    1.64 +        case SHIFT:        return "Shift";
    1.65 +        case CTRL:         return "Ctrl";
    1.66 +        case ALT:          return "Alt";
    1.67 +        case SUPER:        return "Super";
    1.68 +        case HYPER:        return "Hyper";
    1.69 +        case META:         return "Meta";
    1.70 +        case LEVEL3:       return "Level3";
    1.71 +        case LEVEL5:       return "Level5";
    1.72 +        case NOT_MODIFIER: return "NotModifier";
    1.73 +        default:           return "InvalidValue";
    1.74 +    }
    1.75 +}
    1.76 +
    1.77 +#endif // PR_LOGGING
    1.78 +
    1.79 +/* static */ KeymapWrapper::Modifier
    1.80 +KeymapWrapper::GetModifierForGDKKeyval(guint aGdkKeyval)
    1.81 +{
    1.82 +    switch (aGdkKeyval) {
    1.83 +        case GDK_Caps_Lock:        return CAPS_LOCK;
    1.84 +        case GDK_Num_Lock:         return NUM_LOCK;
    1.85 +        case GDK_Scroll_Lock:      return SCROLL_LOCK;
    1.86 +        case GDK_Shift_Lock:
    1.87 +        case GDK_Shift_L:
    1.88 +        case GDK_Shift_R:          return SHIFT;
    1.89 +        case GDK_Control_L:
    1.90 +        case GDK_Control_R:        return CTRL;
    1.91 +        case GDK_Alt_L:
    1.92 +        case GDK_Alt_R:            return ALT;
    1.93 +        case GDK_Super_L:
    1.94 +        case GDK_Super_R:          return SUPER;
    1.95 +        case GDK_Hyper_L:
    1.96 +        case GDK_Hyper_R:          return HYPER;
    1.97 +        case GDK_Meta_L:
    1.98 +        case GDK_Meta_R:           return META;
    1.99 +        case GDK_ISO_Level3_Shift:
   1.100 +        case GDK_Mode_switch:      return LEVEL3;
   1.101 +        case GDK_ISO_Level5_Shift: return LEVEL5;
   1.102 +        default:                   return NOT_MODIFIER;
   1.103 +    }
   1.104 +}
   1.105 +
   1.106 +guint
   1.107 +KeymapWrapper::GetModifierMask(Modifier aModifier) const
   1.108 +{
   1.109 +    switch (aModifier) {
   1.110 +        case CAPS_LOCK:
   1.111 +            return GDK_LOCK_MASK;
   1.112 +        case NUM_LOCK:
   1.113 +            return mModifierMasks[INDEX_NUM_LOCK];
   1.114 +        case SCROLL_LOCK:
   1.115 +            return mModifierMasks[INDEX_SCROLL_LOCK];
   1.116 +        case SHIFT:
   1.117 +            return GDK_SHIFT_MASK;
   1.118 +        case CTRL:
   1.119 +            return GDK_CONTROL_MASK;
   1.120 +        case ALT:
   1.121 +            return mModifierMasks[INDEX_ALT];
   1.122 +        case SUPER:
   1.123 +            return mModifierMasks[INDEX_SUPER];
   1.124 +        case HYPER:
   1.125 +            return mModifierMasks[INDEX_HYPER];
   1.126 +        case META:
   1.127 +            return mModifierMasks[INDEX_META];
   1.128 +        case LEVEL3:
   1.129 +            return mModifierMasks[INDEX_LEVEL3];
   1.130 +        case LEVEL5:
   1.131 +            return mModifierMasks[INDEX_LEVEL5];
   1.132 +        default:
   1.133 +            return 0;
   1.134 +    }
   1.135 +}
   1.136 +
   1.137 +KeymapWrapper::ModifierKey*
   1.138 +KeymapWrapper::GetModifierKey(guint aHardwareKeycode)
   1.139 +{
   1.140 +    for (uint32_t i = 0; i < mModifierKeys.Length(); i++) {
   1.141 +        ModifierKey& key = mModifierKeys[i];
   1.142 +        if (key.mHardwareKeycode == aHardwareKeycode) {
   1.143 +            return &key;
   1.144 +        }
   1.145 +    }
   1.146 +    return nullptr;
   1.147 +}
   1.148 +
   1.149 +/* static */ KeymapWrapper*
   1.150 +KeymapWrapper::GetInstance()
   1.151 +{
   1.152 +    if (sInstance) {
   1.153 +        sInstance->Init();
   1.154 +        return sInstance;
   1.155 +    }
   1.156 +
   1.157 +    sInstance = new KeymapWrapper();
   1.158 +    return sInstance;
   1.159 +}
   1.160 +
   1.161 +KeymapWrapper::KeymapWrapper() :
   1.162 +    mInitialized(false), mGdkKeymap(gdk_keymap_get_default()),
   1.163 +    mXKBBaseEventCode(0)
   1.164 +{
   1.165 +#ifdef PR_LOGGING
   1.166 +    if (!gKeymapWrapperLog) {
   1.167 +        gKeymapWrapperLog = PR_NewLogModule("KeymapWrapperWidgets");
   1.168 +    }
   1.169 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.170 +        ("KeymapWrapper(%p): Constructor, mGdkKeymap=%p",
   1.171 +         this, mGdkKeymap));
   1.172 +#endif // PR_LOGGING
   1.173 +
   1.174 +    g_signal_connect(mGdkKeymap, "keys-changed",
   1.175 +                     (GCallback)OnKeysChanged, this);
   1.176 +
   1.177 +    // This is necessary for catching the destroying timing.
   1.178 +    g_object_weak_ref(G_OBJECT(mGdkKeymap),
   1.179 +                      (GWeakNotify)OnDestroyKeymap, this);
   1.180 +
   1.181 +    InitXKBExtension();
   1.182 +
   1.183 +    Init();
   1.184 +}
   1.185 +
   1.186 +void
   1.187 +KeymapWrapper::Init()
   1.188 +{
   1.189 +    if (mInitialized) {
   1.190 +        return;
   1.191 +    }
   1.192 +    mInitialized = true;
   1.193 +
   1.194 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.195 +        ("KeymapWrapper(%p): Init, mGdkKeymap=%p",
   1.196 +         this, mGdkKeymap));
   1.197 +
   1.198 +    mModifierKeys.Clear();
   1.199 +    memset(mModifierMasks, 0, sizeof(mModifierMasks));
   1.200 +
   1.201 +    InitBySystemSettings();
   1.202 +
   1.203 +    gdk_window_add_filter(nullptr, FilterEvents, this);
   1.204 +
   1.205 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.206 +        ("KeymapWrapper(%p): Init, CapsLock=0x%X, NumLock=0x%X, "
   1.207 +         "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
   1.208 +         "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X",
   1.209 +         this,
   1.210 +         GetModifierMask(CAPS_LOCK), GetModifierMask(NUM_LOCK),
   1.211 +         GetModifierMask(SCROLL_LOCK), GetModifierMask(LEVEL3),
   1.212 +         GetModifierMask(LEVEL5),
   1.213 +         GetModifierMask(SHIFT), GetModifierMask(CTRL),
   1.214 +         GetModifierMask(ALT), GetModifierMask(META),
   1.215 +         GetModifierMask(SUPER), GetModifierMask(HYPER)));
   1.216 +}
   1.217 +
   1.218 +void
   1.219 +KeymapWrapper::InitXKBExtension()
   1.220 +{
   1.221 +    PodZero(&mKeyboardState);
   1.222 +
   1.223 +    int xkbMajorVer = XkbMajorVersion;
   1.224 +    int xkbMinorVer = XkbMinorVersion;
   1.225 +    if (!XkbLibraryVersion(&xkbMajorVer, &xkbMinorVer)) {
   1.226 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.227 +               ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
   1.228 +                "XkbLibraryVersion()", this));
   1.229 +        return;
   1.230 +    }
   1.231 +
   1.232 +    Display* display =
   1.233 +        gdk_x11_display_get_xdisplay(gdk_display_get_default());
   1.234 +
   1.235 +    // XkbLibraryVersion() set xkbMajorVer and xkbMinorVer to that of the
   1.236 +    // library, which may be newer than what is required of the server in
   1.237 +    // XkbQueryExtension(), so these variables should be reset to
   1.238 +    // XkbMajorVersion and XkbMinorVersion before the XkbQueryExtension call.
   1.239 +    xkbMajorVer = XkbMajorVersion;
   1.240 +    xkbMinorVer = XkbMinorVersion;
   1.241 +    int opcode, baseErrorCode;
   1.242 +    if (!XkbQueryExtension(display, &opcode, &mXKBBaseEventCode, &baseErrorCode,
   1.243 +                           &xkbMajorVer, &xkbMinorVer)) {
   1.244 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.245 +               ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
   1.246 +                "XkbQueryExtension(), display=0x%p", this, display));
   1.247 +        return;
   1.248 +    }
   1.249 +
   1.250 +    if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotify,
   1.251 +                               XkbModifierStateMask, XkbModifierStateMask)) {
   1.252 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.253 +               ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
   1.254 +                "XkbSelectEventDetails() for XModifierStateMask, display=0x%p",
   1.255 +                this, display));
   1.256 +        return;
   1.257 +    }
   1.258 +
   1.259 +    if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbControlsNotify,
   1.260 +                               XkbPerKeyRepeatMask, XkbPerKeyRepeatMask)) {
   1.261 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.262 +               ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
   1.263 +                "XkbSelectEventDetails() for XkbControlsNotify, display=0x%p",
   1.264 +                this, display));
   1.265 +        return;
   1.266 +    }
   1.267 +
   1.268 +    if (!XGetKeyboardControl(display, &mKeyboardState)) {
   1.269 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.270 +               ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
   1.271 +                "XGetKeyboardControl(), display=0x%p",
   1.272 +                this, display));
   1.273 +        return;
   1.274 +    }
   1.275 +
   1.276 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.277 +           ("KeymapWrapper(%p): InitXKBExtension, Succeeded", this));
   1.278 +}
   1.279 +
   1.280 +void
   1.281 +KeymapWrapper::InitBySystemSettings()
   1.282 +{
   1.283 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.284 +      ("KeymapWrapper(%p): InitBySystemSettings, mGdkKeymap=%p",
   1.285 +       this, mGdkKeymap));
   1.286 +
   1.287 +    Display* display =
   1.288 +        gdk_x11_display_get_xdisplay(gdk_display_get_default());
   1.289 +
   1.290 +    int min_keycode = 0;
   1.291 +    int max_keycode = 0;
   1.292 +    XDisplayKeycodes(display, &min_keycode, &max_keycode);
   1.293 +
   1.294 +    int keysyms_per_keycode = 0;
   1.295 +    KeySym* xkeymap = XGetKeyboardMapping(display, min_keycode,
   1.296 +                                          max_keycode - min_keycode + 1,
   1.297 +                                          &keysyms_per_keycode);
   1.298 +    if (!xkeymap) {
   1.299 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.300 +            ("KeymapWrapper(%p): InitBySystemSettings, "
   1.301 +             "Failed due to null xkeymap", this));
   1.302 +        return;
   1.303 +    }
   1.304 +
   1.305 +    XModifierKeymap* xmodmap = XGetModifierMapping(display);
   1.306 +    if (!xmodmap) {
   1.307 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.308 +            ("KeymapWrapper(%p): InitBySystemSettings, "
   1.309 +             "Failed due to null xmodmap", this));
   1.310 +        XFree(xkeymap);
   1.311 +        return;
   1.312 +    }
   1.313 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.314 +        ("KeymapWrapper(%p): InitBySystemSettings, min_keycode=%d, "
   1.315 +         "max_keycode=%d, keysyms_per_keycode=%d, max_keypermod=%d",
   1.316 +         this, min_keycode, max_keycode, keysyms_per_keycode,
   1.317 +         xmodmap->max_keypermod));
   1.318 +
   1.319 +    // The modifiermap member of the XModifierKeymap structure contains 8 sets
   1.320 +    // of max_keypermod KeyCodes, one for each modifier in the order Shift,
   1.321 +    // Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5.
   1.322 +    // Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are
   1.323 +    // ignored.
   1.324 +
   1.325 +    // Note that two or more modifiers may use one modifier flag.  E.g.,
   1.326 +    // on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings.
   1.327 +    // And also Super and Hyper share the Mod4. In such cases, we need to
   1.328 +    // decide which modifier flag means one of DOM modifiers.
   1.329 +
   1.330 +    // mod[0] is Modifier introduced by Mod1.
   1.331 +    Modifier mod[5];
   1.332 +    int32_t foundLevel[5];
   1.333 +    for (uint32_t i = 0; i < ArrayLength(mod); i++) {
   1.334 +        mod[i] = NOT_MODIFIER;
   1.335 +        foundLevel[i] = INT32_MAX;
   1.336 +    }
   1.337 +    const uint32_t map_size = 8 * xmodmap->max_keypermod;
   1.338 +    for (uint32_t i = 0; i < map_size; i++) {
   1.339 +        KeyCode keycode = xmodmap->modifiermap[i];
   1.340 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.341 +            ("KeymapWrapper(%p): InitBySystemSettings, "
   1.342 +             "  i=%d, keycode=0x%08X",
   1.343 +             this, i, keycode));
   1.344 +        if (!keycode || keycode < min_keycode || keycode > max_keycode) {
   1.345 +            continue;
   1.346 +        }
   1.347 +
   1.348 +        ModifierKey* modifierKey = GetModifierKey(keycode);
   1.349 +        if (!modifierKey) {
   1.350 +            modifierKey = mModifierKeys.AppendElement(ModifierKey(keycode));
   1.351 +        }
   1.352 +
   1.353 +        const KeySym* syms =
   1.354 +            xkeymap + (keycode - min_keycode) * keysyms_per_keycode;
   1.355 +        const uint32_t bit = i / xmodmap->max_keypermod;
   1.356 +        modifierKey->mMask |= 1 << bit;
   1.357 +
   1.358 +        // We need to know the meaning of Mod1, Mod2, Mod3, Mod4 and Mod5.
   1.359 +        // Let's skip if current map is for others.
   1.360 +        if (bit < 3) {
   1.361 +            continue;
   1.362 +        }
   1.363 +
   1.364 +        const int32_t modIndex = bit - 3;
   1.365 +        for (int32_t j = 0; j < keysyms_per_keycode; j++) {
   1.366 +            Modifier modifier = GetModifierForGDKKeyval(syms[j]);
   1.367 +            PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.368 +                ("KeymapWrapper(%p): InitBySystemSettings, "
   1.369 +                 "    Mod%d, j=%d, syms[j]=%s(0x%X), modifier=%s",
   1.370 +                 this, modIndex + 1, j, gdk_keyval_name(syms[j]), syms[j],
   1.371 +                 GetModifierName(modifier)));
   1.372 +
   1.373 +            switch (modifier) {
   1.374 +                case NOT_MODIFIER:
   1.375 +                    // Don't overwrite the stored information with
   1.376 +                    // NOT_MODIFIER.
   1.377 +                    break;
   1.378 +                case CAPS_LOCK:
   1.379 +                case SHIFT:
   1.380 +                case CTRL:
   1.381 +                    // Ignore the modifiers defined in GDK spec. They shouldn't
   1.382 +                    // be mapped to Mod1-5 because they must not work on native
   1.383 +                    // GTK applications.
   1.384 +                    break;
   1.385 +                default:
   1.386 +                    // If new modifier is found in higher level than stored
   1.387 +                    // value, we don't need to overwrite it.
   1.388 +                    if (j > foundLevel[modIndex]) {
   1.389 +                        break;
   1.390 +                    }
   1.391 +                    // If new modifier is more important than stored value,
   1.392 +                    // we should overwrite it with new modifier.
   1.393 +                    if (j == foundLevel[modIndex]) {
   1.394 +                        mod[modIndex] = std::min(modifier, mod[modIndex]);
   1.395 +                        break;
   1.396 +                    }
   1.397 +                    foundLevel[modIndex] = j;
   1.398 +                    mod[modIndex] = modifier;
   1.399 +                    break;
   1.400 +            }
   1.401 +        }
   1.402 +    }
   1.403 +
   1.404 +    for (uint32_t i = 0; i < COUNT_OF_MODIFIER_INDEX; i++) {
   1.405 +        Modifier modifier;
   1.406 +        switch (i) {
   1.407 +            case INDEX_NUM_LOCK:
   1.408 +                modifier = NUM_LOCK;
   1.409 +                break;
   1.410 +            case INDEX_SCROLL_LOCK:
   1.411 +                modifier = SCROLL_LOCK;
   1.412 +                break;
   1.413 +            case INDEX_ALT:
   1.414 +                modifier = ALT;
   1.415 +                break;
   1.416 +            case INDEX_META:
   1.417 +                modifier = META;
   1.418 +                break;
   1.419 +            case INDEX_SUPER:
   1.420 +                modifier = SUPER;
   1.421 +                break;
   1.422 +            case INDEX_HYPER:
   1.423 +                modifier = HYPER;
   1.424 +                break;
   1.425 +            case INDEX_LEVEL3:
   1.426 +                modifier = LEVEL3;
   1.427 +                break;
   1.428 +            case INDEX_LEVEL5:
   1.429 +                modifier = LEVEL5;
   1.430 +                break;
   1.431 +            default:
   1.432 +                MOZ_CRASH("All indexes must be handled here");
   1.433 +        }
   1.434 +        for (uint32_t j = 0; j < ArrayLength(mod); j++) {
   1.435 +            if (modifier == mod[j]) {
   1.436 +                mModifierMasks[i] |= 1 << (j + 3);
   1.437 +            }
   1.438 +        }
   1.439 +    }
   1.440 +
   1.441 +    XFreeModifiermap(xmodmap);
   1.442 +    XFree(xkeymap);
   1.443 +}
   1.444 +
   1.445 +KeymapWrapper::~KeymapWrapper()
   1.446 +{
   1.447 +    gdk_window_remove_filter(nullptr, FilterEvents, this);
   1.448 +    NS_IF_RELEASE(sBidiKeyboard);
   1.449 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.450 +        ("KeymapWrapper(%p): Destructor", this));
   1.451 +}
   1.452 +
   1.453 +/* static */ GdkFilterReturn
   1.454 +KeymapWrapper::FilterEvents(GdkXEvent* aXEvent,
   1.455 +                            GdkEvent* aGdkEvent,
   1.456 +                            gpointer aData)
   1.457 +{
   1.458 +    XEvent* xEvent = static_cast<XEvent*>(aXEvent);
   1.459 +    switch (xEvent->type) {
   1.460 +        case KeyPress: {
   1.461 +            // If the key doesn't support auto repeat, ignore the event because
   1.462 +            // even if such key (e.g., Shift) is pressed during auto repeat of
   1.463 +            // anoter key, it doesn't stop the auto repeat.
   1.464 +            KeymapWrapper* self = static_cast<KeymapWrapper*>(aData);
   1.465 +            if (!self->IsAutoRepeatableKey(xEvent->xkey.keycode)) {
   1.466 +                break;
   1.467 +            }
   1.468 +            if (sRepeatState == NOT_PRESSED) {
   1.469 +                sRepeatState = FIRST_PRESS;
   1.470 +            } else if (sLastRepeatableHardwareKeyCode == xEvent->xkey.keycode) {
   1.471 +                sRepeatState = REPEATING;
   1.472 +            } else {
   1.473 +                // If a different key is pressed while another key is pressed,
   1.474 +                // auto repeat system repeats only the last pressed key.
   1.475 +                // So, setting new keycode and setting repeat state as first key
   1.476 +                // press should work fine.
   1.477 +                sRepeatState = FIRST_PRESS;
   1.478 +            }
   1.479 +            sLastRepeatableHardwareKeyCode = xEvent->xkey.keycode;
   1.480 +            break;
   1.481 +        }
   1.482 +        case KeyRelease: {
   1.483 +            if (sLastRepeatableHardwareKeyCode != xEvent->xkey.keycode) {
   1.484 +                // This case means the key release event is caused by
   1.485 +                // a non-repeatable key such as Shift or a repeatable key that
   1.486 +                // was pressed before sLastRepeatableHardwareKeyCode was
   1.487 +                // pressed.
   1.488 +                break;
   1.489 +            }
   1.490 +            sRepeatState = NOT_PRESSED;
   1.491 +            break;
   1.492 +        }
   1.493 +        case FocusOut: {
   1.494 +            // At moving focus, we should reset keyboard repeat state.
   1.495 +            // Strictly, this causes incorrect behavior.  However, this
   1.496 +            // correctness must be enough for web applications.
   1.497 +            sRepeatState = NOT_PRESSED;
   1.498 +            break;
   1.499 +        }
   1.500 +        default: {
   1.501 +            KeymapWrapper* self = static_cast<KeymapWrapper*>(aData);
   1.502 +            if (xEvent->type != self->mXKBBaseEventCode) {
   1.503 +                break;
   1.504 +            }
   1.505 +            XkbEvent* xkbEvent = (XkbEvent*)xEvent;
   1.506 +            if (xkbEvent->any.xkb_type != XkbControlsNotify ||
   1.507 +                !(xkbEvent->ctrls.changed_ctrls & XkbPerKeyRepeatMask)) {
   1.508 +                break;
   1.509 +            }
   1.510 +            if (!XGetKeyboardControl(xkbEvent->any.display,
   1.511 +                                     &self->mKeyboardState)) {
   1.512 +                PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.513 +                       ("KeymapWrapper(%p): FilterEvents failed due to failure "
   1.514 +                        "of XGetKeyboardControl(), display=0x%p",
   1.515 +                        self, xkbEvent->any.display));
   1.516 +            }
   1.517 +            break;
   1.518 +        }
   1.519 +    }
   1.520 +
   1.521 +    return GDK_FILTER_CONTINUE;
   1.522 +}
   1.523 +
   1.524 +/* static */ void
   1.525 +KeymapWrapper::OnDestroyKeymap(KeymapWrapper* aKeymapWrapper,
   1.526 +                               GdkKeymap *aGdkKeymap)
   1.527 +{
   1.528 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.529 +        ("KeymapWrapper: OnDestroyKeymap, aGdkKeymap=%p, aKeymapWrapper=%p",
   1.530 +         aGdkKeymap, aKeymapWrapper));
   1.531 +    MOZ_ASSERT(aKeymapWrapper == sInstance,
   1.532 +               "Desroying unexpected instance");
   1.533 +    delete sInstance;
   1.534 +    sInstance = nullptr;
   1.535 +}
   1.536 +
   1.537 +/* static */ void
   1.538 +KeymapWrapper::OnKeysChanged(GdkKeymap *aGdkKeymap,
   1.539 +                             KeymapWrapper* aKeymapWrapper)
   1.540 +{
   1.541 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.542 +        ("KeymapWrapper: OnKeysChanged, aGdkKeymap=%p, aKeymapWrapper=%p",
   1.543 +         aGdkKeymap, aKeymapWrapper));
   1.544 +
   1.545 +    MOZ_ASSERT(sInstance == aKeymapWrapper,
   1.546 +               "This instance must be the singleton instance");
   1.547 +
   1.548 +    // We cannot reintialize here becasue we don't have GdkWindow which is using
   1.549 +    // the GdkKeymap.  We'll reinitialize it when next GetInstance() is called.
   1.550 +    sInstance->mInitialized = false;
   1.551 +
   1.552 +    // Reset the bidi keyboard settings for the new GdkKeymap
   1.553 +    if (!sBidiKeyboard) {
   1.554 +        CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard);
   1.555 +    }
   1.556 +    if (sBidiKeyboard) {
   1.557 +        sBidiKeyboard->Reset();
   1.558 +    }
   1.559 +}
   1.560 +
   1.561 +/* static */ guint
   1.562 +KeymapWrapper::GetCurrentModifierState()
   1.563 +{
   1.564 +    GdkModifierType modifiers;
   1.565 +    gdk_display_get_pointer(gdk_display_get_default(),
   1.566 +                            nullptr, nullptr, nullptr, &modifiers);
   1.567 +    return static_cast<guint>(modifiers);
   1.568 +}
   1.569 +
   1.570 +/* static */ bool
   1.571 +KeymapWrapper::AreModifiersCurrentlyActive(Modifiers aModifiers)
   1.572 +{
   1.573 +    guint modifierState = GetCurrentModifierState();
   1.574 +    return AreModifiersActive(aModifiers, modifierState);
   1.575 +}
   1.576 +
   1.577 +/* static */ bool
   1.578 +KeymapWrapper::AreModifiersActive(Modifiers aModifiers,
   1.579 +                                  guint aModifierState)
   1.580 +{
   1.581 +    NS_ENSURE_TRUE(aModifiers, false);
   1.582 +
   1.583 +    KeymapWrapper* keymapWrapper = GetInstance();
   1.584 +    for (uint32_t i = 0; i < sizeof(Modifier) * 8 && aModifiers; i++) {
   1.585 +        Modifier modifier = static_cast<Modifier>(1 << i);
   1.586 +        if (!(aModifiers & modifier)) {
   1.587 +            continue;
   1.588 +        }
   1.589 +        if (!(aModifierState & keymapWrapper->GetModifierMask(modifier))) {
   1.590 +            return false;
   1.591 +        }
   1.592 +        aModifiers &= ~modifier;
   1.593 +    }
   1.594 +    return true;
   1.595 +}
   1.596 +
   1.597 +/* static */ void
   1.598 +KeymapWrapper::InitInputEvent(WidgetInputEvent& aInputEvent,
   1.599 +                              guint aModifierState)
   1.600 +{
   1.601 +    KeymapWrapper* keymapWrapper = GetInstance();
   1.602 +
   1.603 +    aInputEvent.modifiers = 0;
   1.604 +    // DOM Meta key should be TRUE only on Mac.  We need to discuss this
   1.605 +    // issue later.
   1.606 +    if (keymapWrapper->AreModifiersActive(SHIFT, aModifierState)) {
   1.607 +        aInputEvent.modifiers |= MODIFIER_SHIFT;
   1.608 +    }
   1.609 +    if (keymapWrapper->AreModifiersActive(CTRL, aModifierState)) {
   1.610 +        aInputEvent.modifiers |= MODIFIER_CONTROL;
   1.611 +    }
   1.612 +    if (keymapWrapper->AreModifiersActive(ALT, aModifierState)) {
   1.613 +        aInputEvent.modifiers |= MODIFIER_ALT;
   1.614 +    }
   1.615 +    if (keymapWrapper->AreModifiersActive(META, aModifierState)) {
   1.616 +        aInputEvent.modifiers |= MODIFIER_META;
   1.617 +    }
   1.618 +    if (keymapWrapper->AreModifiersActive(SUPER, aModifierState) ||
   1.619 +        keymapWrapper->AreModifiersActive(HYPER, aModifierState)) {
   1.620 +        aInputEvent.modifiers |= MODIFIER_OS;
   1.621 +    }
   1.622 +    if (keymapWrapper->AreModifiersActive(LEVEL3, aModifierState) ||
   1.623 +        keymapWrapper->AreModifiersActive(LEVEL5, aModifierState)) {
   1.624 +        aInputEvent.modifiers |= MODIFIER_ALTGRAPH;
   1.625 +    }
   1.626 +    if (keymapWrapper->AreModifiersActive(CAPS_LOCK, aModifierState)) {
   1.627 +        aInputEvent.modifiers |= MODIFIER_CAPSLOCK;
   1.628 +    }
   1.629 +    if (keymapWrapper->AreModifiersActive(NUM_LOCK, aModifierState)) {
   1.630 +        aInputEvent.modifiers |= MODIFIER_NUMLOCK;
   1.631 +    }
   1.632 +    if (keymapWrapper->AreModifiersActive(SCROLL_LOCK, aModifierState)) {
   1.633 +        aInputEvent.modifiers |= MODIFIER_SCROLLLOCK;
   1.634 +    }
   1.635 +
   1.636 +    PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG,
   1.637 +        ("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X, "
   1.638 +         "aInputEvent.modifiers=0x%04X (Shift: %s, Control: %s, Alt: %s, "
   1.639 +         "Meta: %s, OS: %s, AltGr: %s, "
   1.640 +         "CapsLock: %s, NumLock: %s, ScrollLock: %s)",
   1.641 +         keymapWrapper, aModifierState, aInputEvent.modifiers,
   1.642 +         GetBoolName(aInputEvent.modifiers & MODIFIER_SHIFT),
   1.643 +         GetBoolName(aInputEvent.modifiers & MODIFIER_CONTROL),
   1.644 +         GetBoolName(aInputEvent.modifiers & MODIFIER_ALT),
   1.645 +         GetBoolName(aInputEvent.modifiers & MODIFIER_META),
   1.646 +         GetBoolName(aInputEvent.modifiers & MODIFIER_OS),
   1.647 +         GetBoolName(aInputEvent.modifiers & MODIFIER_ALTGRAPH),
   1.648 +         GetBoolName(aInputEvent.modifiers & MODIFIER_CAPSLOCK),
   1.649 +         GetBoolName(aInputEvent.modifiers & MODIFIER_NUMLOCK),
   1.650 +         GetBoolName(aInputEvent.modifiers & MODIFIER_SCROLLLOCK)));
   1.651 +
   1.652 +    switch(aInputEvent.eventStructType) {
   1.653 +        case NS_MOUSE_EVENT:
   1.654 +        case NS_MOUSE_SCROLL_EVENT:
   1.655 +        case NS_WHEEL_EVENT:
   1.656 +        case NS_DRAG_EVENT:
   1.657 +        case NS_SIMPLE_GESTURE_EVENT:
   1.658 +            break;
   1.659 +        default:
   1.660 +            return;
   1.661 +    }
   1.662 +
   1.663 +    WidgetMouseEventBase& mouseEvent = *aInputEvent.AsMouseEventBase();
   1.664 +    mouseEvent.buttons = 0;
   1.665 +    if (aModifierState & GDK_BUTTON1_MASK) {
   1.666 +        mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag;
   1.667 +    }
   1.668 +    if (aModifierState & GDK_BUTTON3_MASK) {
   1.669 +        mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag;
   1.670 +    }
   1.671 +    if (aModifierState & GDK_BUTTON2_MASK) {
   1.672 +        mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag;
   1.673 +    }
   1.674 +
   1.675 +    PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG,
   1.676 +        ("KeymapWrapper(%p): InitInputEvent, aInputEvent has buttons, "
   1.677 +         "aInputEvent.buttons=0x%04X (Left: %s, Right: %s, Middle: %s, "
   1.678 +         "4th (BACK): %s, 5th (FORWARD): %s)",
   1.679 +         keymapWrapper, mouseEvent.buttons,
   1.680 +         GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eLeftButtonFlag),
   1.681 +         GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eRightButtonFlag),
   1.682 +         GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eMiddleButtonFlag),
   1.683 +         GetBoolName(mouseEvent.buttons & WidgetMouseEvent::e4thButtonFlag),
   1.684 +         GetBoolName(mouseEvent.buttons & WidgetMouseEvent::e5thButtonFlag)));
   1.685 +}
   1.686 +
   1.687 +/* static */ uint32_t
   1.688 +KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
   1.689 +{
   1.690 +    // If the keyval indicates it's a modifier key, we should use unshifted
   1.691 +    // key's modifier keyval.
   1.692 +    guint keyval = aGdkKeyEvent->keyval;
   1.693 +    if (GetModifierForGDKKeyval(keyval)) {
   1.694 +        // But if the keyval without modifiers isn't a modifier key, we
   1.695 +        // shouldn't use it.  E.g., Japanese keyboard layout's
   1.696 +        // Shift + Eisu-Toggle key is CapsLock.  This is an actual rare case,
   1.697 +        // Windows uses different keycode for a physical key for different
   1.698 +        // shift key state.
   1.699 +        guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent);
   1.700 +        if (GetModifierForGDKKeyval(keyvalWithoutModifier)) {
   1.701 +            keyval = keyvalWithoutModifier;
   1.702 +        }
   1.703 +        // Note that the modifier keycode and activating or deactivating
   1.704 +        // modifier flag may be mismatched, but it's okay.  If a DOM key
   1.705 +        // event handler is testing a keydown event, it's more likely being
   1.706 +        // used to test which key is being pressed than to test which
   1.707 +        // modifier will become active.  So, if we computed DOM keycode
   1.708 +        // from modifier flag which were changing by the physical key, then
   1.709 +        // there would be no other way for the user to generate the original
   1.710 +        // keycode.
   1.711 +        uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval);
   1.712 +        NS_ASSERTION(DOMKeyCode, "All modifier keys must have a DOM keycode");
   1.713 +        return DOMKeyCode;
   1.714 +    }
   1.715 +
   1.716 +    // If the key isn't printable, let's look at the key pairs.
   1.717 +    uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
   1.718 +    if (!charCode) {
   1.719 +        // Always use unshifted keycode for the non-printable key.
   1.720 +        // XXX It might be better to decide DOM keycode from all keyvals of
   1.721 +        //     the hardware keycode.  However, I think that it's too excessive.
   1.722 +        guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent);
   1.723 +        uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyvalWithoutModifier);
   1.724 +        if (!DOMKeyCode) {
   1.725 +            // If the unshifted keyval couldn't be mapped to a DOM keycode,
   1.726 +            // we should fallback to legacy logic, so, we should recompute with
   1.727 +            // the keyval with aGdkKeyEvent.
   1.728 +            DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval);
   1.729 +        }
   1.730 +        return DOMKeyCode;
   1.731 +    }
   1.732 +
   1.733 +    // printable numpad keys should be resolved here.
   1.734 +    switch (keyval) {
   1.735 +        case GDK_KP_Multiply:  return NS_VK_MULTIPLY;
   1.736 +        case GDK_KP_Add:       return NS_VK_ADD;
   1.737 +        case GDK_KP_Separator: return NS_VK_SEPARATOR;
   1.738 +        case GDK_KP_Subtract:  return NS_VK_SUBTRACT;
   1.739 +        case GDK_KP_Decimal:   return NS_VK_DECIMAL;
   1.740 +        case GDK_KP_Divide:    return NS_VK_DIVIDE;
   1.741 +        case GDK_KP_0:         return NS_VK_NUMPAD0;
   1.742 +        case GDK_KP_1:         return NS_VK_NUMPAD1;
   1.743 +        case GDK_KP_2:         return NS_VK_NUMPAD2;
   1.744 +        case GDK_KP_3:         return NS_VK_NUMPAD3;
   1.745 +        case GDK_KP_4:         return NS_VK_NUMPAD4;
   1.746 +        case GDK_KP_5:         return NS_VK_NUMPAD5;
   1.747 +        case GDK_KP_6:         return NS_VK_NUMPAD6;
   1.748 +        case GDK_KP_7:         return NS_VK_NUMPAD7;
   1.749 +        case GDK_KP_8:         return NS_VK_NUMPAD8;
   1.750 +        case GDK_KP_9:         return NS_VK_NUMPAD9;
   1.751 +    }
   1.752 +
   1.753 +    KeymapWrapper* keymapWrapper = GetInstance();
   1.754 +
   1.755 +    // Ignore all modifier state except NumLock.
   1.756 +    guint baseState =
   1.757 +        (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK));
   1.758 +
   1.759 +    // Basically, we should use unmodified character for deciding our keyCode.
   1.760 +    uint32_t unmodifiedChar =
   1.761 +        keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState,
   1.762 +                                      aGdkKeyEvent->group);
   1.763 +    if (IsBasicLatinLetterOrNumeral(unmodifiedChar)) {
   1.764 +        // If the unmodified character is an ASCII alphabet or an ASCII
   1.765 +        // numeric, it's the best hint for deciding our keyCode.
   1.766 +        return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar);
   1.767 +    }
   1.768 +
   1.769 +    // If the unmodified character is not an ASCII character, that means we
   1.770 +    // couldn't find the hint. We should reset it.
   1.771 +    if (unmodifiedChar > 0x7F) {
   1.772 +        unmodifiedChar = 0;
   1.773 +    }
   1.774 +
   1.775 +    // Retry with shifted keycode.
   1.776 +    guint shiftState = (baseState | keymapWrapper->GetModifierMask(SHIFT));
   1.777 +    uint32_t shiftedChar =
   1.778 +        keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState,
   1.779 +                                      aGdkKeyEvent->group);
   1.780 +    if (IsBasicLatinLetterOrNumeral(shiftedChar)) {
   1.781 +        // A shifted character can be an ASCII alphabet on Hebrew keyboard
   1.782 +        // layout. And also shifted character can be an ASCII numeric on
   1.783 +        // AZERTY keyboad layout.  Then, it's a good hint for deciding our
   1.784 +        // keyCode.
   1.785 +        return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar);
   1.786 +    }
   1.787 +
   1.788 +    // If the shifted unmodified character isn't an ASCII character, we should
   1.789 +    // discard it too.
   1.790 +    if (shiftedChar > 0x7F) {
   1.791 +        shiftedChar = 0;
   1.792 +    }
   1.793 +
   1.794 +    // If current keyboard layout isn't ASCII alphabet inputtable layout,
   1.795 +    // look for ASCII alphabet inputtable keyboard layout.  If the key
   1.796 +    // inputs an ASCII alphabet or an ASCII numeric, we should use it
   1.797 +    // for deciding our keyCode.
   1.798 +    // Note that it's important not to use alternative keyboard layout for ASCII
   1.799 +    // alphabet inputabble keyboard layout because the keycode for the key with
   1.800 +    // alternative keyboard layout may conflict with another key on current
   1.801 +    // keyboard layout.
   1.802 +    if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) {
   1.803 +        gint minGroup = keymapWrapper->GetFirstLatinGroup();
   1.804 +        if (minGroup >= 0) {
   1.805 +            uint32_t unmodCharLatin =
   1.806 +                keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState,
   1.807 +                                              minGroup);
   1.808 +            if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) {
   1.809 +                // If the unmodified character is an ASCII alphabet or
   1.810 +                // an ASCII numeric, we should use it for the keyCode.
   1.811 +                return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin);
   1.812 +            }
   1.813 +            uint32_t shiftedCharLatin =
   1.814 +                keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState,
   1.815 +                                              minGroup);
   1.816 +            if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) {
   1.817 +                // If the shifted character is an ASCII alphabet or an ASCII
   1.818 +                // numeric, we should use it for the keyCode.
   1.819 +                return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin);
   1.820 +            }
   1.821 +        }
   1.822 +    }
   1.823 +
   1.824 +    // If unmodified character is in ASCII range, use it.  Otherwise, use
   1.825 +    // shifted character.
   1.826 +    if (!unmodifiedChar && !shiftedChar) {
   1.827 +        return 0;
   1.828 +    }
   1.829 +    return WidgetUtils::ComputeKeyCodeFromChar(
   1.830 +                unmodifiedChar ? unmodifiedChar : shiftedChar);
   1.831 +}
   1.832 +
   1.833 +KeyNameIndex
   1.834 +KeymapWrapper::ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent)
   1.835 +{
   1.836 +    switch (aGdkKeyEvent->keyval) {
   1.837 +
   1.838 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
   1.839 +        case aNativeKey: return aKeyNameIndex;
   1.840 +
   1.841 +#include "NativeKeyToDOMKeyName.h"
   1.842 +
   1.843 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
   1.844 +
   1.845 +        default:
   1.846 +            break;
   1.847 +    }
   1.848 +
   1.849 +    return KEY_NAME_INDEX_Unidentified;
   1.850 +}
   1.851 +
   1.852 +/* static */ void
   1.853 +KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
   1.854 +                            GdkEventKey* aGdkKeyEvent)
   1.855 +{
   1.856 +    KeymapWrapper* keymapWrapper = GetInstance();
   1.857 +
   1.858 +    aKeyEvent.mKeyNameIndex =
   1.859 +        keymapWrapper->ComputeDOMKeyNameIndex(aGdkKeyEvent);
   1.860 +    if (aKeyEvent.mKeyNameIndex == KEY_NAME_INDEX_Unidentified) {
   1.861 +        uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
   1.862 +        if (!charCode) {
   1.863 +            charCode = keymapWrapper->GetUnmodifiedCharCodeFor(aGdkKeyEvent);
   1.864 +        }
   1.865 +        if (charCode) {
   1.866 +            aKeyEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
   1.867 +            MOZ_ASSERT(aKeyEvent.mKeyValue.IsEmpty(),
   1.868 +                       "Uninitialized mKeyValue must be empty");
   1.869 +            AppendUCS4ToUTF16(charCode, aKeyEvent.mKeyValue);
   1.870 +        }
   1.871 +    }
   1.872 +    aKeyEvent.keyCode = ComputeDOMKeyCode(aGdkKeyEvent);
   1.873 +
   1.874 +    // NOTE: The state of given key event indicates adjacent state of
   1.875 +    // modifier keys.  E.g., even if the event is Shift key press event,
   1.876 +    // the bit for Shift is still false.  By the same token, even if the
   1.877 +    // event is Shift key release event, the bit for Shift is still true.
   1.878 +    // Unfortunately, gdk_keyboard_get_modifiers() returns current modifier
   1.879 +    // state.  It means if there're some pending modifier key press or
   1.880 +    // key release events, the result isn't what we want.
   1.881 +    guint modifierState = aGdkKeyEvent->state;
   1.882 +    if (aGdkKeyEvent->is_modifier) {
   1.883 +        Display* display =
   1.884 +            gdk_x11_display_get_xdisplay(gdk_display_get_default());
   1.885 +        if (XEventsQueued(display, QueuedAfterReading)) {
   1.886 +            XEvent nextEvent;
   1.887 +            XPeekEvent(display, &nextEvent);
   1.888 +            if (nextEvent.type == keymapWrapper->mXKBBaseEventCode) {
   1.889 +                XkbEvent* XKBEvent = (XkbEvent*)&nextEvent;
   1.890 +                if (XKBEvent->any.xkb_type == XkbStateNotify) {
   1.891 +                    XkbStateNotifyEvent* stateNotifyEvent =
   1.892 +                        (XkbStateNotifyEvent*)XKBEvent;
   1.893 +                    modifierState &= ~0xFF;
   1.894 +                    modifierState |= stateNotifyEvent->lookup_mods;
   1.895 +                }
   1.896 +            }
   1.897 +        }
   1.898 +    }
   1.899 +    InitInputEvent(aKeyEvent, modifierState);
   1.900 +
   1.901 +    switch (aGdkKeyEvent->keyval) {
   1.902 +        case GDK_Shift_L:
   1.903 +        case GDK_Control_L:
   1.904 +        case GDK_Alt_L:
   1.905 +        case GDK_Super_L:
   1.906 +        case GDK_Hyper_L:
   1.907 +        case GDK_Meta_L:
   1.908 +            aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT;
   1.909 +            break;
   1.910 +
   1.911 +        case GDK_Shift_R:
   1.912 +        case GDK_Control_R:
   1.913 +        case GDK_Alt_R:
   1.914 +        case GDK_Super_R:
   1.915 +        case GDK_Hyper_R:
   1.916 +        case GDK_Meta_R:
   1.917 +            aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT;
   1.918 +            break;
   1.919 +
   1.920 +        case GDK_KP_0:
   1.921 +        case GDK_KP_1:
   1.922 +        case GDK_KP_2:
   1.923 +        case GDK_KP_3:
   1.924 +        case GDK_KP_4:
   1.925 +        case GDK_KP_5:
   1.926 +        case GDK_KP_6:
   1.927 +        case GDK_KP_7:
   1.928 +        case GDK_KP_8:
   1.929 +        case GDK_KP_9:
   1.930 +        case GDK_KP_Space:
   1.931 +        case GDK_KP_Tab:
   1.932 +        case GDK_KP_Enter:
   1.933 +        case GDK_KP_F1:
   1.934 +        case GDK_KP_F2:
   1.935 +        case GDK_KP_F3:
   1.936 +        case GDK_KP_F4:
   1.937 +        case GDK_KP_Home:
   1.938 +        case GDK_KP_Left:
   1.939 +        case GDK_KP_Up:
   1.940 +        case GDK_KP_Right:
   1.941 +        case GDK_KP_Down:
   1.942 +        case GDK_KP_Prior: // same as GDK_KP_Page_Up
   1.943 +        case GDK_KP_Next:  // same as GDK_KP_Page_Down
   1.944 +        case GDK_KP_End:
   1.945 +        case GDK_KP_Begin:
   1.946 +        case GDK_KP_Insert:
   1.947 +        case GDK_KP_Delete:
   1.948 +        case GDK_KP_Equal:
   1.949 +        case GDK_KP_Multiply:
   1.950 +        case GDK_KP_Add:
   1.951 +        case GDK_KP_Separator:
   1.952 +        case GDK_KP_Subtract:
   1.953 +        case GDK_KP_Decimal:
   1.954 +        case GDK_KP_Divide:
   1.955 +            aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
   1.956 +            break;
   1.957 +
   1.958 +        default:
   1.959 +            aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
   1.960 +            break;
   1.961 +    }
   1.962 +
   1.963 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
   1.964 +        ("KeymapWrapper(%p): InitKeyEvent, modifierState=0x%08X "
   1.965 +         "aGdkKeyEvent={ type=%s, keyval=%s(0x%X), state=0x%08X, "
   1.966 +         "hardware_keycode=0x%08X, is_modifier=%s } "
   1.967 +         "aKeyEvent={ message=%s, isShift=%s, isControl=%s, "
   1.968 +         "isAlt=%s, isMeta=%s }",
   1.969 +         keymapWrapper, modifierState,
   1.970 +         ((aGdkKeyEvent->type == GDK_KEY_PRESS) ?
   1.971 +               "GDK_KEY_PRESS" : "GDK_KEY_RELEASE"),
   1.972 +         gdk_keyval_name(aGdkKeyEvent->keyval),
   1.973 +         aGdkKeyEvent->keyval, aGdkKeyEvent->state,
   1.974 +         aGdkKeyEvent->hardware_keycode,
   1.975 +         GetBoolName(aGdkKeyEvent->is_modifier),
   1.976 +         ((aKeyEvent.message == NS_KEY_DOWN) ? "NS_KEY_DOWN" :
   1.977 +               (aKeyEvent.message == NS_KEY_PRESS) ? "NS_KEY_PRESS" :
   1.978 +                                                      "NS_KEY_UP"),
   1.979 +         GetBoolName(aKeyEvent.IsShift()), GetBoolName(aKeyEvent.IsControl()),
   1.980 +         GetBoolName(aKeyEvent.IsAlt()), GetBoolName(aKeyEvent.IsMeta())));
   1.981 +
   1.982 +    if (aKeyEvent.message == NS_KEY_PRESS) {
   1.983 +        keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent);
   1.984 +    }
   1.985 +
   1.986 +    // The transformations above and in gdk for the keyval are not invertible
   1.987 +    // so link to the GdkEvent (which will vanish soon after return from the
   1.988 +    // event callback) to give plugins access to hardware_keycode and state.
   1.989 +    // (An XEvent would be nice but the GdkEvent is good enough.)
   1.990 +    aKeyEvent.pluginEvent = (void *)aGdkKeyEvent;
   1.991 +    aKeyEvent.time = aGdkKeyEvent->time;
   1.992 +    aKeyEvent.mNativeKeyEvent = static_cast<void*>(aGdkKeyEvent);
   1.993 +    aKeyEvent.mIsRepeat = sRepeatState == REPEATING &&
   1.994 +        aGdkKeyEvent->hardware_keycode == sLastRepeatableHardwareKeyCode;
   1.995 +}
   1.996 +
   1.997 +/* static */ uint32_t
   1.998 +KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent)
   1.999 +{
  1.1000 +    // Anything above 0xf000 is considered a non-printable
  1.1001 +    // Exception: directly encoded UCS characters
  1.1002 +    if (aGdkKeyEvent->keyval > 0xf000 &&
  1.1003 +        (aGdkKeyEvent->keyval & 0xff000000) != 0x01000000) {
  1.1004 +        // Keypad keys are an exception: they return a value different
  1.1005 +        // from their non-keypad equivalents, but mozilla doesn't distinguish.
  1.1006 +        switch (aGdkKeyEvent->keyval) {
  1.1007 +            case GDK_KP_Space:              return ' ';
  1.1008 +            case GDK_KP_Equal:              return '=';
  1.1009 +            case GDK_KP_Multiply:           return '*';
  1.1010 +            case GDK_KP_Add:                return '+';
  1.1011 +            case GDK_KP_Separator:          return ',';
  1.1012 +            case GDK_KP_Subtract:           return '-';
  1.1013 +            case GDK_KP_Decimal:            return '.';
  1.1014 +            case GDK_KP_Divide:             return '/';
  1.1015 +            case GDK_KP_0:                  return '0';
  1.1016 +            case GDK_KP_1:                  return '1';
  1.1017 +            case GDK_KP_2:                  return '2';
  1.1018 +            case GDK_KP_3:                  return '3';
  1.1019 +            case GDK_KP_4:                  return '4';
  1.1020 +            case GDK_KP_5:                  return '5';
  1.1021 +            case GDK_KP_6:                  return '6';
  1.1022 +            case GDK_KP_7:                  return '7';
  1.1023 +            case GDK_KP_8:                  return '8';
  1.1024 +            case GDK_KP_9:                  return '9';
  1.1025 +            default:                        return 0; // non-printables
  1.1026 +        }
  1.1027 +    }
  1.1028 +
  1.1029 +    static const long MAX_UNICODE = 0x10FFFF;
  1.1030 +
  1.1031 +    // we're supposedly printable, let's try to convert
  1.1032 +    long ucs = keysym2ucs(aGdkKeyEvent->keyval);
  1.1033 +    if ((ucs != -1) && (ucs < MAX_UNICODE)) {
  1.1034 +         return ucs;
  1.1035 +    }
  1.1036 +
  1.1037 +    // I guess we couldn't convert
  1.1038 +    return 0;
  1.1039 +}
  1.1040 +
  1.1041 +uint32_t
  1.1042 +KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent,
  1.1043 +                              guint aModifierState,
  1.1044 +                              gint aGroup)
  1.1045 +{
  1.1046 +    guint keyval;
  1.1047 +    if (!gdk_keymap_translate_keyboard_state(mGdkKeymap,
  1.1048 +             aGdkKeyEvent->hardware_keycode,
  1.1049 +             GdkModifierType(aModifierState),
  1.1050 +             aGroup, &keyval, nullptr, nullptr, nullptr)) {
  1.1051 +        return 0;
  1.1052 +    }
  1.1053 +    GdkEventKey tmpEvent = *aGdkKeyEvent;
  1.1054 +    tmpEvent.state = aModifierState;
  1.1055 +    tmpEvent.keyval = keyval;
  1.1056 +    tmpEvent.group = aGroup;
  1.1057 +    return GetCharCodeFor(&tmpEvent);
  1.1058 +}
  1.1059 +
  1.1060 +uint32_t
  1.1061 +KeymapWrapper::GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent)
  1.1062 +{
  1.1063 +    guint state = aGdkKeyEvent->state &
  1.1064 +        (GetModifierMask(SHIFT) | GetModifierMask(CAPS_LOCK) |
  1.1065 +         GetModifierMask(NUM_LOCK) | GetModifierMask(SCROLL_LOCK) |
  1.1066 +         GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5));
  1.1067 +    uint32_t charCode = GetCharCodeFor(aGdkKeyEvent, GdkModifierType(state),
  1.1068 +                                       aGdkKeyEvent->group);
  1.1069 +    if (charCode) {
  1.1070 +        return charCode;
  1.1071 +    }
  1.1072 +    // If no character is mapped to the key when Level3 Shift or Level5 Shift
  1.1073 +    // is active, let's return a character which is inputted by the key without
  1.1074 +    // Level3 nor Level5 Shift.
  1.1075 +    guint stateWithoutAltGraph =
  1.1076 +        state & ~(GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5));
  1.1077 +    if (state == stateWithoutAltGraph) {
  1.1078 +        return 0;
  1.1079 +    }
  1.1080 +    return GetCharCodeFor(aGdkKeyEvent, GdkModifierType(stateWithoutAltGraph),
  1.1081 +                          aGdkKeyEvent->group);
  1.1082 +}
  1.1083 +
  1.1084 +gint
  1.1085 +KeymapWrapper::GetKeyLevel(GdkEventKey *aGdkKeyEvent)
  1.1086 +{
  1.1087 +    gint level;
  1.1088 +    if (!gdk_keymap_translate_keyboard_state(mGdkKeymap,
  1.1089 +             aGdkKeyEvent->hardware_keycode,
  1.1090 +             GdkModifierType(aGdkKeyEvent->state),
  1.1091 +             aGdkKeyEvent->group, nullptr, nullptr, &level, nullptr)) {
  1.1092 +        return -1;
  1.1093 +    }
  1.1094 +    return level;
  1.1095 +}
  1.1096 +
  1.1097 +gint
  1.1098 +KeymapWrapper::GetFirstLatinGroup()
  1.1099 +{
  1.1100 +    GdkKeymapKey *keys;
  1.1101 +    gint count;
  1.1102 +    gint minGroup = -1;
  1.1103 +    if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) {
  1.1104 +        // find the minimum number group for latin inputtable layout
  1.1105 +        for (gint i = 0; i < count && minGroup != 0; ++i) {
  1.1106 +            if (keys[i].level != 0 && keys[i].level != 1) {
  1.1107 +                continue;
  1.1108 +            }
  1.1109 +            if (minGroup >= 0 && keys[i].group > minGroup) {
  1.1110 +                continue;
  1.1111 +            }
  1.1112 +            minGroup = keys[i].group;
  1.1113 +        }
  1.1114 +        g_free(keys);
  1.1115 +    }
  1.1116 +    return minGroup;
  1.1117 +}
  1.1118 +
  1.1119 +bool
  1.1120 +KeymapWrapper::IsLatinGroup(guint8 aGroup)
  1.1121 +{
  1.1122 +    GdkKeymapKey *keys;
  1.1123 +    gint count;
  1.1124 +    bool result = false;
  1.1125 +    if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) {
  1.1126 +        for (gint i = 0; i < count; ++i) {
  1.1127 +            if (keys[i].level != 0 && keys[i].level != 1) {
  1.1128 +                continue;
  1.1129 +            }
  1.1130 +            if (keys[i].group == aGroup) {
  1.1131 +                result = true;
  1.1132 +                break;
  1.1133 +            }
  1.1134 +        }
  1.1135 +        g_free(keys);
  1.1136 +    }
  1.1137 +    return result;
  1.1138 +}
  1.1139 +
  1.1140 +bool
  1.1141 +KeymapWrapper::IsAutoRepeatableKey(guint aHardwareKeyCode)
  1.1142 +{
  1.1143 +    uint8_t indexOfArray = aHardwareKeyCode / 8;
  1.1144 +    MOZ_ASSERT(indexOfArray < ArrayLength(mKeyboardState.auto_repeats),
  1.1145 +               "invalid index");
  1.1146 +    char bitMask = 1 << (aHardwareKeyCode % 8);
  1.1147 +    return (mKeyboardState.auto_repeats[indexOfArray] & bitMask) != 0;
  1.1148 +}
  1.1149 +
  1.1150 +/* static */ bool
  1.1151 +KeymapWrapper::IsBasicLatinLetterOrNumeral(uint32_t aCharCode)
  1.1152 +{
  1.1153 +    return (aCharCode >= 'a' && aCharCode <= 'z') ||
  1.1154 +           (aCharCode >= 'A' && aCharCode <= 'Z') ||
  1.1155 +           (aCharCode >= '0' && aCharCode <= '9');
  1.1156 +}
  1.1157 +
  1.1158 +/* static */ guint
  1.1159 +KeymapWrapper::GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent)
  1.1160 +{
  1.1161 +    KeymapWrapper* keymapWrapper = GetInstance();
  1.1162 +    guint state =
  1.1163 +        (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK));
  1.1164 +    guint keyval;
  1.1165 +    if (!gdk_keymap_translate_keyboard_state(keymapWrapper->mGdkKeymap,
  1.1166 +             aGdkKeyEvent->hardware_keycode, GdkModifierType(state),
  1.1167 +             aGdkKeyEvent->group, &keyval, nullptr, nullptr, nullptr)) {
  1.1168 +        return 0;
  1.1169 +    }
  1.1170 +    return keyval;
  1.1171 +}
  1.1172 +
  1.1173 +/* static */ uint32_t
  1.1174 +KeymapWrapper::GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval)
  1.1175 +{
  1.1176 +    switch (aGdkKeyval) {
  1.1177 +        case GDK_Cancel:                return NS_VK_CANCEL;
  1.1178 +        case GDK_BackSpace:             return NS_VK_BACK;
  1.1179 +        case GDK_Tab:
  1.1180 +        case GDK_ISO_Left_Tab:          return NS_VK_TAB;
  1.1181 +        case GDK_Clear:                 return NS_VK_CLEAR;
  1.1182 +        case GDK_Return:                return NS_VK_RETURN;
  1.1183 +        case GDK_Shift_L:
  1.1184 +        case GDK_Shift_R:
  1.1185 +        case GDK_Shift_Lock:            return NS_VK_SHIFT;
  1.1186 +        case GDK_Control_L:
  1.1187 +        case GDK_Control_R:             return NS_VK_CONTROL;
  1.1188 +        case GDK_Alt_L:
  1.1189 +        case GDK_Alt_R:                 return NS_VK_ALT;
  1.1190 +        case GDK_Meta_L:
  1.1191 +        case GDK_Meta_R:                return NS_VK_META;
  1.1192 +
  1.1193 +        // Assume that Super or Hyper is always mapped to physical Win key.
  1.1194 +        case GDK_Super_L:
  1.1195 +        case GDK_Super_R:
  1.1196 +        case GDK_Hyper_L:
  1.1197 +        case GDK_Hyper_R:               return NS_VK_WIN;
  1.1198 +
  1.1199 +        // GTK's AltGraph key is similar to Mac's Option (Alt) key.  However,
  1.1200 +        // unfortunately, browsers on Mac are using NS_VK_ALT for it even though
  1.1201 +        // it's really different from Alt key on Windows.
  1.1202 +        // On the other hand, GTK's AltGrapsh keys are really different from
  1.1203 +        // Alt key.  However, there is no AltGrapsh key on Windows.  On Windows,
  1.1204 +        // both Ctrl and Alt keys are pressed internally when AltGr key is
  1.1205 +        // pressed.  For some languages' users, AltGraph key is important, so,
  1.1206 +        // web applications on such locale may want to know AltGraph key press.
  1.1207 +        // Therefore, we should map AltGr keycode for them only on GTK.
  1.1208 +        case GDK_ISO_Level3_Shift:
  1.1209 +        case GDK_ISO_Level5_Shift:
  1.1210 +        // We assume that Mode_switch is always used for level3 shift.
  1.1211 +        case GDK_Mode_switch:           return NS_VK_ALTGR;
  1.1212 +
  1.1213 +        case GDK_Pause:                 return NS_VK_PAUSE;
  1.1214 +        case GDK_Caps_Lock:             return NS_VK_CAPS_LOCK;
  1.1215 +        case GDK_Kana_Lock:
  1.1216 +        case GDK_Kana_Shift:            return NS_VK_KANA;
  1.1217 +        case GDK_Hangul:                return NS_VK_HANGUL;
  1.1218 +        // case GDK_XXX:                   return NS_VK_JUNJA;
  1.1219 +        // case GDK_XXX:                   return NS_VK_FINAL;
  1.1220 +        case GDK_Hangul_Hanja:          return NS_VK_HANJA;
  1.1221 +        case GDK_Kanji:                 return NS_VK_KANJI;
  1.1222 +        case GDK_Escape:                return NS_VK_ESCAPE;
  1.1223 +        case GDK_Henkan:                return NS_VK_CONVERT;
  1.1224 +        case GDK_Muhenkan:              return NS_VK_NONCONVERT;
  1.1225 +        // case GDK_XXX:                   return NS_VK_ACCEPT;
  1.1226 +        // case GDK_XXX:                   return NS_VK_MODECHANGE;
  1.1227 +        case GDK_Page_Up:               return NS_VK_PAGE_UP;
  1.1228 +        case GDK_Page_Down:             return NS_VK_PAGE_DOWN;
  1.1229 +        case GDK_End:                   return NS_VK_END;
  1.1230 +        case GDK_Home:                  return NS_VK_HOME;
  1.1231 +        case GDK_Left:                  return NS_VK_LEFT;
  1.1232 +        case GDK_Up:                    return NS_VK_UP;
  1.1233 +        case GDK_Right:                 return NS_VK_RIGHT;
  1.1234 +        case GDK_Down:                  return NS_VK_DOWN;
  1.1235 +        case GDK_Select:                return NS_VK_SELECT;
  1.1236 +        case GDK_Print:                 return NS_VK_PRINT;
  1.1237 +        case GDK_Execute:               return NS_VK_EXECUTE;
  1.1238 +        case GDK_Insert:                return NS_VK_INSERT;
  1.1239 +        case GDK_Delete:                return NS_VK_DELETE;
  1.1240 +        case GDK_Help:                  return NS_VK_HELP;
  1.1241 +
  1.1242 +        // keypad keys
  1.1243 +        case GDK_KP_Left:               return NS_VK_LEFT;
  1.1244 +        case GDK_KP_Right:              return NS_VK_RIGHT;
  1.1245 +        case GDK_KP_Up:                 return NS_VK_UP;
  1.1246 +        case GDK_KP_Down:               return NS_VK_DOWN;
  1.1247 +        case GDK_KP_Page_Up:            return NS_VK_PAGE_UP;
  1.1248 +        // Not sure what these are
  1.1249 +        // case GDK_KP_Prior:              return NS_VK_;
  1.1250 +        // case GDK_KP_Next:               return NS_VK_;
  1.1251 +        case GDK_KP_Begin:              return NS_VK_CLEAR; // Num-unlocked 5
  1.1252 +        case GDK_KP_Page_Down:          return NS_VK_PAGE_DOWN;
  1.1253 +        case GDK_KP_Home:               return NS_VK_HOME;
  1.1254 +        case GDK_KP_End:                return NS_VK_END;
  1.1255 +        case GDK_KP_Insert:             return NS_VK_INSERT;
  1.1256 +        case GDK_KP_Delete:             return NS_VK_DELETE;
  1.1257 +        case GDK_KP_Enter:              return NS_VK_RETURN;
  1.1258 +
  1.1259 +        case GDK_Num_Lock:              return NS_VK_NUM_LOCK;
  1.1260 +        case GDK_Scroll_Lock:           return NS_VK_SCROLL_LOCK;
  1.1261 +
  1.1262 +        // Function keys
  1.1263 +        case GDK_F1:                    return NS_VK_F1;
  1.1264 +        case GDK_F2:                    return NS_VK_F2;
  1.1265 +        case GDK_F3:                    return NS_VK_F3;
  1.1266 +        case GDK_F4:                    return NS_VK_F4;
  1.1267 +        case GDK_F5:                    return NS_VK_F5;
  1.1268 +        case GDK_F6:                    return NS_VK_F6;
  1.1269 +        case GDK_F7:                    return NS_VK_F7;
  1.1270 +        case GDK_F8:                    return NS_VK_F8;
  1.1271 +        case GDK_F9:                    return NS_VK_F9;
  1.1272 +        case GDK_F10:                   return NS_VK_F10;
  1.1273 +        case GDK_F11:                   return NS_VK_F11;
  1.1274 +        case GDK_F12:                   return NS_VK_F12;
  1.1275 +        case GDK_F13:                   return NS_VK_F13;
  1.1276 +        case GDK_F14:                   return NS_VK_F14;
  1.1277 +        case GDK_F15:                   return NS_VK_F15;
  1.1278 +        case GDK_F16:                   return NS_VK_F16;
  1.1279 +        case GDK_F17:                   return NS_VK_F17;
  1.1280 +        case GDK_F18:                   return NS_VK_F18;
  1.1281 +        case GDK_F19:                   return NS_VK_F19;
  1.1282 +        case GDK_F20:                   return NS_VK_F20;
  1.1283 +        case GDK_F21:                   return NS_VK_F21;
  1.1284 +        case GDK_F22:                   return NS_VK_F22;
  1.1285 +        case GDK_F23:                   return NS_VK_F23;
  1.1286 +        case GDK_F24:                   return NS_VK_F24;
  1.1287 +
  1.1288 +        // context menu key, keysym 0xff67, typically keycode 117 on 105-key
  1.1289 +        // (Microsoft) x86 keyboards, located between right 'Windows' key and
  1.1290 +        // right Ctrl key
  1.1291 +        case GDK_Menu:                  return NS_VK_CONTEXT_MENU;
  1.1292 +        case GDK_Sleep:                 return NS_VK_SLEEP;
  1.1293 +
  1.1294 +        case GDK_3270_Attn:             return NS_VK_ATTN;
  1.1295 +        case GDK_3270_CursorSelect:     return NS_VK_CRSEL;
  1.1296 +        case GDK_3270_ExSelect:         return NS_VK_EXSEL;
  1.1297 +        case GDK_3270_EraseEOF:         return NS_VK_EREOF;
  1.1298 +        case GDK_3270_Play:             return NS_VK_PLAY;
  1.1299 +        // case GDK_XXX:                   return NS_VK_ZOOM;
  1.1300 +        case GDK_3270_PA1:              return NS_VK_PA1;
  1.1301 +
  1.1302 +        // map Sun Keyboard special keysyms on to NS_VK keys
  1.1303 +
  1.1304 +        // Sun F11 key generates SunF36(0x1005ff10) keysym
  1.1305 +        case 0x1005ff10:                return NS_VK_F11;
  1.1306 +        // Sun F12 key generates SunF37(0x1005ff11) keysym
  1.1307 +        case 0x1005ff11:                return NS_VK_F12;
  1.1308 +        default:                        return 0;
  1.1309 +    }
  1.1310 +}
  1.1311 +
  1.1312 +void
  1.1313 +KeymapWrapper::InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent,
  1.1314 +                                 GdkEventKey* aGdkKeyEvent)
  1.1315 +{
  1.1316 +    NS_ENSURE_TRUE_VOID(aKeyEvent.message == NS_KEY_PRESS);
  1.1317 +
  1.1318 +    aKeyEvent.charCode = GetCharCodeFor(aGdkKeyEvent);
  1.1319 +    if (!aKeyEvent.charCode) {
  1.1320 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
  1.1321 +            ("KeymapWrapper(%p): InitKeypressEvent, "
  1.1322 +             "keyCode=0x%02X, charCode=0x%08X",
  1.1323 +             this, aKeyEvent.keyCode, aKeyEvent.charCode));
  1.1324 +        return;
  1.1325 +    }
  1.1326 +
  1.1327 +    // If the event causes inputting a character, keyCode must be zero.
  1.1328 +    aKeyEvent.keyCode = 0;
  1.1329 +
  1.1330 +    // If Ctrl or Alt or Meta or OS is pressed, we need to append the key
  1.1331 +    // details for handling shortcut key.  Otherwise, we have no additional
  1.1332 +    // work.
  1.1333 +    if (!aKeyEvent.IsControl() && !aKeyEvent.IsAlt() &&
  1.1334 +        !aKeyEvent.IsMeta() && !aKeyEvent.IsOS()) {
  1.1335 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
  1.1336 +            ("KeymapWrapper(%p): InitKeypressEvent, "
  1.1337 +             "keyCode=0x%02X, charCode=0x%08X",
  1.1338 +             this, aKeyEvent.keyCode, aKeyEvent.charCode));
  1.1339 +        return;
  1.1340 +    }
  1.1341 +
  1.1342 +    gint level = GetKeyLevel(aGdkKeyEvent);
  1.1343 +    if (level != 0 && level != 1) {
  1.1344 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
  1.1345 +            ("KeymapWrapper(%p): InitKeypressEvent, "
  1.1346 +             "keyCode=0x%02X, charCode=0x%08X, level=%d",
  1.1347 +             this, aKeyEvent.keyCode, aKeyEvent.charCode, level));
  1.1348 +        return;
  1.1349 +    }
  1.1350 +
  1.1351 +    guint baseState = aGdkKeyEvent->state &
  1.1352 +        ~(GetModifierMask(SHIFT) | GetModifierMask(CTRL) |
  1.1353 +          GetModifierMask(ALT) | GetModifierMask(META) |
  1.1354 +          GetModifierMask(SUPER) | GetModifierMask(HYPER));
  1.1355 +
  1.1356 +    // We shold send both shifted char and unshifted char, all keyboard layout
  1.1357 +    // users can use all keys.  Don't change event.charCode. On some keyboard
  1.1358 +    // layouts, Ctrl/Alt/Meta keys are used for inputting some characters.
  1.1359 +    AlternativeCharCode altCharCodes(0, 0);
  1.1360 +    // unshifted charcode of current keyboard layout.
  1.1361 +    altCharCodes.mUnshiftedCharCode =
  1.1362 +        GetCharCodeFor(aGdkKeyEvent, baseState, aGdkKeyEvent->group);
  1.1363 +    bool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF);
  1.1364 +    // shifted charcode of current keyboard layout.
  1.1365 +    altCharCodes.mShiftedCharCode =
  1.1366 +        GetCharCodeFor(aGdkKeyEvent,
  1.1367 +                       baseState | GetModifierMask(SHIFT),
  1.1368 +                       aGdkKeyEvent->group);
  1.1369 +    isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF);
  1.1370 +    if (altCharCodes.mUnshiftedCharCode || altCharCodes.mShiftedCharCode) {
  1.1371 +        aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes);
  1.1372 +    }
  1.1373 +
  1.1374 +    bool needLatinKeyCodes = !isLatin;
  1.1375 +    if (!needLatinKeyCodes) {
  1.1376 +        needLatinKeyCodes = 
  1.1377 +            (IS_ASCII_ALPHABETICAL(altCharCodes.mUnshiftedCharCode) !=
  1.1378 +             IS_ASCII_ALPHABETICAL(altCharCodes.mShiftedCharCode));
  1.1379 +    }
  1.1380 +
  1.1381 +    // If current keyboard layout can input Latin characters, we don't need
  1.1382 +    // more information.
  1.1383 +    if (!needLatinKeyCodes) {
  1.1384 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
  1.1385 +            ("KeymapWrapper(%p): InitKeypressEvent, keyCode=0x%02X, "
  1.1386 +             "charCode=0x%08X, level=%d, altCharCodes={ "
  1.1387 +             "mUnshiftedCharCode=0x%08X, mShiftedCharCode=0x%08X }",
  1.1388 +             this, aKeyEvent.keyCode, aKeyEvent.charCode, level,
  1.1389 +             altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode));
  1.1390 +        return;
  1.1391 +    }
  1.1392 +
  1.1393 +    // Next, find Latin inputtable keyboard layout.
  1.1394 +    gint minGroup = GetFirstLatinGroup();
  1.1395 +    if (minGroup < 0) {
  1.1396 +        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
  1.1397 +            ("KeymapWrapper(%p): InitKeypressEvent, "
  1.1398 +             "Latin keyboard layout isn't found: "
  1.1399 +             "keyCode=0x%02X, charCode=0x%08X, level=%d, "
  1.1400 +             "altCharCodes={ mUnshiftedCharCode=0x%08X, "
  1.1401 +             "mShiftedCharCode=0x%08X }",
  1.1402 +             this, aKeyEvent.keyCode, aKeyEvent.charCode, level,
  1.1403 +             altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode));
  1.1404 +        return;
  1.1405 +    }
  1.1406 +
  1.1407 +    AlternativeCharCode altLatinCharCodes(0, 0);
  1.1408 +    uint32_t unmodifiedCh =
  1.1409 +        aKeyEvent.IsShift() ? altCharCodes.mShiftedCharCode :
  1.1410 +                              altCharCodes.mUnshiftedCharCode;
  1.1411 +
  1.1412 +    // unshifted charcode of found keyboard layout.
  1.1413 +    uint32_t ch = GetCharCodeFor(aGdkKeyEvent, baseState, minGroup);
  1.1414 +    altLatinCharCodes.mUnshiftedCharCode =
  1.1415 +        IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
  1.1416 +    // shifted charcode of found keyboard layout.
  1.1417 +    ch = GetCharCodeFor(aGdkKeyEvent,
  1.1418 +                        baseState | GetModifierMask(SHIFT),
  1.1419 +                        minGroup);
  1.1420 +    altLatinCharCodes.mShiftedCharCode =
  1.1421 +        IsBasicLatinLetterOrNumeral(ch) ? ch : 0;
  1.1422 +    if (altLatinCharCodes.mUnshiftedCharCode ||
  1.1423 +        altLatinCharCodes.mShiftedCharCode) {
  1.1424 +        aKeyEvent.alternativeCharCodes.AppendElement(altLatinCharCodes);
  1.1425 +    }
  1.1426 +    // If the charCode is not Latin, and the level is 0 or 1, we should
  1.1427 +    // replace the charCode to Latin char if Alt and Meta keys are not
  1.1428 +    // pressed. (Alt should be sent the localized char for accesskey
  1.1429 +    // like handling of Web Applications.)
  1.1430 +    ch = aKeyEvent.IsShift() ? altLatinCharCodes.mShiftedCharCode :
  1.1431 +                               altLatinCharCodes.mUnshiftedCharCode;
  1.1432 +    if (ch && !(aKeyEvent.IsAlt() || aKeyEvent.IsMeta()) &&
  1.1433 +        aKeyEvent.charCode == unmodifiedCh) {
  1.1434 +        aKeyEvent.charCode = ch;
  1.1435 +    }
  1.1436 +
  1.1437 +    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
  1.1438 +        ("KeymapWrapper(%p): InitKeypressEvent, "
  1.1439 +         "keyCode=0x%02X, charCode=0x%08X, level=%d, minGroup=%d, "
  1.1440 +         "altCharCodes={ mUnshiftedCharCode=0x%08X, "
  1.1441 +         "mShiftedCharCode=0x%08X } "
  1.1442 +         "altLatinCharCodes={ mUnshiftedCharCode=0x%08X, "
  1.1443 +         "mShiftedCharCode=0x%08X }",
  1.1444 +         this, aKeyEvent.keyCode, aKeyEvent.charCode, level, minGroup,
  1.1445 +         altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode,
  1.1446 +         altLatinCharCodes.mUnshiftedCharCode,
  1.1447 +         altLatinCharCodes.mShiftedCharCode));
  1.1448 +}
  1.1449 +
  1.1450 +/* static */ bool
  1.1451 +KeymapWrapper::IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent)
  1.1452 +{
  1.1453 +    // If this is a modifier key event, we shouldn't send keypress event.
  1.1454 +    switch (ComputeDOMKeyCode(aGdkKeyEvent)) {
  1.1455 +        case NS_VK_SHIFT:
  1.1456 +        case NS_VK_CONTROL:
  1.1457 +        case NS_VK_ALT:
  1.1458 +        case NS_VK_ALTGR:
  1.1459 +        case NS_VK_WIN:
  1.1460 +        case NS_VK_CAPS_LOCK:
  1.1461 +        case NS_VK_NUM_LOCK:
  1.1462 +        case NS_VK_SCROLL_LOCK:
  1.1463 +            return false;
  1.1464 +        default:
  1.1465 +            return true;
  1.1466 +    }
  1.1467 +}
  1.1468 +
  1.1469 +} // namespace widget
  1.1470 +} // namespace mozilla

mercurial