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