Coverage Report

Created: 2018-09-25 14:53

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