1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
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/. */
10 #include "nsGtkKeyUtils.h"
12 #include <gdk/gdkkeysyms.h>
16 #if (MOZ_WIDGET_GTK == 3)
17 #include <gdk/gdkkeysyms-compat.h>
19 #include <X11/XKBlib.h>
20 #include "WidgetUtils.h"
21 #include "keysym2ucs.h"
22 #include "nsIBidiKeyboard.h"
23 #include "nsServiceManagerUtils.h"
26 PRLogModuleInfo
* gKeymapWrapperLog
= nullptr;
29 #include "mozilla/ArrayUtils.h"
30 #include "mozilla/MouseEvents.h"
31 #include "mozilla/TextEvents.h"
36 #define IS_ASCII_ALPHABETICAL(key) \
37 ((('a' <= key) && (key <= 'z')) || (('A' <= key) && (key <= 'Z')))
39 #define MOZ_MODIFIER_KEYS "MozKeymapWrapper"
41 KeymapWrapper
* KeymapWrapper::sInstance
= nullptr;
42 guint
KeymapWrapper::sLastRepeatableHardwareKeyCode
= 0;
43 KeymapWrapper::RepeatState
KeymapWrapper::sRepeatState
=
44 KeymapWrapper::NOT_PRESSED
;
45 nsIBidiKeyboard
* sBidiKeyboard
= nullptr;
49 static const char* GetBoolName(bool aBool
)
51 return aBool
? "TRUE" : "FALSE";
54 /* static */ const char*
55 KeymapWrapper::GetModifierName(Modifier aModifier
)
58 case CAPS_LOCK
: return "CapsLock";
59 case NUM_LOCK
: return "NumLock";
60 case SCROLL_LOCK
: return "ScrollLock";
61 case SHIFT
: return "Shift";
62 case CTRL
: return "Ctrl";
63 case ALT
: return "Alt";
64 case SUPER
: return "Super";
65 case HYPER
: return "Hyper";
66 case META
: return "Meta";
67 case LEVEL3
: return "Level3";
68 case LEVEL5
: return "Level5";
69 case NOT_MODIFIER
: return "NotModifier";
70 default: return "InvalidValue";
76 /* static */ KeymapWrapper::Modifier
77 KeymapWrapper::GetModifierForGDKKeyval(guint aGdkKeyval
)
80 case GDK_Caps_Lock
: return CAPS_LOCK
;
81 case GDK_Num_Lock
: return NUM_LOCK
;
82 case GDK_Scroll_Lock
: return SCROLL_LOCK
;
85 case GDK_Shift_R
: return SHIFT
;
87 case GDK_Control_R
: return CTRL
;
89 case GDK_Alt_R
: return ALT
;
91 case GDK_Super_R
: return SUPER
;
93 case GDK_Hyper_R
: return HYPER
;
95 case GDK_Meta_R
: return META
;
96 case GDK_ISO_Level3_Shift
:
97 case GDK_Mode_switch
: return LEVEL3
;
98 case GDK_ISO_Level5_Shift
: return LEVEL5
;
99 default: return NOT_MODIFIER
;
104 KeymapWrapper::GetModifierMask(Modifier aModifier
) const
108 return GDK_LOCK_MASK
;
110 return mModifierMasks
[INDEX_NUM_LOCK
];
112 return mModifierMasks
[INDEX_SCROLL_LOCK
];
114 return GDK_SHIFT_MASK
;
116 return GDK_CONTROL_MASK
;
118 return mModifierMasks
[INDEX_ALT
];
120 return mModifierMasks
[INDEX_SUPER
];
122 return mModifierMasks
[INDEX_HYPER
];
124 return mModifierMasks
[INDEX_META
];
126 return mModifierMasks
[INDEX_LEVEL3
];
128 return mModifierMasks
[INDEX_LEVEL5
];
134 KeymapWrapper::ModifierKey
*
135 KeymapWrapper::GetModifierKey(guint aHardwareKeycode
)
137 for (uint32_t i
= 0; i
< mModifierKeys
.Length(); i
++) {
138 ModifierKey
& key
= mModifierKeys
[i
];
139 if (key
.mHardwareKeycode
== aHardwareKeycode
) {
146 /* static */ KeymapWrapper
*
147 KeymapWrapper::GetInstance()
154 sInstance
= new KeymapWrapper();
158 KeymapWrapper::KeymapWrapper() :
159 mInitialized(false), mGdkKeymap(gdk_keymap_get_default()),
163 if (!gKeymapWrapperLog
) {
164 gKeymapWrapperLog
= PR_NewLogModule("KeymapWrapperWidgets");
166 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
167 ("KeymapWrapper(%p): Constructor, mGdkKeymap=%p",
171 g_signal_connect(mGdkKeymap
, "keys-changed",
172 (GCallback
)OnKeysChanged
, this);
174 // This is necessary for catching the destroying timing.
175 g_object_weak_ref(G_OBJECT(mGdkKeymap
),
176 (GWeakNotify
)OnDestroyKeymap
, this);
184 KeymapWrapper::Init()
191 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
192 ("KeymapWrapper(%p): Init, mGdkKeymap=%p",
195 mModifierKeys
.Clear();
196 memset(mModifierMasks
, 0, sizeof(mModifierMasks
));
198 InitBySystemSettings();
200 gdk_window_add_filter(nullptr, FilterEvents
, this);
202 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
203 ("KeymapWrapper(%p): Init, CapsLock=0x%X, NumLock=0x%X, "
204 "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
205 "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X",
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
)));
216 KeymapWrapper::InitXKBExtension()
218 PodZero(&mKeyboardState
);
220 int xkbMajorVer
= XkbMajorVersion
;
221 int xkbMinorVer
= XkbMinorVersion
;
222 if (!XkbLibraryVersion(&xkbMajorVer
, &xkbMinorVer
)) {
223 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
224 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
225 "XkbLibraryVersion()", this));
230 gdk_x11_display_get_xdisplay(gdk_display_get_default());
232 // XkbLibraryVersion() set xkbMajorVer and xkbMinorVer to that of the
233 // library, which may be newer than what is required of the server in
234 // XkbQueryExtension(), so these variables should be reset to
235 // XkbMajorVersion and XkbMinorVersion before the XkbQueryExtension call.
236 xkbMajorVer
= XkbMajorVersion
;
237 xkbMinorVer
= XkbMinorVersion
;
238 int opcode
, baseErrorCode
;
239 if (!XkbQueryExtension(display
, &opcode
, &mXKBBaseEventCode
, &baseErrorCode
,
240 &xkbMajorVer
, &xkbMinorVer
)) {
241 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
242 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
243 "XkbQueryExtension(), display=0x%p", this, display
));
247 if (!XkbSelectEventDetails(display
, XkbUseCoreKbd
, XkbStateNotify
,
248 XkbModifierStateMask
, XkbModifierStateMask
)) {
249 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
250 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
251 "XkbSelectEventDetails() for XModifierStateMask, display=0x%p",
256 if (!XkbSelectEventDetails(display
, XkbUseCoreKbd
, XkbControlsNotify
,
257 XkbPerKeyRepeatMask
, XkbPerKeyRepeatMask
)) {
258 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
259 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
260 "XkbSelectEventDetails() for XkbControlsNotify, display=0x%p",
265 if (!XGetKeyboardControl(display
, &mKeyboardState
)) {
266 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
267 ("KeymapWrapper(%p): InitXKBExtension failed due to failure of "
268 "XGetKeyboardControl(), display=0x%p",
273 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
274 ("KeymapWrapper(%p): InitXKBExtension, Succeeded", this));
278 KeymapWrapper::InitBySystemSettings()
280 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
281 ("KeymapWrapper(%p): InitBySystemSettings, mGdkKeymap=%p",
285 gdk_x11_display_get_xdisplay(gdk_display_get_default());
289 XDisplayKeycodes(display
, &min_keycode
, &max_keycode
);
291 int keysyms_per_keycode
= 0;
292 KeySym
* xkeymap
= XGetKeyboardMapping(display
, min_keycode
,
293 max_keycode
- min_keycode
+ 1,
294 &keysyms_per_keycode
);
296 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
297 ("KeymapWrapper(%p): InitBySystemSettings, "
298 "Failed due to null xkeymap", this));
302 XModifierKeymap
* xmodmap
= XGetModifierMapping(display
);
304 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
305 ("KeymapWrapper(%p): InitBySystemSettings, "
306 "Failed due to null xmodmap", this));
310 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
311 ("KeymapWrapper(%p): InitBySystemSettings, min_keycode=%d, "
312 "max_keycode=%d, keysyms_per_keycode=%d, max_keypermod=%d",
313 this, min_keycode
, max_keycode
, keysyms_per_keycode
,
314 xmodmap
->max_keypermod
));
316 // The modifiermap member of the XModifierKeymap structure contains 8 sets
317 // of max_keypermod KeyCodes, one for each modifier in the order Shift,
318 // Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5.
319 // Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are
322 // Note that two or more modifiers may use one modifier flag. E.g.,
323 // on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings.
324 // And also Super and Hyper share the Mod4. In such cases, we need to
325 // decide which modifier flag means one of DOM modifiers.
327 // mod[0] is Modifier introduced by Mod1.
329 int32_t foundLevel
[5];
330 for (uint32_t i
= 0; i
< ArrayLength(mod
); i
++) {
331 mod
[i
] = NOT_MODIFIER
;
332 foundLevel
[i
] = INT32_MAX
;
334 const uint32_t map_size
= 8 * xmodmap
->max_keypermod
;
335 for (uint32_t i
= 0; i
< map_size
; i
++) {
336 KeyCode keycode
= xmodmap
->modifiermap
[i
];
337 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
338 ("KeymapWrapper(%p): InitBySystemSettings, "
339 " i=%d, keycode=0x%08X",
341 if (!keycode
|| keycode
< min_keycode
|| keycode
> max_keycode
) {
345 ModifierKey
* modifierKey
= GetModifierKey(keycode
);
347 modifierKey
= mModifierKeys
.AppendElement(ModifierKey(keycode
));
351 xkeymap
+ (keycode
- min_keycode
) * keysyms_per_keycode
;
352 const uint32_t bit
= i
/ xmodmap
->max_keypermod
;
353 modifierKey
->mMask
|= 1 << bit
;
355 // We need to know the meaning of Mod1, Mod2, Mod3, Mod4 and Mod5.
356 // Let's skip if current map is for others.
361 const int32_t modIndex
= bit
- 3;
362 for (int32_t j
= 0; j
< keysyms_per_keycode
; j
++) {
363 Modifier modifier
= GetModifierForGDKKeyval(syms
[j
]);
364 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
365 ("KeymapWrapper(%p): InitBySystemSettings, "
366 " Mod%d, j=%d, syms[j]=%s(0x%X), modifier=%s",
367 this, modIndex
+ 1, j
, gdk_keyval_name(syms
[j
]), syms
[j
],
368 GetModifierName(modifier
)));
372 // Don't overwrite the stored information with
378 // Ignore the modifiers defined in GDK spec. They shouldn't
379 // be mapped to Mod1-5 because they must not work on native
383 // If new modifier is found in higher level than stored
384 // value, we don't need to overwrite it.
385 if (j
> foundLevel
[modIndex
]) {
388 // If new modifier is more important than stored value,
389 // we should overwrite it with new modifier.
390 if (j
== foundLevel
[modIndex
]) {
391 mod
[modIndex
] = std::min(modifier
, mod
[modIndex
]);
394 foundLevel
[modIndex
] = j
;
395 mod
[modIndex
] = modifier
;
401 for (uint32_t i
= 0; i
< COUNT_OF_MODIFIER_INDEX
; i
++) {
407 case INDEX_SCROLL_LOCK
:
408 modifier
= SCROLL_LOCK
;
429 MOZ_CRASH("All indexes must be handled here");
431 for (uint32_t j
= 0; j
< ArrayLength(mod
); j
++) {
432 if (modifier
== mod
[j
]) {
433 mModifierMasks
[i
] |= 1 << (j
+ 3);
438 XFreeModifiermap(xmodmap
);
442 KeymapWrapper::~KeymapWrapper()
444 gdk_window_remove_filter(nullptr, FilterEvents
, this);
445 NS_IF_RELEASE(sBidiKeyboard
);
446 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
447 ("KeymapWrapper(%p): Destructor", this));
450 /* static */ GdkFilterReturn
451 KeymapWrapper::FilterEvents(GdkXEvent
* aXEvent
,
455 XEvent
* xEvent
= static_cast<XEvent
*>(aXEvent
);
456 switch (xEvent
->type
) {
458 // If the key doesn't support auto repeat, ignore the event because
459 // even if such key (e.g., Shift) is pressed during auto repeat of
460 // anoter key, it doesn't stop the auto repeat.
461 KeymapWrapper
* self
= static_cast<KeymapWrapper
*>(aData
);
462 if (!self
->IsAutoRepeatableKey(xEvent
->xkey
.keycode
)) {
465 if (sRepeatState
== NOT_PRESSED
) {
466 sRepeatState
= FIRST_PRESS
;
467 } else if (sLastRepeatableHardwareKeyCode
== xEvent
->xkey
.keycode
) {
468 sRepeatState
= REPEATING
;
470 // If a different key is pressed while another key is pressed,
471 // auto repeat system repeats only the last pressed key.
472 // So, setting new keycode and setting repeat state as first key
473 // press should work fine.
474 sRepeatState
= FIRST_PRESS
;
476 sLastRepeatableHardwareKeyCode
= xEvent
->xkey
.keycode
;
480 if (sLastRepeatableHardwareKeyCode
!= xEvent
->xkey
.keycode
) {
481 // This case means the key release event is caused by
482 // a non-repeatable key such as Shift or a repeatable key that
483 // was pressed before sLastRepeatableHardwareKeyCode was
487 sRepeatState
= NOT_PRESSED
;
491 // At moving focus, we should reset keyboard repeat state.
492 // Strictly, this causes incorrect behavior. However, this
493 // correctness must be enough for web applications.
494 sRepeatState
= NOT_PRESSED
;
498 KeymapWrapper
* self
= static_cast<KeymapWrapper
*>(aData
);
499 if (xEvent
->type
!= self
->mXKBBaseEventCode
) {
502 XkbEvent
* xkbEvent
= (XkbEvent
*)xEvent
;
503 if (xkbEvent
->any
.xkb_type
!= XkbControlsNotify
||
504 !(xkbEvent
->ctrls
.changed_ctrls
& XkbPerKeyRepeatMask
)) {
507 if (!XGetKeyboardControl(xkbEvent
->any
.display
,
508 &self
->mKeyboardState
)) {
509 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
510 ("KeymapWrapper(%p): FilterEvents failed due to failure "
511 "of XGetKeyboardControl(), display=0x%p",
512 self
, xkbEvent
->any
.display
));
518 return GDK_FILTER_CONTINUE
;
522 KeymapWrapper::OnDestroyKeymap(KeymapWrapper
* aKeymapWrapper
,
523 GdkKeymap
*aGdkKeymap
)
525 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
526 ("KeymapWrapper: OnDestroyKeymap, aGdkKeymap=%p, aKeymapWrapper=%p",
527 aGdkKeymap
, aKeymapWrapper
));
528 MOZ_ASSERT(aKeymapWrapper
== sInstance
,
529 "Desroying unexpected instance");
535 KeymapWrapper::OnKeysChanged(GdkKeymap
*aGdkKeymap
,
536 KeymapWrapper
* aKeymapWrapper
)
538 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
539 ("KeymapWrapper: OnKeysChanged, aGdkKeymap=%p, aKeymapWrapper=%p",
540 aGdkKeymap
, aKeymapWrapper
));
542 MOZ_ASSERT(sInstance
== aKeymapWrapper
,
543 "This instance must be the singleton instance");
545 // We cannot reintialize here becasue we don't have GdkWindow which is using
546 // the GdkKeymap. We'll reinitialize it when next GetInstance() is called.
547 sInstance
->mInitialized
= false;
549 // Reset the bidi keyboard settings for the new GdkKeymap
550 if (!sBidiKeyboard
) {
551 CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard
);
554 sBidiKeyboard
->Reset();
559 KeymapWrapper::GetCurrentModifierState()
561 GdkModifierType modifiers
;
562 gdk_display_get_pointer(gdk_display_get_default(),
563 nullptr, nullptr, nullptr, &modifiers
);
564 return static_cast<guint
>(modifiers
);
568 KeymapWrapper::AreModifiersCurrentlyActive(Modifiers aModifiers
)
570 guint modifierState
= GetCurrentModifierState();
571 return AreModifiersActive(aModifiers
, modifierState
);
575 KeymapWrapper::AreModifiersActive(Modifiers aModifiers
,
576 guint aModifierState
)
578 NS_ENSURE_TRUE(aModifiers
, false);
580 KeymapWrapper
* keymapWrapper
= GetInstance();
581 for (uint32_t i
= 0; i
< sizeof(Modifier
) * 8 && aModifiers
; i
++) {
582 Modifier modifier
= static_cast<Modifier
>(1 << i
);
583 if (!(aModifiers
& modifier
)) {
586 if (!(aModifierState
& keymapWrapper
->GetModifierMask(modifier
))) {
589 aModifiers
&= ~modifier
;
595 KeymapWrapper::InitInputEvent(WidgetInputEvent
& aInputEvent
,
596 guint aModifierState
)
598 KeymapWrapper
* keymapWrapper
= GetInstance();
600 aInputEvent
.modifiers
= 0;
601 // DOM Meta key should be TRUE only on Mac. We need to discuss this
603 if (keymapWrapper
->AreModifiersActive(SHIFT
, aModifierState
)) {
604 aInputEvent
.modifiers
|= MODIFIER_SHIFT
;
606 if (keymapWrapper
->AreModifiersActive(CTRL
, aModifierState
)) {
607 aInputEvent
.modifiers
|= MODIFIER_CONTROL
;
609 if (keymapWrapper
->AreModifiersActive(ALT
, aModifierState
)) {
610 aInputEvent
.modifiers
|= MODIFIER_ALT
;
612 if (keymapWrapper
->AreModifiersActive(META
, aModifierState
)) {
613 aInputEvent
.modifiers
|= MODIFIER_META
;
615 if (keymapWrapper
->AreModifiersActive(SUPER
, aModifierState
) ||
616 keymapWrapper
->AreModifiersActive(HYPER
, aModifierState
)) {
617 aInputEvent
.modifiers
|= MODIFIER_OS
;
619 if (keymapWrapper
->AreModifiersActive(LEVEL3
, aModifierState
) ||
620 keymapWrapper
->AreModifiersActive(LEVEL5
, aModifierState
)) {
621 aInputEvent
.modifiers
|= MODIFIER_ALTGRAPH
;
623 if (keymapWrapper
->AreModifiersActive(CAPS_LOCK
, aModifierState
)) {
624 aInputEvent
.modifiers
|= MODIFIER_CAPSLOCK
;
626 if (keymapWrapper
->AreModifiersActive(NUM_LOCK
, aModifierState
)) {
627 aInputEvent
.modifiers
|= MODIFIER_NUMLOCK
;
629 if (keymapWrapper
->AreModifiersActive(SCROLL_LOCK
, aModifierState
)) {
630 aInputEvent
.modifiers
|= MODIFIER_SCROLLLOCK
;
633 PR_LOG(gKeymapWrapperLog
, PR_LOG_DEBUG
,
634 ("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X, "
635 "aInputEvent.modifiers=0x%04X (Shift: %s, Control: %s, Alt: %s, "
636 "Meta: %s, OS: %s, AltGr: %s, "
637 "CapsLock: %s, NumLock: %s, ScrollLock: %s)",
638 keymapWrapper
, aModifierState
, aInputEvent
.modifiers
,
639 GetBoolName(aInputEvent
.modifiers
& MODIFIER_SHIFT
),
640 GetBoolName(aInputEvent
.modifiers
& MODIFIER_CONTROL
),
641 GetBoolName(aInputEvent
.modifiers
& MODIFIER_ALT
),
642 GetBoolName(aInputEvent
.modifiers
& MODIFIER_META
),
643 GetBoolName(aInputEvent
.modifiers
& MODIFIER_OS
),
644 GetBoolName(aInputEvent
.modifiers
& MODIFIER_ALTGRAPH
),
645 GetBoolName(aInputEvent
.modifiers
& MODIFIER_CAPSLOCK
),
646 GetBoolName(aInputEvent
.modifiers
& MODIFIER_NUMLOCK
),
647 GetBoolName(aInputEvent
.modifiers
& MODIFIER_SCROLLLOCK
)));
649 switch(aInputEvent
.mClass
) {
650 case eMouseEventClass
:
651 case eMouseScrollEventClass
:
652 case eWheelEventClass
:
653 case eDragEventClass
:
654 case eSimpleGestureEventClass
:
660 WidgetMouseEventBase
& mouseEvent
= *aInputEvent
.AsMouseEventBase();
661 mouseEvent
.buttons
= 0;
662 if (aModifierState
& GDK_BUTTON1_MASK
) {
663 mouseEvent
.buttons
|= WidgetMouseEvent::eLeftButtonFlag
;
665 if (aModifierState
& GDK_BUTTON3_MASK
) {
666 mouseEvent
.buttons
|= WidgetMouseEvent::eRightButtonFlag
;
668 if (aModifierState
& GDK_BUTTON2_MASK
) {
669 mouseEvent
.buttons
|= WidgetMouseEvent::eMiddleButtonFlag
;
672 PR_LOG(gKeymapWrapperLog
, PR_LOG_DEBUG
,
673 ("KeymapWrapper(%p): InitInputEvent, aInputEvent has buttons, "
674 "aInputEvent.buttons=0x%04X (Left: %s, Right: %s, Middle: %s, "
675 "4th (BACK): %s, 5th (FORWARD): %s)",
676 keymapWrapper
, mouseEvent
.buttons
,
677 GetBoolName(mouseEvent
.buttons
& WidgetMouseEvent::eLeftButtonFlag
),
678 GetBoolName(mouseEvent
.buttons
& WidgetMouseEvent::eRightButtonFlag
),
679 GetBoolName(mouseEvent
.buttons
& WidgetMouseEvent::eMiddleButtonFlag
),
680 GetBoolName(mouseEvent
.buttons
& WidgetMouseEvent::e4thButtonFlag
),
681 GetBoolName(mouseEvent
.buttons
& WidgetMouseEvent::e5thButtonFlag
)));
684 /* static */ uint32_t
685 KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey
* aGdkKeyEvent
)
687 // If the keyval indicates it's a modifier key, we should use unshifted
688 // key's modifier keyval.
689 guint keyval
= aGdkKeyEvent
->keyval
;
690 if (GetModifierForGDKKeyval(keyval
)) {
691 // But if the keyval without modifiers isn't a modifier key, we
692 // shouldn't use it. E.g., Japanese keyboard layout's
693 // Shift + Eisu-Toggle key is CapsLock. This is an actual rare case,
694 // Windows uses different keycode for a physical key for different
696 guint keyvalWithoutModifier
= GetGDKKeyvalWithoutModifier(aGdkKeyEvent
);
697 if (GetModifierForGDKKeyval(keyvalWithoutModifier
)) {
698 keyval
= keyvalWithoutModifier
;
700 // Note that the modifier keycode and activating or deactivating
701 // modifier flag may be mismatched, but it's okay. If a DOM key
702 // event handler is testing a keydown event, it's more likely being
703 // used to test which key is being pressed than to test which
704 // modifier will become active. So, if we computed DOM keycode
705 // from modifier flag which were changing by the physical key, then
706 // there would be no other way for the user to generate the original
708 uint32_t DOMKeyCode
= GetDOMKeyCodeFromKeyPairs(keyval
);
709 NS_ASSERTION(DOMKeyCode
, "All modifier keys must have a DOM keycode");
713 // If the key isn't printable, let's look at the key pairs.
714 uint32_t charCode
= GetCharCodeFor(aGdkKeyEvent
);
716 // Always use unshifted keycode for the non-printable key.
717 // XXX It might be better to decide DOM keycode from all keyvals of
718 // the hardware keycode. However, I think that it's too excessive.
719 guint keyvalWithoutModifier
= GetGDKKeyvalWithoutModifier(aGdkKeyEvent
);
720 uint32_t DOMKeyCode
= GetDOMKeyCodeFromKeyPairs(keyvalWithoutModifier
);
722 // If the unshifted keyval couldn't be mapped to a DOM keycode,
723 // we should fallback to legacy logic, so, we should recompute with
724 // the keyval with aGdkKeyEvent.
725 DOMKeyCode
= GetDOMKeyCodeFromKeyPairs(keyval
);
730 // printable numpad keys should be resolved here.
732 case GDK_KP_Multiply
: return NS_VK_MULTIPLY
;
733 case GDK_KP_Add
: return NS_VK_ADD
;
734 case GDK_KP_Separator
: return NS_VK_SEPARATOR
;
735 case GDK_KP_Subtract
: return NS_VK_SUBTRACT
;
736 case GDK_KP_Decimal
: return NS_VK_DECIMAL
;
737 case GDK_KP_Divide
: return NS_VK_DIVIDE
;
738 case GDK_KP_0
: return NS_VK_NUMPAD0
;
739 case GDK_KP_1
: return NS_VK_NUMPAD1
;
740 case GDK_KP_2
: return NS_VK_NUMPAD2
;
741 case GDK_KP_3
: return NS_VK_NUMPAD3
;
742 case GDK_KP_4
: return NS_VK_NUMPAD4
;
743 case GDK_KP_5
: return NS_VK_NUMPAD5
;
744 case GDK_KP_6
: return NS_VK_NUMPAD6
;
745 case GDK_KP_7
: return NS_VK_NUMPAD7
;
746 case GDK_KP_8
: return NS_VK_NUMPAD8
;
747 case GDK_KP_9
: return NS_VK_NUMPAD9
;
750 KeymapWrapper
* keymapWrapper
= GetInstance();
752 // Ignore all modifier state except NumLock.
754 (aGdkKeyEvent
->state
& keymapWrapper
->GetModifierMask(NUM_LOCK
));
756 // Basically, we should use unmodified character for deciding our keyCode.
757 uint32_t unmodifiedChar
=
758 keymapWrapper
->GetCharCodeFor(aGdkKeyEvent
, baseState
,
759 aGdkKeyEvent
->group
);
760 if (IsBasicLatinLetterOrNumeral(unmodifiedChar
)) {
761 // If the unmodified character is an ASCII alphabet or an ASCII
762 // numeric, it's the best hint for deciding our keyCode.
763 return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar
);
766 // If the unmodified character is not an ASCII character, that means we
767 // couldn't find the hint. We should reset it.
768 if (unmodifiedChar
> 0x7F) {
772 // Retry with shifted keycode.
773 guint shiftState
= (baseState
| keymapWrapper
->GetModifierMask(SHIFT
));
774 uint32_t shiftedChar
=
775 keymapWrapper
->GetCharCodeFor(aGdkKeyEvent
, shiftState
,
776 aGdkKeyEvent
->group
);
777 if (IsBasicLatinLetterOrNumeral(shiftedChar
)) {
778 // A shifted character can be an ASCII alphabet on Hebrew keyboard
779 // layout. And also shifted character can be an ASCII numeric on
780 // AZERTY keyboad layout. Then, it's a good hint for deciding our
782 return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar
);
785 // If the shifted unmodified character isn't an ASCII character, we should
787 if (shiftedChar
> 0x7F) {
791 // If current keyboard layout isn't ASCII alphabet inputtable layout,
792 // look for ASCII alphabet inputtable keyboard layout. If the key
793 // inputs an ASCII alphabet or an ASCII numeric, we should use it
794 // for deciding our keyCode.
795 // Note that it's important not to use alternative keyboard layout for ASCII
796 // alphabet inputabble keyboard layout because the keycode for the key with
797 // alternative keyboard layout may conflict with another key on current
799 if (!keymapWrapper
->IsLatinGroup(aGdkKeyEvent
->group
)) {
800 gint minGroup
= keymapWrapper
->GetFirstLatinGroup();
802 uint32_t unmodCharLatin
=
803 keymapWrapper
->GetCharCodeFor(aGdkKeyEvent
, baseState
,
805 if (IsBasicLatinLetterOrNumeral(unmodCharLatin
)) {
806 // If the unmodified character is an ASCII alphabet or
807 // an ASCII numeric, we should use it for the keyCode.
808 return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin
);
810 uint32_t shiftedCharLatin
=
811 keymapWrapper
->GetCharCodeFor(aGdkKeyEvent
, shiftState
,
813 if (IsBasicLatinLetterOrNumeral(shiftedCharLatin
)) {
814 // If the shifted character is an ASCII alphabet or an ASCII
815 // numeric, we should use it for the keyCode.
816 return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin
);
821 // If unmodified character is in ASCII range, use it. Otherwise, use
822 // shifted character.
823 if (!unmodifiedChar
&& !shiftedChar
) {
826 return WidgetUtils::ComputeKeyCodeFromChar(
827 unmodifiedChar
? unmodifiedChar
: shiftedChar
);
831 KeymapWrapper::ComputeDOMKeyNameIndex(const GdkEventKey
* aGdkKeyEvent
)
833 switch (aGdkKeyEvent
->keyval
) {
835 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
836 case aNativeKey: return aKeyNameIndex;
838 #include "NativeKeyToDOMKeyName.h"
840 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
846 return KEY_NAME_INDEX_Unidentified
;
849 /* static */ CodeNameIndex
850 KeymapWrapper::ComputeDOMCodeNameIndex(const GdkEventKey
* aGdkKeyEvent
)
852 switch (aGdkKeyEvent
->hardware_keycode
) {
854 #define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, aCodeNameIndex) \
855 case aNativeKey: return aCodeNameIndex;
857 #include "NativeKeyToDOMCodeName.h"
859 #undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX
865 return CODE_NAME_INDEX_UNKNOWN
;
869 KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent
& aKeyEvent
,
870 GdkEventKey
* aGdkKeyEvent
)
872 KeymapWrapper
* keymapWrapper
= GetInstance();
874 aKeyEvent
.mCodeNameIndex
= ComputeDOMCodeNameIndex(aGdkKeyEvent
);
875 MOZ_ASSERT(aKeyEvent
.mCodeNameIndex
!= CODE_NAME_INDEX_USE_STRING
);
876 aKeyEvent
.mKeyNameIndex
=
877 keymapWrapper
->ComputeDOMKeyNameIndex(aGdkKeyEvent
);
878 if (aKeyEvent
.mKeyNameIndex
== KEY_NAME_INDEX_Unidentified
) {
879 uint32_t charCode
= GetCharCodeFor(aGdkKeyEvent
);
881 charCode
= keymapWrapper
->GetUnmodifiedCharCodeFor(aGdkKeyEvent
);
884 aKeyEvent
.mKeyNameIndex
= KEY_NAME_INDEX_USE_STRING
;
885 MOZ_ASSERT(aKeyEvent
.mKeyValue
.IsEmpty(),
886 "Uninitialized mKeyValue must be empty");
887 AppendUCS4ToUTF16(charCode
, aKeyEvent
.mKeyValue
);
890 aKeyEvent
.keyCode
= ComputeDOMKeyCode(aGdkKeyEvent
);
892 // NOTE: The state of given key event indicates adjacent state of
893 // modifier keys. E.g., even if the event is Shift key press event,
894 // the bit for Shift is still false. By the same token, even if the
895 // event is Shift key release event, the bit for Shift is still true.
896 // Unfortunately, gdk_keyboard_get_modifiers() returns current modifier
897 // state. It means if there're some pending modifier key press or
898 // key release events, the result isn't what we want.
899 guint modifierState
= aGdkKeyEvent
->state
;
900 if (aGdkKeyEvent
->is_modifier
) {
902 gdk_x11_display_get_xdisplay(gdk_display_get_default());
903 if (XEventsQueued(display
, QueuedAfterReading
)) {
905 XPeekEvent(display
, &nextEvent
);
906 if (nextEvent
.type
== keymapWrapper
->mXKBBaseEventCode
) {
907 XkbEvent
* XKBEvent
= (XkbEvent
*)&nextEvent
;
908 if (XKBEvent
->any
.xkb_type
== XkbStateNotify
) {
909 XkbStateNotifyEvent
* stateNotifyEvent
=
910 (XkbStateNotifyEvent
*)XKBEvent
;
911 modifierState
&= ~0xFF;
912 modifierState
|= stateNotifyEvent
->lookup_mods
;
917 InitInputEvent(aKeyEvent
, modifierState
);
919 switch (aGdkKeyEvent
->keyval
) {
926 aKeyEvent
.location
= nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT
;
935 aKeyEvent
.location
= nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT
;
960 case GDK_KP_Prior
: // same as GDK_KP_Page_Up
961 case GDK_KP_Next
: // same as GDK_KP_Page_Down
967 case GDK_KP_Multiply
:
969 case GDK_KP_Separator
:
970 case GDK_KP_Subtract
:
973 aKeyEvent
.location
= nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD
;
977 aKeyEvent
.location
= nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD
;
981 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
982 ("KeymapWrapper(%p): InitKeyEvent, modifierState=0x%08X "
983 "aGdkKeyEvent={ type=%s, keyval=%s(0x%X), state=0x%08X, "
984 "hardware_keycode=0x%08X, is_modifier=%s } "
985 "aKeyEvent={ message=%s, isShift=%s, isControl=%s, "
986 "isAlt=%s, isMeta=%s }",
987 keymapWrapper
, modifierState
,
988 ((aGdkKeyEvent
->type
== GDK_KEY_PRESS
) ?
989 "GDK_KEY_PRESS" : "GDK_KEY_RELEASE"),
990 gdk_keyval_name(aGdkKeyEvent
->keyval
),
991 aGdkKeyEvent
->keyval
, aGdkKeyEvent
->state
,
992 aGdkKeyEvent
->hardware_keycode
,
993 GetBoolName(aGdkKeyEvent
->is_modifier
),
994 ((aKeyEvent
.message
== NS_KEY_DOWN
) ? "NS_KEY_DOWN" :
995 (aKeyEvent
.message
== NS_KEY_PRESS
) ? "NS_KEY_PRESS" :
997 GetBoolName(aKeyEvent
.IsShift()), GetBoolName(aKeyEvent
.IsControl()),
998 GetBoolName(aKeyEvent
.IsAlt()), GetBoolName(aKeyEvent
.IsMeta())));
1000 if (aKeyEvent
.message
== NS_KEY_PRESS
) {
1001 keymapWrapper
->InitKeypressEvent(aKeyEvent
, aGdkKeyEvent
);
1004 // The transformations above and in gdk for the keyval are not invertible
1005 // so link to the GdkEvent (which will vanish soon after return from the
1006 // event callback) to give plugins access to hardware_keycode and state.
1007 // (An XEvent would be nice but the GdkEvent is good enough.)
1008 aKeyEvent
.mPluginEvent
.Copy(*aGdkKeyEvent
);
1009 aKeyEvent
.time
= aGdkKeyEvent
->time
;
1010 aKeyEvent
.mNativeKeyEvent
= static_cast<void*>(aGdkKeyEvent
);
1011 aKeyEvent
.mIsRepeat
= sRepeatState
== REPEATING
&&
1012 aGdkKeyEvent
->hardware_keycode
== sLastRepeatableHardwareKeyCode
;
1015 /* static */ uint32_t
1016 KeymapWrapper::GetCharCodeFor(const GdkEventKey
*aGdkKeyEvent
)
1018 // Anything above 0xf000 is considered a non-printable
1019 // Exception: directly encoded UCS characters
1020 if (aGdkKeyEvent
->keyval
> 0xf000 &&
1021 (aGdkKeyEvent
->keyval
& 0xff000000) != 0x01000000) {
1022 // Keypad keys are an exception: they return a value different
1023 // from their non-keypad equivalents, but mozilla doesn't distinguish.
1024 switch (aGdkKeyEvent
->keyval
) {
1025 case GDK_KP_Space
: return ' ';
1026 case GDK_KP_Equal
: return '=';
1027 case GDK_KP_Multiply
: return '*';
1028 case GDK_KP_Add
: return '+';
1029 case GDK_KP_Separator
: return ',';
1030 case GDK_KP_Subtract
: return '-';
1031 case GDK_KP_Decimal
: return '.';
1032 case GDK_KP_Divide
: return '/';
1033 case GDK_KP_0
: return '0';
1034 case GDK_KP_1
: return '1';
1035 case GDK_KP_2
: return '2';
1036 case GDK_KP_3
: return '3';
1037 case GDK_KP_4
: return '4';
1038 case GDK_KP_5
: return '5';
1039 case GDK_KP_6
: return '6';
1040 case GDK_KP_7
: return '7';
1041 case GDK_KP_8
: return '8';
1042 case GDK_KP_9
: return '9';
1043 default: return 0; // non-printables
1047 static const long MAX_UNICODE
= 0x10FFFF;
1049 // we're supposedly printable, let's try to convert
1050 long ucs
= keysym2ucs(aGdkKeyEvent
->keyval
);
1051 if ((ucs
!= -1) && (ucs
< MAX_UNICODE
)) {
1055 // I guess we couldn't convert
1060 KeymapWrapper::GetCharCodeFor(const GdkEventKey
*aGdkKeyEvent
,
1061 guint aModifierState
,
1065 if (!gdk_keymap_translate_keyboard_state(mGdkKeymap
,
1066 aGdkKeyEvent
->hardware_keycode
,
1067 GdkModifierType(aModifierState
),
1068 aGroup
, &keyval
, nullptr, nullptr, nullptr)) {
1071 GdkEventKey tmpEvent
= *aGdkKeyEvent
;
1072 tmpEvent
.state
= aModifierState
;
1073 tmpEvent
.keyval
= keyval
;
1074 tmpEvent
.group
= aGroup
;
1075 return GetCharCodeFor(&tmpEvent
);
1079 KeymapWrapper::GetUnmodifiedCharCodeFor(const GdkEventKey
* aGdkKeyEvent
)
1081 guint state
= aGdkKeyEvent
->state
&
1082 (GetModifierMask(SHIFT
) | GetModifierMask(CAPS_LOCK
) |
1083 GetModifierMask(NUM_LOCK
) | GetModifierMask(SCROLL_LOCK
) |
1084 GetModifierMask(LEVEL3
) | GetModifierMask(LEVEL5
));
1085 uint32_t charCode
= GetCharCodeFor(aGdkKeyEvent
, GdkModifierType(state
),
1086 aGdkKeyEvent
->group
);
1090 // If no character is mapped to the key when Level3 Shift or Level5 Shift
1091 // is active, let's return a character which is inputted by the key without
1092 // Level3 nor Level5 Shift.
1093 guint stateWithoutAltGraph
=
1094 state
& ~(GetModifierMask(LEVEL3
) | GetModifierMask(LEVEL5
));
1095 if (state
== stateWithoutAltGraph
) {
1098 return GetCharCodeFor(aGdkKeyEvent
, GdkModifierType(stateWithoutAltGraph
),
1099 aGdkKeyEvent
->group
);
1103 KeymapWrapper::GetKeyLevel(GdkEventKey
*aGdkKeyEvent
)
1106 if (!gdk_keymap_translate_keyboard_state(mGdkKeymap
,
1107 aGdkKeyEvent
->hardware_keycode
,
1108 GdkModifierType(aGdkKeyEvent
->state
),
1109 aGdkKeyEvent
->group
, nullptr, nullptr, &level
, nullptr)) {
1116 KeymapWrapper::GetFirstLatinGroup()
1121 if (gdk_keymap_get_entries_for_keyval(mGdkKeymap
, GDK_a
, &keys
, &count
)) {
1122 // find the minimum number group for latin inputtable layout
1123 for (gint i
= 0; i
< count
&& minGroup
!= 0; ++i
) {
1124 if (keys
[i
].level
!= 0 && keys
[i
].level
!= 1) {
1127 if (minGroup
>= 0 && keys
[i
].group
> minGroup
) {
1130 minGroup
= keys
[i
].group
;
1138 KeymapWrapper::IsLatinGroup(guint8 aGroup
)
1142 bool result
= false;
1143 if (gdk_keymap_get_entries_for_keyval(mGdkKeymap
, GDK_a
, &keys
, &count
)) {
1144 for (gint i
= 0; i
< count
; ++i
) {
1145 if (keys
[i
].level
!= 0 && keys
[i
].level
!= 1) {
1148 if (keys
[i
].group
== aGroup
) {
1159 KeymapWrapper::IsAutoRepeatableKey(guint aHardwareKeyCode
)
1161 uint8_t indexOfArray
= aHardwareKeyCode
/ 8;
1162 MOZ_ASSERT(indexOfArray
< ArrayLength(mKeyboardState
.auto_repeats
),
1164 char bitMask
= 1 << (aHardwareKeyCode
% 8);
1165 return (mKeyboardState
.auto_repeats
[indexOfArray
] & bitMask
) != 0;
1169 KeymapWrapper::IsBasicLatinLetterOrNumeral(uint32_t aCharCode
)
1171 return (aCharCode
>= 'a' && aCharCode
<= 'z') ||
1172 (aCharCode
>= 'A' && aCharCode
<= 'Z') ||
1173 (aCharCode
>= '0' && aCharCode
<= '9');
1177 KeymapWrapper::GetGDKKeyvalWithoutModifier(const GdkEventKey
*aGdkKeyEvent
)
1179 KeymapWrapper
* keymapWrapper
= GetInstance();
1181 (aGdkKeyEvent
->state
& keymapWrapper
->GetModifierMask(NUM_LOCK
));
1183 if (!gdk_keymap_translate_keyboard_state(keymapWrapper
->mGdkKeymap
,
1184 aGdkKeyEvent
->hardware_keycode
, GdkModifierType(state
),
1185 aGdkKeyEvent
->group
, &keyval
, nullptr, nullptr, nullptr)) {
1191 /* static */ uint32_t
1192 KeymapWrapper::GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval
)
1194 switch (aGdkKeyval
) {
1195 case GDK_Cancel
: return NS_VK_CANCEL
;
1196 case GDK_BackSpace
: return NS_VK_BACK
;
1198 case GDK_ISO_Left_Tab
: return NS_VK_TAB
;
1199 case GDK_Clear
: return NS_VK_CLEAR
;
1200 case GDK_Return
: return NS_VK_RETURN
;
1203 case GDK_Shift_Lock
: return NS_VK_SHIFT
;
1205 case GDK_Control_R
: return NS_VK_CONTROL
;
1207 case GDK_Alt_R
: return NS_VK_ALT
;
1209 case GDK_Meta_R
: return NS_VK_META
;
1211 // Assume that Super or Hyper is always mapped to physical Win key.
1215 case GDK_Hyper_R
: return NS_VK_WIN
;
1217 // GTK's AltGraph key is similar to Mac's Option (Alt) key. However,
1218 // unfortunately, browsers on Mac are using NS_VK_ALT for it even though
1219 // it's really different from Alt key on Windows.
1220 // On the other hand, GTK's AltGrapsh keys are really different from
1221 // Alt key. However, there is no AltGrapsh key on Windows. On Windows,
1222 // both Ctrl and Alt keys are pressed internally when AltGr key is
1223 // pressed. For some languages' users, AltGraph key is important, so,
1224 // web applications on such locale may want to know AltGraph key press.
1225 // Therefore, we should map AltGr keycode for them only on GTK.
1226 case GDK_ISO_Level3_Shift
:
1227 case GDK_ISO_Level5_Shift
:
1228 // We assume that Mode_switch is always used for level3 shift.
1229 case GDK_Mode_switch
: return NS_VK_ALTGR
;
1231 case GDK_Pause
: return NS_VK_PAUSE
;
1232 case GDK_Caps_Lock
: return NS_VK_CAPS_LOCK
;
1234 case GDK_Kana_Shift
: return NS_VK_KANA
;
1235 case GDK_Hangul
: return NS_VK_HANGUL
;
1236 // case GDK_XXX: return NS_VK_JUNJA;
1237 // case GDK_XXX: return NS_VK_FINAL;
1238 case GDK_Hangul_Hanja
: return NS_VK_HANJA
;
1239 case GDK_Kanji
: return NS_VK_KANJI
;
1240 case GDK_Escape
: return NS_VK_ESCAPE
;
1241 case GDK_Henkan
: return NS_VK_CONVERT
;
1242 case GDK_Muhenkan
: return NS_VK_NONCONVERT
;
1243 // case GDK_XXX: return NS_VK_ACCEPT;
1244 // case GDK_XXX: return NS_VK_MODECHANGE;
1245 case GDK_Page_Up
: return NS_VK_PAGE_UP
;
1246 case GDK_Page_Down
: return NS_VK_PAGE_DOWN
;
1247 case GDK_End
: return NS_VK_END
;
1248 case GDK_Home
: return NS_VK_HOME
;
1249 case GDK_Left
: return NS_VK_LEFT
;
1250 case GDK_Up
: return NS_VK_UP
;
1251 case GDK_Right
: return NS_VK_RIGHT
;
1252 case GDK_Down
: return NS_VK_DOWN
;
1253 case GDK_Select
: return NS_VK_SELECT
;
1254 case GDK_Print
: return NS_VK_PRINT
;
1255 case GDK_Execute
: return NS_VK_EXECUTE
;
1256 case GDK_Insert
: return NS_VK_INSERT
;
1257 case GDK_Delete
: return NS_VK_DELETE
;
1258 case GDK_Help
: return NS_VK_HELP
;
1261 case GDK_KP_Left
: return NS_VK_LEFT
;
1262 case GDK_KP_Right
: return NS_VK_RIGHT
;
1263 case GDK_KP_Up
: return NS_VK_UP
;
1264 case GDK_KP_Down
: return NS_VK_DOWN
;
1265 case GDK_KP_Page_Up
: return NS_VK_PAGE_UP
;
1266 // Not sure what these are
1267 // case GDK_KP_Prior: return NS_VK_;
1268 // case GDK_KP_Next: return NS_VK_;
1269 case GDK_KP_Begin
: return NS_VK_CLEAR
; // Num-unlocked 5
1270 case GDK_KP_Page_Down
: return NS_VK_PAGE_DOWN
;
1271 case GDK_KP_Home
: return NS_VK_HOME
;
1272 case GDK_KP_End
: return NS_VK_END
;
1273 case GDK_KP_Insert
: return NS_VK_INSERT
;
1274 case GDK_KP_Delete
: return NS_VK_DELETE
;
1275 case GDK_KP_Enter
: return NS_VK_RETURN
;
1277 case GDK_Num_Lock
: return NS_VK_NUM_LOCK
;
1278 case GDK_Scroll_Lock
: return NS_VK_SCROLL_LOCK
;
1281 case GDK_F1
: return NS_VK_F1
;
1282 case GDK_F2
: return NS_VK_F2
;
1283 case GDK_F3
: return NS_VK_F3
;
1284 case GDK_F4
: return NS_VK_F4
;
1285 case GDK_F5
: return NS_VK_F5
;
1286 case GDK_F6
: return NS_VK_F6
;
1287 case GDK_F7
: return NS_VK_F7
;
1288 case GDK_F8
: return NS_VK_F8
;
1289 case GDK_F9
: return NS_VK_F9
;
1290 case GDK_F10
: return NS_VK_F10
;
1291 case GDK_F11
: return NS_VK_F11
;
1292 case GDK_F12
: return NS_VK_F12
;
1293 case GDK_F13
: return NS_VK_F13
;
1294 case GDK_F14
: return NS_VK_F14
;
1295 case GDK_F15
: return NS_VK_F15
;
1296 case GDK_F16
: return NS_VK_F16
;
1297 case GDK_F17
: return NS_VK_F17
;
1298 case GDK_F18
: return NS_VK_F18
;
1299 case GDK_F19
: return NS_VK_F19
;
1300 case GDK_F20
: return NS_VK_F20
;
1301 case GDK_F21
: return NS_VK_F21
;
1302 case GDK_F22
: return NS_VK_F22
;
1303 case GDK_F23
: return NS_VK_F23
;
1304 case GDK_F24
: return NS_VK_F24
;
1306 // context menu key, keysym 0xff67, typically keycode 117 on 105-key
1307 // (Microsoft) x86 keyboards, located between right 'Windows' key and
1309 case GDK_Menu
: return NS_VK_CONTEXT_MENU
;
1310 case GDK_Sleep
: return NS_VK_SLEEP
;
1312 case GDK_3270_Attn
: return NS_VK_ATTN
;
1313 case GDK_3270_CursorSelect
: return NS_VK_CRSEL
;
1314 case GDK_3270_ExSelect
: return NS_VK_EXSEL
;
1315 case GDK_3270_EraseEOF
: return NS_VK_EREOF
;
1316 case GDK_3270_Play
: return NS_VK_PLAY
;
1317 // case GDK_XXX: return NS_VK_ZOOM;
1318 case GDK_3270_PA1
: return NS_VK_PA1
;
1320 // map Sun Keyboard special keysyms on to NS_VK keys
1322 // Sun F11 key generates SunF36(0x1005ff10) keysym
1323 case 0x1005ff10: return NS_VK_F11
;
1324 // Sun F12 key generates SunF37(0x1005ff11) keysym
1325 case 0x1005ff11: return NS_VK_F12
;
1331 KeymapWrapper::InitKeypressEvent(WidgetKeyboardEvent
& aKeyEvent
,
1332 GdkEventKey
* aGdkKeyEvent
)
1334 NS_ENSURE_TRUE_VOID(aKeyEvent
.message
== NS_KEY_PRESS
);
1336 aKeyEvent
.charCode
= GetCharCodeFor(aGdkKeyEvent
);
1337 if (!aKeyEvent
.charCode
) {
1338 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
1339 ("KeymapWrapper(%p): InitKeypressEvent, "
1340 "keyCode=0x%02X, charCode=0x%08X",
1341 this, aKeyEvent
.keyCode
, aKeyEvent
.charCode
));
1345 // If the event causes inputting a character, keyCode must be zero.
1346 aKeyEvent
.keyCode
= 0;
1348 // If Ctrl or Alt or Meta or OS is pressed, we need to append the key
1349 // details for handling shortcut key. Otherwise, we have no additional
1351 if (!aKeyEvent
.IsControl() && !aKeyEvent
.IsAlt() &&
1352 !aKeyEvent
.IsMeta() && !aKeyEvent
.IsOS()) {
1353 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
1354 ("KeymapWrapper(%p): InitKeypressEvent, "
1355 "keyCode=0x%02X, charCode=0x%08X",
1356 this, aKeyEvent
.keyCode
, aKeyEvent
.charCode
));
1360 gint level
= GetKeyLevel(aGdkKeyEvent
);
1361 if (level
!= 0 && level
!= 1) {
1362 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
1363 ("KeymapWrapper(%p): InitKeypressEvent, "
1364 "keyCode=0x%02X, charCode=0x%08X, level=%d",
1365 this, aKeyEvent
.keyCode
, aKeyEvent
.charCode
, level
));
1369 guint baseState
= aGdkKeyEvent
->state
&
1370 ~(GetModifierMask(SHIFT
) | GetModifierMask(CTRL
) |
1371 GetModifierMask(ALT
) | GetModifierMask(META
) |
1372 GetModifierMask(SUPER
) | GetModifierMask(HYPER
));
1374 // We shold send both shifted char and unshifted char, all keyboard layout
1375 // users can use all keys. Don't change event.charCode. On some keyboard
1376 // layouts, Ctrl/Alt/Meta keys are used for inputting some characters.
1377 AlternativeCharCode
altCharCodes(0, 0);
1378 // unshifted charcode of current keyboard layout.
1379 altCharCodes
.mUnshiftedCharCode
=
1380 GetCharCodeFor(aGdkKeyEvent
, baseState
, aGdkKeyEvent
->group
);
1381 bool isLatin
= (altCharCodes
.mUnshiftedCharCode
<= 0xFF);
1382 // shifted charcode of current keyboard layout.
1383 altCharCodes
.mShiftedCharCode
=
1384 GetCharCodeFor(aGdkKeyEvent
,
1385 baseState
| GetModifierMask(SHIFT
),
1386 aGdkKeyEvent
->group
);
1387 isLatin
= isLatin
&& (altCharCodes
.mShiftedCharCode
<= 0xFF);
1388 if (altCharCodes
.mUnshiftedCharCode
|| altCharCodes
.mShiftedCharCode
) {
1389 aKeyEvent
.alternativeCharCodes
.AppendElement(altCharCodes
);
1392 bool needLatinKeyCodes
= !isLatin
;
1393 if (!needLatinKeyCodes
) {
1395 (IS_ASCII_ALPHABETICAL(altCharCodes
.mUnshiftedCharCode
) !=
1396 IS_ASCII_ALPHABETICAL(altCharCodes
.mShiftedCharCode
));
1399 // If current keyboard layout can input Latin characters, we don't need
1400 // more information.
1401 if (!needLatinKeyCodes
) {
1402 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
1403 ("KeymapWrapper(%p): InitKeypressEvent, keyCode=0x%02X, "
1404 "charCode=0x%08X, level=%d, altCharCodes={ "
1405 "mUnshiftedCharCode=0x%08X, mShiftedCharCode=0x%08X }",
1406 this, aKeyEvent
.keyCode
, aKeyEvent
.charCode
, level
,
1407 altCharCodes
.mUnshiftedCharCode
, altCharCodes
.mShiftedCharCode
));
1411 // Next, find Latin inputtable keyboard layout.
1412 gint minGroup
= GetFirstLatinGroup();
1414 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
1415 ("KeymapWrapper(%p): InitKeypressEvent, "
1416 "Latin keyboard layout isn't found: "
1417 "keyCode=0x%02X, charCode=0x%08X, level=%d, "
1418 "altCharCodes={ mUnshiftedCharCode=0x%08X, "
1419 "mShiftedCharCode=0x%08X }",
1420 this, aKeyEvent
.keyCode
, aKeyEvent
.charCode
, level
,
1421 altCharCodes
.mUnshiftedCharCode
, altCharCodes
.mShiftedCharCode
));
1425 AlternativeCharCode
altLatinCharCodes(0, 0);
1426 uint32_t unmodifiedCh
=
1427 aKeyEvent
.IsShift() ? altCharCodes
.mShiftedCharCode
:
1428 altCharCodes
.mUnshiftedCharCode
;
1430 // unshifted charcode of found keyboard layout.
1431 uint32_t ch
= GetCharCodeFor(aGdkKeyEvent
, baseState
, minGroup
);
1432 altLatinCharCodes
.mUnshiftedCharCode
=
1433 IsBasicLatinLetterOrNumeral(ch
) ? ch
: 0;
1434 // shifted charcode of found keyboard layout.
1435 ch
= GetCharCodeFor(aGdkKeyEvent
,
1436 baseState
| GetModifierMask(SHIFT
),
1438 altLatinCharCodes
.mShiftedCharCode
=
1439 IsBasicLatinLetterOrNumeral(ch
) ? ch
: 0;
1440 if (altLatinCharCodes
.mUnshiftedCharCode
||
1441 altLatinCharCodes
.mShiftedCharCode
) {
1442 aKeyEvent
.alternativeCharCodes
.AppendElement(altLatinCharCodes
);
1444 // If the charCode is not Latin, and the level is 0 or 1, we should
1445 // replace the charCode to Latin char if Alt and Meta keys are not
1446 // pressed. (Alt should be sent the localized char for accesskey
1447 // like handling of Web Applications.)
1448 ch
= aKeyEvent
.IsShift() ? altLatinCharCodes
.mShiftedCharCode
:
1449 altLatinCharCodes
.mUnshiftedCharCode
;
1450 if (ch
&& !(aKeyEvent
.IsAlt() || aKeyEvent
.IsMeta()) &&
1451 aKeyEvent
.charCode
== unmodifiedCh
) {
1452 aKeyEvent
.charCode
= ch
;
1455 PR_LOG(gKeymapWrapperLog
, PR_LOG_ALWAYS
,
1456 ("KeymapWrapper(%p): InitKeypressEvent, "
1457 "keyCode=0x%02X, charCode=0x%08X, level=%d, minGroup=%d, "
1458 "altCharCodes={ mUnshiftedCharCode=0x%08X, "
1459 "mShiftedCharCode=0x%08X } "
1460 "altLatinCharCodes={ mUnshiftedCharCode=0x%08X, "
1461 "mShiftedCharCode=0x%08X }",
1462 this, aKeyEvent
.keyCode
, aKeyEvent
.charCode
, level
, minGroup
,
1463 altCharCodes
.mUnshiftedCharCode
, altCharCodes
.mShiftedCharCode
,
1464 altLatinCharCodes
.mUnshiftedCharCode
,
1465 altLatinCharCodes
.mShiftedCharCode
));
1469 KeymapWrapper::IsKeyPressEventNecessary(GdkEventKey
* aGdkKeyEvent
)
1471 // If this is a modifier key event, we shouldn't send keypress event.
1472 switch (ComputeDOMKeyCode(aGdkKeyEvent
)) {
1478 case NS_VK_CAPS_LOCK
:
1479 case NS_VK_NUM_LOCK
:
1480 case NS_VK_SCROLL_LOCK
:
1487 } // namespace widget
1488 } // namespace mozilla