/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* 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 "nsTArray.h" #include "mozilla/EventForwards.h" #include <gdk/gdk.h> #include <X11/XKBlib.h> 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. */ 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); /** * 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); /** * 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. */ static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, 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); /** * Destroys the singleton KeymapWrapper instance, if it exists. */ static void Shutdown(); protected: /** * GetInstance() returns a KeymapWrapper instance. * * @return A singleton instance of KeymapWrapper. */ static KeymapWrapper* GetInstance(); KeymapWrapper(); ~KeymapWrapper(); bool mInitialized; /** * Initializing methods. */ void Init(); void InitXKBExtension(); void InitBySystemSettings(); /** * 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); /** * mGdkKeymap is a wrapped instance by this class. */ GdkKeymap* mGdkKeymap; /** * The base event code of XKB extension. */ int mXKBBaseEventCode; /** * 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; /** * Pointer of the singleton instance. */ static KeymapWrapper* sInstance; /** * Auto key repeat management. */ static guint sLastRepeatableHardwareKeyCode; 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); /** * 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); /** * 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); /** * 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); /** * See the document of WillDispatchKeyboardEvent(). */ void WillDispatchKeyboardEventInternal(WidgetKeyboardEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent); }; } // namespace widget } // namespace mozilla #endif /* __nsGdkKeyUtils_h__ */