michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim:expandtab:shiftwidth=4:tabstop=4: michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef __nsGdkKeyUtils_h__ michael@0: #define __nsGdkKeyUtils_h__ michael@0: michael@0: #include "nsTArray.h" michael@0: #include "mozilla/EventForwards.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: michael@0: /** michael@0: * KeymapWrapper is a wrapper class of GdkKeymap. GdkKeymap doesn't support michael@0: * all our needs, therefore, we need to access lower level APIs. michael@0: * But such code is usually complex and might be slow. Against such issues, michael@0: * we should cache some information. michael@0: * michael@0: * This class provides only static methods. The methods is using internal michael@0: * singleton instance which is initialized by default GdkKeymap. When the michael@0: * GdkKeymap is destroyed, the singleton instance will be destroyed. michael@0: */ michael@0: michael@0: class KeymapWrapper michael@0: { michael@0: public: michael@0: /** michael@0: * Compute an our DOM keycode from a GDK keyval. michael@0: */ michael@0: static uint32_t ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent); michael@0: michael@0: /** michael@0: * Compute a DOM key name index from aGdkKeyEvent. michael@0: */ michael@0: KeyNameIndex ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent); michael@0: michael@0: /** michael@0: * Modifier is list of modifiers which we support in widget level. michael@0: */ michael@0: enum Modifier { michael@0: NOT_MODIFIER = 0x0000, michael@0: CAPS_LOCK = 0x0001, michael@0: NUM_LOCK = 0x0002, michael@0: SCROLL_LOCK = 0x0004, michael@0: SHIFT = 0x0008, michael@0: CTRL = 0x0010, michael@0: ALT = 0x0020, michael@0: META = 0x0040, michael@0: SUPER = 0x0080, michael@0: HYPER = 0x0100, michael@0: LEVEL3 = 0x0200, michael@0: LEVEL5 = 0x0400 michael@0: }; michael@0: michael@0: /** michael@0: * Modifiers is used for combination of Modifier. michael@0: * E.g., |Modifiers modifiers = (SHIFT | CTRL);| means Shift and Ctrl. michael@0: */ michael@0: typedef uint32_t Modifiers; michael@0: michael@0: /** michael@0: * GetCurrentModifierState() returns current modifier key state. michael@0: * The "current" means actual state of hardware keyboard when this is michael@0: * called. I.e., if some key events are not still dispatched by GDK, michael@0: * the state may mismatch with GdkEventKey::state. michael@0: * michael@0: * @return Current modifier key state. michael@0: */ michael@0: static guint GetCurrentModifierState(); michael@0: michael@0: /** michael@0: * AreModifiersCurrentlyActive() checks the "current" modifier state michael@0: * on aGdkWindow with the keymap of the singleton instance. michael@0: * michael@0: * @param aModifiers One or more of Modifier values except michael@0: * NOT_MODIFIER. michael@0: * @return TRUE if all of modifieres in aModifiers are michael@0: * active. Otherwise, FALSE. michael@0: */ michael@0: static bool AreModifiersCurrentlyActive(Modifiers aModifiers); michael@0: michael@0: /** michael@0: * AreModifiersActive() just checks whether aModifierState indicates michael@0: * all modifiers in aModifiers are active or not. michael@0: * michael@0: * @param aModifiers One or more of Modifier values except michael@0: * NOT_MODIFIER. michael@0: * @param aModifierState GDK's modifier states. michael@0: * @return TRUE if aGdkModifierType indecates all of michael@0: * modifiers in aModifier are active. michael@0: * Otherwise, FALSE. michael@0: */ michael@0: static bool AreModifiersActive(Modifiers aModifiers, michael@0: guint aModifierState); michael@0: michael@0: /** michael@0: * InitInputEvent() initializes the aInputEvent with aModifierState. michael@0: */ michael@0: static void InitInputEvent(WidgetInputEvent& aInputEvent, michael@0: guint aModifierState); michael@0: michael@0: /** michael@0: * InitKeyEvent() intializes aKeyEvent's modifier key related members michael@0: * and keycode related values. michael@0: * michael@0: * @param aKeyEvent It's an WidgetKeyboardEvent which needs to be michael@0: * initialized. michael@0: * @param aGdkKeyEvent A native GDK key event. michael@0: */ michael@0: static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, michael@0: GdkEventKey* aGdkKeyEvent); michael@0: michael@0: /** michael@0: * IsKeyPressEventNecessary() returns TRUE when aGdkKeyEvent should cause michael@0: * a DOM keypress event. Otherwise, FALSE. michael@0: */ michael@0: static bool IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent); michael@0: michael@0: protected: michael@0: michael@0: /** michael@0: * GetInstance() returns a KeymapWrapper instance. michael@0: * michael@0: * @return A singleton instance of KeymapWrapper. michael@0: */ michael@0: static KeymapWrapper* GetInstance(); michael@0: michael@0: KeymapWrapper(); michael@0: ~KeymapWrapper(); michael@0: michael@0: bool mInitialized; michael@0: michael@0: /** michael@0: * Initializing methods. michael@0: */ michael@0: void Init(); michael@0: void InitXKBExtension(); michael@0: void InitBySystemSettings(); michael@0: michael@0: /** michael@0: * mModifierKeys stores each hardware key information. michael@0: */ michael@0: struct ModifierKey { michael@0: guint mHardwareKeycode; michael@0: guint mMask; michael@0: michael@0: ModifierKey(guint aHardwareKeycode) : michael@0: mHardwareKeycode(aHardwareKeycode), mMask(0) michael@0: { michael@0: } michael@0: }; michael@0: nsTArray mModifierKeys; michael@0: michael@0: /** michael@0: * GetModifierKey() returns modifier key information of the hardware michael@0: * keycode. If the key isn't a modifier key, returns nullptr. michael@0: */ michael@0: ModifierKey* GetModifierKey(guint aHardwareKeycode); michael@0: michael@0: /** michael@0: * mModifierMasks is bit masks for each modifier. The index should be one michael@0: * of ModifierIndex values. michael@0: */ michael@0: enum ModifierIndex { michael@0: INDEX_NUM_LOCK, michael@0: INDEX_SCROLL_LOCK, michael@0: INDEX_ALT, michael@0: INDEX_META, michael@0: INDEX_SUPER, michael@0: INDEX_HYPER, michael@0: INDEX_LEVEL3, michael@0: INDEX_LEVEL5, michael@0: COUNT_OF_MODIFIER_INDEX michael@0: }; michael@0: guint mModifierMasks[COUNT_OF_MODIFIER_INDEX]; michael@0: michael@0: guint GetModifierMask(Modifier aModifier) const; michael@0: michael@0: /** michael@0: * @param aGdkKeyval A GDK defined modifier key value such as michael@0: * GDK_Shift_L. michael@0: * @return Returns Modifier values for aGdkKeyval. michael@0: * If the given key code isn't a modifier key, michael@0: * returns NOT_MODIFIER. michael@0: */ michael@0: static Modifier GetModifierForGDKKeyval(guint aGdkKeyval); michael@0: michael@0: #ifdef PR_LOGGING michael@0: static const char* GetModifierName(Modifier aModifier); michael@0: #endif // PR_LOGGING michael@0: michael@0: /** michael@0: * mGdkKeymap is a wrapped instance by this class. michael@0: */ michael@0: GdkKeymap* mGdkKeymap; michael@0: michael@0: /** michael@0: * The base event code of XKB extension. michael@0: */ michael@0: int mXKBBaseEventCode; michael@0: michael@0: /** michael@0: * Only auto_repeats[] stores valid value. If you need to use other michael@0: * members, you need to listen notification events for them. michael@0: * See a call of XkbSelectEventDetails() with XkbControlsNotify in michael@0: * InitXKBExtension(). michael@0: */ michael@0: XKeyboardState mKeyboardState; michael@0: michael@0: /** michael@0: * Pointer of the singleton instance. michael@0: */ michael@0: static KeymapWrapper* sInstance; michael@0: michael@0: /** michael@0: * Auto key repeat management. michael@0: */ michael@0: static guint sLastRepeatableHardwareKeyCode; michael@0: enum RepeatState michael@0: { michael@0: NOT_PRESSED, michael@0: FIRST_PRESS, michael@0: REPEATING michael@0: }; michael@0: static RepeatState sRepeatState; michael@0: michael@0: /** michael@0: * IsAutoRepeatableKey() returns true if the key supports auto repeat. michael@0: * Otherwise, false. michael@0: */ michael@0: bool IsAutoRepeatableKey(guint aHardwareKeyCode); michael@0: michael@0: /** michael@0: * Signal handlers. michael@0: */ michael@0: static void OnKeysChanged(GdkKeymap* aKeymap, KeymapWrapper* aKeymapWrapper); michael@0: static void OnDestroyKeymap(KeymapWrapper* aKeymapWrapper, michael@0: GdkKeymap *aGdkKeymap); michael@0: michael@0: /** michael@0: * GetCharCodeFor() Computes what character is inputted by the key event michael@0: * with aModifierState and aGroup. michael@0: * michael@0: * @param aGdkKeyEvent Native key event, must not be nullptr. michael@0: * @param aModifierState Combination of GdkModifierType which you michael@0: * want to test with aGdkKeyEvent. michael@0: * @param aGroup Set group in the mGdkKeymap. michael@0: * @return charCode which is inputted by aGdkKeyEvent. michael@0: * If failed, this returns 0. michael@0: */ michael@0: static uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent); michael@0: uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent, michael@0: guint aModifierState, michael@0: gint aGroup); michael@0: michael@0: /** michael@0: * GetUnmodifiedCharCodeFor() computes what character is inputted by the michael@0: * key event without Ctrl/Alt/Meta/Super/Hyper modifiers. michael@0: * If Level3 or Level5 Shift causes no character input, this also ignores michael@0: * them. michael@0: * michael@0: * @param aGdkKeyEvent Native key event, must not be nullptr. michael@0: * @return charCode which is computed without modifiers michael@0: * which prevent text input. michael@0: */ michael@0: uint32_t GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent); michael@0: michael@0: /** michael@0: * GetKeyLevel() returns level of the aGdkKeyEvent in mGdkKeymap. michael@0: * michael@0: * @param aGdkKeyEvent Native key event, must not be nullptr. michael@0: * @return Using level. Typically, this is 0 or 1. michael@0: * If failed, this returns -1. michael@0: */ michael@0: gint GetKeyLevel(GdkEventKey *aGdkKeyEvent); michael@0: michael@0: /** michael@0: * GetFirstLatinGroup() returns group of mGdkKeymap which can input an michael@0: * ASCII character by GDK_A. michael@0: * michael@0: * @return group value of GdkEventKey. michael@0: */ michael@0: gint GetFirstLatinGroup(); michael@0: michael@0: /** michael@0: * IsLatinGroup() checkes whether the keyboard layout of aGroup is michael@0: * ASCII alphabet inputtable or not. michael@0: * michael@0: * @param aGroup The group value of GdkEventKey. michael@0: * @return TRUE if the keyboard layout can input michael@0: * ASCII alphabet. Otherwise, FALSE. michael@0: */ michael@0: bool IsLatinGroup(guint8 aGroup); michael@0: michael@0: /** michael@0: * IsBasicLatinLetterOrNumeral() Checks whether the aCharCode is an michael@0: * alphabet or a numeric character in ASCII. michael@0: * michael@0: * @param aCharCode Charcode which you want to test. michael@0: * @return TRUE if aCharCode is an alphabet or a numeric michael@0: * in ASCII range. Otherwise, FALSE. michael@0: */ michael@0: static bool IsBasicLatinLetterOrNumeral(uint32_t aCharCode); michael@0: michael@0: /** michael@0: * GetGDKKeyvalWithoutModifier() returns the keyval for aGdkKeyEvent when michael@0: * ignoring the modifier state except NumLock. (NumLock is a key to change michael@0: * some key's meaning.) michael@0: */ michael@0: static guint GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent); michael@0: michael@0: /** michael@0: * GetDOMKeyCodeFromKeyPairs() returns DOM keycode for aGdkKeyval if michael@0: * it's in KeyPair table. michael@0: */ michael@0: static uint32_t GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval); michael@0: michael@0: /** michael@0: * InitKeypressEvent() intializes keyCode, charCode and michael@0: * alternativeCharCodes of keypress event. michael@0: * michael@0: * @param aKeyEvent An NS_KEY_PRESS event, must not be nullptr. michael@0: * The modifier related members and keyCode must michael@0: * be initialized already. michael@0: * @param aGdkKeyEvent A native key event which causes dispatching michael@0: * aKeyEvent. michael@0: */ michael@0: void InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent, michael@0: GdkEventKey* aGdkKeyEvent); michael@0: michael@0: /** michael@0: * FilterEvents() listens all events on all our windows. michael@0: * Be careful, this may make damage to performance if you add expensive michael@0: * code in this method. michael@0: */ michael@0: static GdkFilterReturn FilterEvents(GdkXEvent* aXEvent, michael@0: GdkEvent* aGdkEvent, michael@0: gpointer aData); michael@0: }; michael@0: michael@0: } // namespace widget michael@0: } // namespace mozilla michael@0: michael@0: #endif /* __nsGdkKeyUtils_h__ */