1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gtk/nsGtkKeyUtils.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,351 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim:expandtab:shiftwidth=4:tabstop=4: 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#ifndef __nsGdkKeyUtils_h__ 1.12 +#define __nsGdkKeyUtils_h__ 1.13 + 1.14 +#include "nsTArray.h" 1.15 +#include "mozilla/EventForwards.h" 1.16 + 1.17 +#include <gdk/gdk.h> 1.18 +#include <X11/XKBlib.h> 1.19 + 1.20 +namespace mozilla { 1.21 +namespace widget { 1.22 + 1.23 +/** 1.24 + * KeymapWrapper is a wrapper class of GdkKeymap. GdkKeymap doesn't support 1.25 + * all our needs, therefore, we need to access lower level APIs. 1.26 + * But such code is usually complex and might be slow. Against such issues, 1.27 + * we should cache some information. 1.28 + * 1.29 + * This class provides only static methods. The methods is using internal 1.30 + * singleton instance which is initialized by default GdkKeymap. When the 1.31 + * GdkKeymap is destroyed, the singleton instance will be destroyed. 1.32 + */ 1.33 + 1.34 +class KeymapWrapper 1.35 +{ 1.36 +public: 1.37 + /** 1.38 + * Compute an our DOM keycode from a GDK keyval. 1.39 + */ 1.40 + static uint32_t ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent); 1.41 + 1.42 + /** 1.43 + * Compute a DOM key name index from aGdkKeyEvent. 1.44 + */ 1.45 + KeyNameIndex ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent); 1.46 + 1.47 + /** 1.48 + * Modifier is list of modifiers which we support in widget level. 1.49 + */ 1.50 + enum Modifier { 1.51 + NOT_MODIFIER = 0x0000, 1.52 + CAPS_LOCK = 0x0001, 1.53 + NUM_LOCK = 0x0002, 1.54 + SCROLL_LOCK = 0x0004, 1.55 + SHIFT = 0x0008, 1.56 + CTRL = 0x0010, 1.57 + ALT = 0x0020, 1.58 + META = 0x0040, 1.59 + SUPER = 0x0080, 1.60 + HYPER = 0x0100, 1.61 + LEVEL3 = 0x0200, 1.62 + LEVEL5 = 0x0400 1.63 + }; 1.64 + 1.65 + /** 1.66 + * Modifiers is used for combination of Modifier. 1.67 + * E.g., |Modifiers modifiers = (SHIFT | CTRL);| means Shift and Ctrl. 1.68 + */ 1.69 + typedef uint32_t Modifiers; 1.70 + 1.71 + /** 1.72 + * GetCurrentModifierState() returns current modifier key state. 1.73 + * The "current" means actual state of hardware keyboard when this is 1.74 + * called. I.e., if some key events are not still dispatched by GDK, 1.75 + * the state may mismatch with GdkEventKey::state. 1.76 + * 1.77 + * @return Current modifier key state. 1.78 + */ 1.79 + static guint GetCurrentModifierState(); 1.80 + 1.81 + /** 1.82 + * AreModifiersCurrentlyActive() checks the "current" modifier state 1.83 + * on aGdkWindow with the keymap of the singleton instance. 1.84 + * 1.85 + * @param aModifiers One or more of Modifier values except 1.86 + * NOT_MODIFIER. 1.87 + * @return TRUE if all of modifieres in aModifiers are 1.88 + * active. Otherwise, FALSE. 1.89 + */ 1.90 + static bool AreModifiersCurrentlyActive(Modifiers aModifiers); 1.91 + 1.92 + /** 1.93 + * AreModifiersActive() just checks whether aModifierState indicates 1.94 + * all modifiers in aModifiers are active or not. 1.95 + * 1.96 + * @param aModifiers One or more of Modifier values except 1.97 + * NOT_MODIFIER. 1.98 + * @param aModifierState GDK's modifier states. 1.99 + * @return TRUE if aGdkModifierType indecates all of 1.100 + * modifiers in aModifier are active. 1.101 + * Otherwise, FALSE. 1.102 + */ 1.103 + static bool AreModifiersActive(Modifiers aModifiers, 1.104 + guint aModifierState); 1.105 + 1.106 + /** 1.107 + * InitInputEvent() initializes the aInputEvent with aModifierState. 1.108 + */ 1.109 + static void InitInputEvent(WidgetInputEvent& aInputEvent, 1.110 + guint aModifierState); 1.111 + 1.112 + /** 1.113 + * InitKeyEvent() intializes aKeyEvent's modifier key related members 1.114 + * and keycode related values. 1.115 + * 1.116 + * @param aKeyEvent It's an WidgetKeyboardEvent which needs to be 1.117 + * initialized. 1.118 + * @param aGdkKeyEvent A native GDK key event. 1.119 + */ 1.120 + static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, 1.121 + GdkEventKey* aGdkKeyEvent); 1.122 + 1.123 + /** 1.124 + * IsKeyPressEventNecessary() returns TRUE when aGdkKeyEvent should cause 1.125 + * a DOM keypress event. Otherwise, FALSE. 1.126 + */ 1.127 + static bool IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent); 1.128 + 1.129 +protected: 1.130 + 1.131 + /** 1.132 + * GetInstance() returns a KeymapWrapper instance. 1.133 + * 1.134 + * @return A singleton instance of KeymapWrapper. 1.135 + */ 1.136 + static KeymapWrapper* GetInstance(); 1.137 + 1.138 + KeymapWrapper(); 1.139 + ~KeymapWrapper(); 1.140 + 1.141 + bool mInitialized; 1.142 + 1.143 + /** 1.144 + * Initializing methods. 1.145 + */ 1.146 + void Init(); 1.147 + void InitXKBExtension(); 1.148 + void InitBySystemSettings(); 1.149 + 1.150 + /** 1.151 + * mModifierKeys stores each hardware key information. 1.152 + */ 1.153 + struct ModifierKey { 1.154 + guint mHardwareKeycode; 1.155 + guint mMask; 1.156 + 1.157 + ModifierKey(guint aHardwareKeycode) : 1.158 + mHardwareKeycode(aHardwareKeycode), mMask(0) 1.159 + { 1.160 + } 1.161 + }; 1.162 + nsTArray<ModifierKey> mModifierKeys; 1.163 + 1.164 + /** 1.165 + * GetModifierKey() returns modifier key information of the hardware 1.166 + * keycode. If the key isn't a modifier key, returns nullptr. 1.167 + */ 1.168 + ModifierKey* GetModifierKey(guint aHardwareKeycode); 1.169 + 1.170 + /** 1.171 + * mModifierMasks is bit masks for each modifier. The index should be one 1.172 + * of ModifierIndex values. 1.173 + */ 1.174 + enum ModifierIndex { 1.175 + INDEX_NUM_LOCK, 1.176 + INDEX_SCROLL_LOCK, 1.177 + INDEX_ALT, 1.178 + INDEX_META, 1.179 + INDEX_SUPER, 1.180 + INDEX_HYPER, 1.181 + INDEX_LEVEL3, 1.182 + INDEX_LEVEL5, 1.183 + COUNT_OF_MODIFIER_INDEX 1.184 + }; 1.185 + guint mModifierMasks[COUNT_OF_MODIFIER_INDEX]; 1.186 + 1.187 + guint GetModifierMask(Modifier aModifier) const; 1.188 + 1.189 + /** 1.190 + * @param aGdkKeyval A GDK defined modifier key value such as 1.191 + * GDK_Shift_L. 1.192 + * @return Returns Modifier values for aGdkKeyval. 1.193 + * If the given key code isn't a modifier key, 1.194 + * returns NOT_MODIFIER. 1.195 + */ 1.196 + static Modifier GetModifierForGDKKeyval(guint aGdkKeyval); 1.197 + 1.198 +#ifdef PR_LOGGING 1.199 + static const char* GetModifierName(Modifier aModifier); 1.200 +#endif // PR_LOGGING 1.201 + 1.202 + /** 1.203 + * mGdkKeymap is a wrapped instance by this class. 1.204 + */ 1.205 + GdkKeymap* mGdkKeymap; 1.206 + 1.207 + /** 1.208 + * The base event code of XKB extension. 1.209 + */ 1.210 + int mXKBBaseEventCode; 1.211 + 1.212 + /** 1.213 + * Only auto_repeats[] stores valid value. If you need to use other 1.214 + * members, you need to listen notification events for them. 1.215 + * See a call of XkbSelectEventDetails() with XkbControlsNotify in 1.216 + * InitXKBExtension(). 1.217 + */ 1.218 + XKeyboardState mKeyboardState; 1.219 + 1.220 + /** 1.221 + * Pointer of the singleton instance. 1.222 + */ 1.223 + static KeymapWrapper* sInstance; 1.224 + 1.225 + /** 1.226 + * Auto key repeat management. 1.227 + */ 1.228 + static guint sLastRepeatableHardwareKeyCode; 1.229 + enum RepeatState 1.230 + { 1.231 + NOT_PRESSED, 1.232 + FIRST_PRESS, 1.233 + REPEATING 1.234 + }; 1.235 + static RepeatState sRepeatState; 1.236 + 1.237 + /** 1.238 + * IsAutoRepeatableKey() returns true if the key supports auto repeat. 1.239 + * Otherwise, false. 1.240 + */ 1.241 + bool IsAutoRepeatableKey(guint aHardwareKeyCode); 1.242 + 1.243 + /** 1.244 + * Signal handlers. 1.245 + */ 1.246 + static void OnKeysChanged(GdkKeymap* aKeymap, KeymapWrapper* aKeymapWrapper); 1.247 + static void OnDestroyKeymap(KeymapWrapper* aKeymapWrapper, 1.248 + GdkKeymap *aGdkKeymap); 1.249 + 1.250 + /** 1.251 + * GetCharCodeFor() Computes what character is inputted by the key event 1.252 + * with aModifierState and aGroup. 1.253 + * 1.254 + * @param aGdkKeyEvent Native key event, must not be nullptr. 1.255 + * @param aModifierState Combination of GdkModifierType which you 1.256 + * want to test with aGdkKeyEvent. 1.257 + * @param aGroup Set group in the mGdkKeymap. 1.258 + * @return charCode which is inputted by aGdkKeyEvent. 1.259 + * If failed, this returns 0. 1.260 + */ 1.261 + static uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent); 1.262 + uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent, 1.263 + guint aModifierState, 1.264 + gint aGroup); 1.265 + 1.266 + /** 1.267 + * GetUnmodifiedCharCodeFor() computes what character is inputted by the 1.268 + * key event without Ctrl/Alt/Meta/Super/Hyper modifiers. 1.269 + * If Level3 or Level5 Shift causes no character input, this also ignores 1.270 + * them. 1.271 + * 1.272 + * @param aGdkKeyEvent Native key event, must not be nullptr. 1.273 + * @return charCode which is computed without modifiers 1.274 + * which prevent text input. 1.275 + */ 1.276 + uint32_t GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent); 1.277 + 1.278 + /** 1.279 + * GetKeyLevel() returns level of the aGdkKeyEvent in mGdkKeymap. 1.280 + * 1.281 + * @param aGdkKeyEvent Native key event, must not be nullptr. 1.282 + * @return Using level. Typically, this is 0 or 1. 1.283 + * If failed, this returns -1. 1.284 + */ 1.285 + gint GetKeyLevel(GdkEventKey *aGdkKeyEvent); 1.286 + 1.287 + /** 1.288 + * GetFirstLatinGroup() returns group of mGdkKeymap which can input an 1.289 + * ASCII character by GDK_A. 1.290 + * 1.291 + * @return group value of GdkEventKey. 1.292 + */ 1.293 + gint GetFirstLatinGroup(); 1.294 + 1.295 + /** 1.296 + * IsLatinGroup() checkes whether the keyboard layout of aGroup is 1.297 + * ASCII alphabet inputtable or not. 1.298 + * 1.299 + * @param aGroup The group value of GdkEventKey. 1.300 + * @return TRUE if the keyboard layout can input 1.301 + * ASCII alphabet. Otherwise, FALSE. 1.302 + */ 1.303 + bool IsLatinGroup(guint8 aGroup); 1.304 + 1.305 + /** 1.306 + * IsBasicLatinLetterOrNumeral() Checks whether the aCharCode is an 1.307 + * alphabet or a numeric character in ASCII. 1.308 + * 1.309 + * @param aCharCode Charcode which you want to test. 1.310 + * @return TRUE if aCharCode is an alphabet or a numeric 1.311 + * in ASCII range. Otherwise, FALSE. 1.312 + */ 1.313 + static bool IsBasicLatinLetterOrNumeral(uint32_t aCharCode); 1.314 + 1.315 + /** 1.316 + * GetGDKKeyvalWithoutModifier() returns the keyval for aGdkKeyEvent when 1.317 + * ignoring the modifier state except NumLock. (NumLock is a key to change 1.318 + * some key's meaning.) 1.319 + */ 1.320 + static guint GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent); 1.321 + 1.322 + /** 1.323 + * GetDOMKeyCodeFromKeyPairs() returns DOM keycode for aGdkKeyval if 1.324 + * it's in KeyPair table. 1.325 + */ 1.326 + static uint32_t GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval); 1.327 + 1.328 + /** 1.329 + * InitKeypressEvent() intializes keyCode, charCode and 1.330 + * alternativeCharCodes of keypress event. 1.331 + * 1.332 + * @param aKeyEvent An NS_KEY_PRESS event, must not be nullptr. 1.333 + * The modifier related members and keyCode must 1.334 + * be initialized already. 1.335 + * @param aGdkKeyEvent A native key event which causes dispatching 1.336 + * aKeyEvent. 1.337 + */ 1.338 + void InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent, 1.339 + GdkEventKey* aGdkKeyEvent); 1.340 + 1.341 + /** 1.342 + * FilterEvents() listens all events on all our windows. 1.343 + * Be careful, this may make damage to performance if you add expensive 1.344 + * code in this method. 1.345 + */ 1.346 + static GdkFilterReturn FilterEvents(GdkXEvent* aXEvent, 1.347 + GdkEvent* aGdkEvent, 1.348 + gpointer aData); 1.349 +}; 1.350 + 1.351 +} // namespace widget 1.352 +} // namespace mozilla 1.353 + 1.354 +#endif /* __nsGdkKeyUtils_h__ */