summaryrefslogtreecommitdiffstats
path: root/widget/gtk/nsGtkKeyUtils.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/gtk/nsGtkKeyUtils.h515
1 files changed, 515 insertions, 0 deletions
diff --git a/widget/gtk/nsGtkKeyUtils.h b/widget/gtk/nsGtkKeyUtils.h
new file mode 100644
index 0000000000..c5c8096934
--- /dev/null
+++ b/widget/gtk/nsGtkKeyUtils.h
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __nsGdkKeyUtils_h__
+#define __nsGdkKeyUtils_h__
+
+#include "mozilla/EventForwards.h"
+#include "nsIWidget.h"
+#include "nsTArray.h"
+
+#include <gdk/gdk.h>
+#ifdef MOZ_X11
+# include <X11/XKBlib.h>
+#endif
+#ifdef MOZ_WAYLAND
+# include <gdk/gdkwayland.h>
+# include <xkbcommon/xkbcommon.h>
+#endif
+#include "X11UndefineNone.h"
+
+class nsWindow;
+
+namespace mozilla {
+namespace widget {
+
+/**
+ * KeymapWrapper is a wrapper class of GdkKeymap. GdkKeymap doesn't support
+ * all our needs, therefore, we need to access lower level APIs.
+ * But such code is usually complex and might be slow. Against such issues,
+ * we should cache some information.
+ *
+ * This class provides only static methods. The methods is using internal
+ * singleton instance which is initialized by default GdkKeymap. When the
+ * GdkKeymap is destroyed, the singleton instance will be destroyed.
+ */
+
+class KeymapWrapper {
+ public:
+ /**
+ * Compute an our DOM keycode from a GDK keyval.
+ */
+ static uint32_t ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * Compute a DOM key name index from aGdkKeyEvent.
+ */
+ static KeyNameIndex ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * Compute a DOM code name index from aGdkKeyEvent.
+ */
+ static CodeNameIndex ComputeDOMCodeNameIndex(const GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * Modifier is list of modifiers which we support in widget level.
+ */
+ enum Modifier {
+ NOT_MODIFIER = 0x0000,
+ CAPS_LOCK = 0x0001,
+ NUM_LOCK = 0x0002,
+ SCROLL_LOCK = 0x0004,
+ SHIFT = 0x0008,
+ CTRL = 0x0010,
+ ALT = 0x0020,
+ META = 0x0040,
+ SUPER = 0x0080,
+ HYPER = 0x0100,
+ LEVEL3 = 0x0200,
+ LEVEL5 = 0x0400
+ };
+
+ /**
+ * Modifiers is used for combination of Modifier.
+ * E.g., |Modifiers modifiers = (SHIFT | CTRL);| means Shift and Ctrl.
+ */
+ typedef uint32_t Modifiers;
+
+ /**
+ * GetCurrentModifierState() returns current modifier key state.
+ * The "current" means actual state of hardware keyboard when this is
+ * called. I.e., if some key events are not still dispatched by GDK,
+ * the state may mismatch with GdkEventKey::state.
+ *
+ * @return Current modifier key state.
+ */
+ static guint GetCurrentModifierState();
+
+ /**
+ * AreModifiersCurrentlyActive() checks the "current" modifier state
+ * on aGdkWindow with the keymap of the singleton instance.
+ *
+ * @param aModifiers One or more of Modifier values except
+ * NOT_MODIFIER.
+ * @return TRUE if all of modifieres in aModifiers are
+ * active. Otherwise, FALSE.
+ */
+ static bool AreModifiersCurrentlyActive(Modifiers aModifiers);
+
+ /**
+ * Utility function to compute current keyboard modifiers for
+ * WidgetInputEvent
+ */
+ static uint32_t ComputeCurrentKeyModifiers();
+
+ /**
+ * Utility function to covert platform modifier state to keyboard modifiers
+ * of WidgetInputEvent
+ */
+ static uint32_t ComputeKeyModifiers(guint aModifierState);
+
+ /**
+ * Convert native modifiers for `nsIWidget::SynthesizeNative*()` to
+ * GDK's state.
+ */
+ static guint ConvertWidgetModifierToGdkState(
+ nsIWidget::Modifiers aNativeModifiers);
+
+ /**
+ * InitInputEvent() initializes the aInputEvent with aModifierState.
+ */
+ static void InitInputEvent(WidgetInputEvent& aInputEvent,
+ guint aModifierState);
+
+ /**
+ * InitKeyEvent() intializes aKeyEvent's modifier key related members
+ * and keycode related values.
+ *
+ * @param aKeyEvent It's an WidgetKeyboardEvent which needs to be
+ * initialized.
+ * @param aGdkKeyEvent A native GDK key event.
+ * @param aIsProcessedByIME true if aGdkKeyEvent is handled by IME.
+ */
+ static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
+ GdkEventKey* aGdkKeyEvent, bool aIsProcessedByIME);
+
+ /**
+ * DispatchKeyDownOrKeyUpEvent() dispatches eKeyDown or eKeyUp event.
+ *
+ * @param aWindow The window to dispatch a keyboard event.
+ * @param aGdkKeyEvent A native GDK_KEY_PRESS or GDK_KEY_RELEASE
+ * event.
+ * @param aIsProcessedByIME true if the event is handled by IME.
+ * @param aIsCancelled [Out] true if the default is prevented.
+ * @return true if eKeyDown event is actually dispatched.
+ * Otherwise, false.
+ */
+ static bool DispatchKeyDownOrKeyUpEvent(nsWindow* aWindow,
+ GdkEventKey* aGdkKeyEvent,
+ bool aIsProcessedByIME,
+ bool* aIsCancelled);
+
+ /**
+ * DispatchKeyDownOrKeyUpEvent() dispatches eKeyDown or eKeyUp event.
+ *
+ * @param aWindow The window to dispatch aKeyboardEvent.
+ * @param aKeyboardEvent An eKeyDown or eKeyUp event. This will be
+ * dispatched as is.
+ * @param aIsCancelled [Out] true if the default is prevented.
+ * @return true if eKeyDown event is actually dispatched.
+ * Otherwise, false.
+ */
+ static bool DispatchKeyDownOrKeyUpEvent(nsWindow* aWindow,
+ WidgetKeyboardEvent& aKeyboardEvent,
+ bool* aIsCancelled);
+
+ /**
+ * GDK_KEY_PRESS event handler.
+ *
+ * @param aWindow The window to dispatch eKeyDown event (and maybe
+ * eKeyPress events).
+ * @param aGdkKeyEvent Receivied GDK_KEY_PRESS event.
+ */
+ static void HandleKeyPressEvent(nsWindow* aWindow, GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * GDK_KEY_RELEASE event handler.
+ *
+ * @param aWindow The window to dispatch eKeyUp event.
+ * @param aGdkKeyEvent Receivied GDK_KEY_RELEASE event.
+ * @return true if an event is dispatched. Otherwise, false.
+ */
+ static bool HandleKeyReleaseEvent(nsWindow* aWindow,
+ GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * WillDispatchKeyboardEvent() is called via
+ * TextEventDispatcherListener::WillDispatchKeyboardEvent().
+ *
+ * @param aKeyEvent An instance of KeyboardEvent which will be
+ * dispatched. This method should set charCode
+ * and alternative char codes if it's necessary.
+ * @param aGdkKeyEvent A GdkEventKey instance which caused the
+ * aKeyEvent.
+ */
+ static void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyEvent,
+ GdkEventKey* aGdkKeyEvent);
+
+#ifdef MOZ_WAYLAND
+ /**
+ * Utility function to set all supported modifier masks
+ * from xkb_keymap. We call that from Wayland backend routines.
+ */
+ static void SetModifierMasks(xkb_keymap* aKeymap);
+
+ /**
+ * Wayland global focus handlers
+ */
+ static void SetFocusIn(wl_surface* aFocusSurface, uint32_t aFocusSerial);
+ static void SetFocusOut(wl_surface* aFocusSurface);
+ static void GetFocusInfo(wl_surface** aFocusSurface, uint32_t* aFocusSerial);
+
+ static void SetSeat(wl_seat* aSeat, int aId);
+ static void ClearSeat(int aId);
+ static wl_seat* GetSeat();
+
+ static void SetKeyboard(wl_keyboard* aKeyboard);
+ static wl_keyboard* GetKeyboard();
+ static void ClearKeyboard();
+
+ /**
+ * EnsureInstance() is provided on Wayland to register Wayland callbacks
+ * early.
+ */
+ static void EnsureInstance();
+#endif
+
+ /**
+ * ResetKeyboard is called on keymap changes from OnKeysChanged and
+ * keyboard_handle_keymap to prepare for keymap changes.
+ */
+ static void ResetKeyboard();
+
+ /**
+ * Destroys the singleton KeymapWrapper instance, if it exists.
+ */
+ static void Shutdown();
+
+ private:
+ /**
+ * GetInstance() returns a KeymapWrapper instance.
+ *
+ * @return A singleton instance of KeymapWrapper.
+ */
+ static KeymapWrapper* GetInstance();
+
+ KeymapWrapper();
+ ~KeymapWrapper();
+
+ bool mInitialized;
+
+ /**
+ * Initializing methods.
+ */
+ void Init();
+#ifdef MOZ_X11
+ void InitXKBExtension();
+ void InitBySystemSettingsX11();
+#endif
+#ifdef MOZ_WAYLAND
+ void InitBySystemSettingsWayland();
+#endif
+
+ /**
+ * mModifierKeys stores each hardware key information.
+ */
+ struct ModifierKey {
+ guint mHardwareKeycode;
+ guint mMask;
+
+ explicit ModifierKey(guint aHardwareKeycode)
+ : mHardwareKeycode(aHardwareKeycode), mMask(0) {}
+ };
+ nsTArray<ModifierKey> mModifierKeys;
+
+ /**
+ * GetModifierKey() returns modifier key information of the hardware
+ * keycode. If the key isn't a modifier key, returns nullptr.
+ */
+ ModifierKey* GetModifierKey(guint aHardwareKeycode);
+
+ /**
+ * mModifierMasks is bit masks for each modifier. The index should be one
+ * of ModifierIndex values.
+ */
+ enum ModifierIndex {
+ INDEX_NUM_LOCK,
+ INDEX_SCROLL_LOCK,
+ INDEX_ALT,
+ INDEX_META,
+ INDEX_SUPER,
+ INDEX_HYPER,
+ INDEX_LEVEL3,
+ INDEX_LEVEL5,
+ COUNT_OF_MODIFIER_INDEX
+ };
+ guint mModifierMasks[COUNT_OF_MODIFIER_INDEX];
+
+ guint GetModifierMask(Modifier aModifier) const;
+
+ /**
+ * @param aGdkKeyval A GDK defined modifier key value such as
+ * GDK_Shift_L.
+ * @return Returns Modifier values for aGdkKeyval.
+ * If the given key code isn't a modifier key,
+ * returns NOT_MODIFIER.
+ */
+ static Modifier GetModifierForGDKKeyval(guint aGdkKeyval);
+
+ static const char* GetModifierName(Modifier aModifier);
+
+ /**
+ * AreModifiersActive() just checks whether aModifierState indicates
+ * all modifiers in aModifiers are active or not.
+ *
+ * @param aModifiers One or more of Modifier values except
+ * NOT_MODIFIER.
+ * @param aModifierState GDK's modifier states.
+ * @return TRUE if aGdkModifierType indecates all of
+ * modifiers in aModifier are active.
+ * Otherwise, FALSE.
+ */
+ static bool AreModifiersActive(Modifiers aModifiers, guint aModifierState);
+
+ /**
+ * mGdkKeymap is a wrapped instance by this class.
+ */
+ GdkKeymap* mGdkKeymap;
+
+ /**
+ * The base event code of XKB extension.
+ */
+ int mXKBBaseEventCode;
+
+#ifdef MOZ_X11
+ /**
+ * Only auto_repeats[] stores valid value. If you need to use other
+ * members, you need to listen notification events for them.
+ * See a call of XkbSelectEventDetails() with XkbControlsNotify in
+ * InitXKBExtension().
+ */
+ XKeyboardState mKeyboardState;
+#endif
+
+ /**
+ * Pointer of the singleton instance.
+ */
+ static KeymapWrapper* sInstance;
+
+ /**
+ * Auto key repeat management.
+ */
+ static guint sLastRepeatableHardwareKeyCode;
+#ifdef MOZ_X11
+ static Time sLastRepeatableKeyTime;
+#endif
+ enum RepeatState { NOT_PRESSED, FIRST_PRESS, REPEATING };
+ static RepeatState sRepeatState;
+
+ /**
+ * IsAutoRepeatableKey() returns true if the key supports auto repeat.
+ * Otherwise, false.
+ */
+ bool IsAutoRepeatableKey(guint aHardwareKeyCode);
+
+ /**
+ * Signal handlers.
+ */
+ static void OnKeysChanged(GdkKeymap* aKeymap, KeymapWrapper* aKeymapWrapper);
+ static void OnDirectionChanged(GdkKeymap* aGdkKeymap,
+ KeymapWrapper* aKeymapWrapper);
+
+ gulong mOnKeysChangedSignalHandle;
+ gulong mOnDirectionChangedSignalHandle;
+
+ /**
+ * GetCharCodeFor() Computes what character is inputted by the key event
+ * with aModifierState and aGroup.
+ *
+ * @param aGdkKeyEvent Native key event, must not be nullptr.
+ * @param aModifierState Combination of GdkModifierType which you
+ * want to test with aGdkKeyEvent.
+ * @param aGroup Set group in the mGdkKeymap.
+ * @return charCode which is inputted by aGdkKeyEvent.
+ * If failed, this returns 0.
+ */
+ static uint32_t GetCharCodeFor(const GdkEventKey* aGdkKeyEvent);
+ uint32_t GetCharCodeFor(const GdkEventKey* aGdkKeyEvent, guint aModifierState,
+ gint aGroup);
+
+ /**
+ * GetUnmodifiedCharCodeFor() computes what character is inputted by the
+ * key event without Ctrl/Alt/Meta/Super/Hyper modifiers.
+ * If Level3 or Level5 Shift causes no character input, this also ignores
+ * them.
+ *
+ * @param aGdkKeyEvent Native key event, must not be nullptr.
+ * @return charCode which is computed without modifiers
+ * which prevent text input.
+ */
+ uint32_t GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * GetKeyLevel() returns level of the aGdkKeyEvent in mGdkKeymap.
+ *
+ * @param aGdkKeyEvent Native key event, must not be nullptr.
+ * @return Using level. Typically, this is 0 or 1.
+ * If failed, this returns -1.
+ */
+ gint GetKeyLevel(GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * GetFirstLatinGroup() returns group of mGdkKeymap which can input an
+ * ASCII character by GDK_A.
+ *
+ * @return group value of GdkEventKey.
+ */
+ gint GetFirstLatinGroup();
+
+ /**
+ * IsLatinGroup() checkes whether the keyboard layout of aGroup is
+ * ASCII alphabet inputtable or not.
+ *
+ * @param aGroup The group value of GdkEventKey.
+ * @return TRUE if the keyboard layout can input
+ * ASCII alphabet. Otherwise, FALSE.
+ */
+ bool IsLatinGroup(guint8 aGroup);
+
+ /**
+ * IsBasicLatinLetterOrNumeral() Checks whether the aCharCode is an
+ * alphabet or a numeric character in ASCII.
+ *
+ * @param aCharCode Charcode which you want to test.
+ * @return TRUE if aCharCode is an alphabet or a numeric
+ * in ASCII range. Otherwise, FALSE.
+ */
+ static bool IsBasicLatinLetterOrNumeral(uint32_t aCharCode);
+
+ /**
+ * IsPrintableASCIICharacter() checks whether the aCharCode is a printable
+ * ASCII character. I.e., returns false if aCharCode is a control
+ * character even in an ASCII character.
+ */
+ static bool IsPrintableASCIICharacter(uint32_t aCharCode) {
+ return aCharCode >= 0x20 && aCharCode <= 0x7E;
+ }
+
+ /**
+ * GetGDKKeyvalWithoutModifier() returns the keyval for aGdkKeyEvent when
+ * ignoring the modifier state except NumLock. (NumLock is a key to change
+ * some key's meaning.)
+ */
+ static guint GetGDKKeyvalWithoutModifier(const GdkEventKey* aGdkKeyEvent);
+
+ /**
+ * GetDOMKeyCodeFromKeyPairs() returns DOM keycode for aGdkKeyval if
+ * it's in KeyPair table.
+ */
+ static uint32_t GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval);
+
+#ifdef MOZ_X11
+ /**
+ * FilterEvents() listens all events on all our windows.
+ * Be careful, this may make damage to performance if you add expensive
+ * code in this method.
+ */
+ static GdkFilterReturn FilterEvents(GdkXEvent* aXEvent, GdkEvent* aGdkEvent,
+ gpointer aData);
+#endif
+
+ /**
+ * MaybeDispatchContextMenuEvent() may dispatch eContextMenu event if
+ * the given key combination should cause opening context menu.
+ *
+ * @param aWindow The window to dispatch a contextmenu event.
+ * @param aEvent The native key event.
+ * @return true if this method dispatched eContextMenu
+ * event. Otherwise, false.
+ * Be aware, when this returns true, the
+ * widget may have been destroyed.
+ */
+ static bool MaybeDispatchContextMenuEvent(nsWindow* aWindow,
+ const GdkEventKey* aEvent);
+
+ /**
+ * See the document of WillDispatchKeyboardEvent().
+ */
+ void WillDispatchKeyboardEventInternal(WidgetKeyboardEvent& aKeyEvent,
+ GdkEventKey* aGdkKeyEvent);
+
+#ifdef MOZ_WAYLAND
+ /**
+ * Utility function to set Xkb modifier key mask.
+ */
+ void SetModifierMask(xkb_keymap* aKeymap, ModifierIndex aModifierIndex,
+ const char* aModifierName);
+#endif
+
+#ifdef MOZ_WAYLAND
+ static wl_seat* sSeat;
+ static int sSeatID;
+ static wl_keyboard* sKeyboard;
+ wl_surface* mFocusSurface = nullptr;
+ uint32_t mFocusSerial = 0;
+#endif
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif /* __nsGdkKeyUtils_h__ */