1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gtk/nsGtkKeyUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1467 @@ 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 +#include "prlog.h" 1.12 + 1.13 +#include "nsGtkKeyUtils.h" 1.14 + 1.15 +#include <gdk/gdkkeysyms.h> 1.16 +#include <algorithm> 1.17 +#include <gdk/gdk.h> 1.18 +#include <gdk/gdkx.h> 1.19 +#if (MOZ_WIDGET_GTK == 3) 1.20 +#include <gdk/gdkkeysyms-compat.h> 1.21 +#endif 1.22 +#include <X11/XKBlib.h> 1.23 +#include "WidgetUtils.h" 1.24 +#include "keysym2ucs.h" 1.25 +#include "nsIBidiKeyboard.h" 1.26 +#include "nsServiceManagerUtils.h" 1.27 + 1.28 +#ifdef PR_LOGGING 1.29 +PRLogModuleInfo* gKeymapWrapperLog = nullptr; 1.30 +#endif // PR_LOGGING 1.31 + 1.32 +#include "mozilla/ArrayUtils.h" 1.33 +#include "mozilla/MouseEvents.h" 1.34 +#include "mozilla/TextEvents.h" 1.35 + 1.36 +namespace mozilla { 1.37 +namespace widget { 1.38 + 1.39 +#define IS_ASCII_ALPHABETICAL(key) \ 1.40 + ((('a' <= key) && (key <= 'z')) || (('A' <= key) && (key <= 'Z'))) 1.41 + 1.42 +#define MOZ_MODIFIER_KEYS "MozKeymapWrapper" 1.43 + 1.44 +KeymapWrapper* KeymapWrapper::sInstance = nullptr; 1.45 +guint KeymapWrapper::sLastRepeatableHardwareKeyCode = 0; 1.46 +KeymapWrapper::RepeatState KeymapWrapper::sRepeatState = 1.47 + KeymapWrapper::NOT_PRESSED; 1.48 +nsIBidiKeyboard* sBidiKeyboard = nullptr; 1.49 + 1.50 +#ifdef PR_LOGGING 1.51 + 1.52 +static const char* GetBoolName(bool aBool) 1.53 +{ 1.54 + return aBool ? "TRUE" : "FALSE"; 1.55 +} 1.56 + 1.57 +/* static */ const char* 1.58 +KeymapWrapper::GetModifierName(Modifier aModifier) 1.59 +{ 1.60 + switch (aModifier) { 1.61 + case CAPS_LOCK: return "CapsLock"; 1.62 + case NUM_LOCK: return "NumLock"; 1.63 + case SCROLL_LOCK: return "ScrollLock"; 1.64 + case SHIFT: return "Shift"; 1.65 + case CTRL: return "Ctrl"; 1.66 + case ALT: return "Alt"; 1.67 + case SUPER: return "Super"; 1.68 + case HYPER: return "Hyper"; 1.69 + case META: return "Meta"; 1.70 + case LEVEL3: return "Level3"; 1.71 + case LEVEL5: return "Level5"; 1.72 + case NOT_MODIFIER: return "NotModifier"; 1.73 + default: return "InvalidValue"; 1.74 + } 1.75 +} 1.76 + 1.77 +#endif // PR_LOGGING 1.78 + 1.79 +/* static */ KeymapWrapper::Modifier 1.80 +KeymapWrapper::GetModifierForGDKKeyval(guint aGdkKeyval) 1.81 +{ 1.82 + switch (aGdkKeyval) { 1.83 + case GDK_Caps_Lock: return CAPS_LOCK; 1.84 + case GDK_Num_Lock: return NUM_LOCK; 1.85 + case GDK_Scroll_Lock: return SCROLL_LOCK; 1.86 + case GDK_Shift_Lock: 1.87 + case GDK_Shift_L: 1.88 + case GDK_Shift_R: return SHIFT; 1.89 + case GDK_Control_L: 1.90 + case GDK_Control_R: return CTRL; 1.91 + case GDK_Alt_L: 1.92 + case GDK_Alt_R: return ALT; 1.93 + case GDK_Super_L: 1.94 + case GDK_Super_R: return SUPER; 1.95 + case GDK_Hyper_L: 1.96 + case GDK_Hyper_R: return HYPER; 1.97 + case GDK_Meta_L: 1.98 + case GDK_Meta_R: return META; 1.99 + case GDK_ISO_Level3_Shift: 1.100 + case GDK_Mode_switch: return LEVEL3; 1.101 + case GDK_ISO_Level5_Shift: return LEVEL5; 1.102 + default: return NOT_MODIFIER; 1.103 + } 1.104 +} 1.105 + 1.106 +guint 1.107 +KeymapWrapper::GetModifierMask(Modifier aModifier) const 1.108 +{ 1.109 + switch (aModifier) { 1.110 + case CAPS_LOCK: 1.111 + return GDK_LOCK_MASK; 1.112 + case NUM_LOCK: 1.113 + return mModifierMasks[INDEX_NUM_LOCK]; 1.114 + case SCROLL_LOCK: 1.115 + return mModifierMasks[INDEX_SCROLL_LOCK]; 1.116 + case SHIFT: 1.117 + return GDK_SHIFT_MASK; 1.118 + case CTRL: 1.119 + return GDK_CONTROL_MASK; 1.120 + case ALT: 1.121 + return mModifierMasks[INDEX_ALT]; 1.122 + case SUPER: 1.123 + return mModifierMasks[INDEX_SUPER]; 1.124 + case HYPER: 1.125 + return mModifierMasks[INDEX_HYPER]; 1.126 + case META: 1.127 + return mModifierMasks[INDEX_META]; 1.128 + case LEVEL3: 1.129 + return mModifierMasks[INDEX_LEVEL3]; 1.130 + case LEVEL5: 1.131 + return mModifierMasks[INDEX_LEVEL5]; 1.132 + default: 1.133 + return 0; 1.134 + } 1.135 +} 1.136 + 1.137 +KeymapWrapper::ModifierKey* 1.138 +KeymapWrapper::GetModifierKey(guint aHardwareKeycode) 1.139 +{ 1.140 + for (uint32_t i = 0; i < mModifierKeys.Length(); i++) { 1.141 + ModifierKey& key = mModifierKeys[i]; 1.142 + if (key.mHardwareKeycode == aHardwareKeycode) { 1.143 + return &key; 1.144 + } 1.145 + } 1.146 + return nullptr; 1.147 +} 1.148 + 1.149 +/* static */ KeymapWrapper* 1.150 +KeymapWrapper::GetInstance() 1.151 +{ 1.152 + if (sInstance) { 1.153 + sInstance->Init(); 1.154 + return sInstance; 1.155 + } 1.156 + 1.157 + sInstance = new KeymapWrapper(); 1.158 + return sInstance; 1.159 +} 1.160 + 1.161 +KeymapWrapper::KeymapWrapper() : 1.162 + mInitialized(false), mGdkKeymap(gdk_keymap_get_default()), 1.163 + mXKBBaseEventCode(0) 1.164 +{ 1.165 +#ifdef PR_LOGGING 1.166 + if (!gKeymapWrapperLog) { 1.167 + gKeymapWrapperLog = PR_NewLogModule("KeymapWrapperWidgets"); 1.168 + } 1.169 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.170 + ("KeymapWrapper(%p): Constructor, mGdkKeymap=%p", 1.171 + this, mGdkKeymap)); 1.172 +#endif // PR_LOGGING 1.173 + 1.174 + g_signal_connect(mGdkKeymap, "keys-changed", 1.175 + (GCallback)OnKeysChanged, this); 1.176 + 1.177 + // This is necessary for catching the destroying timing. 1.178 + g_object_weak_ref(G_OBJECT(mGdkKeymap), 1.179 + (GWeakNotify)OnDestroyKeymap, this); 1.180 + 1.181 + InitXKBExtension(); 1.182 + 1.183 + Init(); 1.184 +} 1.185 + 1.186 +void 1.187 +KeymapWrapper::Init() 1.188 +{ 1.189 + if (mInitialized) { 1.190 + return; 1.191 + } 1.192 + mInitialized = true; 1.193 + 1.194 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.195 + ("KeymapWrapper(%p): Init, mGdkKeymap=%p", 1.196 + this, mGdkKeymap)); 1.197 + 1.198 + mModifierKeys.Clear(); 1.199 + memset(mModifierMasks, 0, sizeof(mModifierMasks)); 1.200 + 1.201 + InitBySystemSettings(); 1.202 + 1.203 + gdk_window_add_filter(nullptr, FilterEvents, this); 1.204 + 1.205 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.206 + ("KeymapWrapper(%p): Init, CapsLock=0x%X, NumLock=0x%X, " 1.207 + "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, " 1.208 + "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X", 1.209 + this, 1.210 + GetModifierMask(CAPS_LOCK), GetModifierMask(NUM_LOCK), 1.211 + GetModifierMask(SCROLL_LOCK), GetModifierMask(LEVEL3), 1.212 + GetModifierMask(LEVEL5), 1.213 + GetModifierMask(SHIFT), GetModifierMask(CTRL), 1.214 + GetModifierMask(ALT), GetModifierMask(META), 1.215 + GetModifierMask(SUPER), GetModifierMask(HYPER))); 1.216 +} 1.217 + 1.218 +void 1.219 +KeymapWrapper::InitXKBExtension() 1.220 +{ 1.221 + PodZero(&mKeyboardState); 1.222 + 1.223 + int xkbMajorVer = XkbMajorVersion; 1.224 + int xkbMinorVer = XkbMinorVersion; 1.225 + if (!XkbLibraryVersion(&xkbMajorVer, &xkbMinorVer)) { 1.226 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.227 + ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " 1.228 + "XkbLibraryVersion()", this)); 1.229 + return; 1.230 + } 1.231 + 1.232 + Display* display = 1.233 + gdk_x11_display_get_xdisplay(gdk_display_get_default()); 1.234 + 1.235 + // XkbLibraryVersion() set xkbMajorVer and xkbMinorVer to that of the 1.236 + // library, which may be newer than what is required of the server in 1.237 + // XkbQueryExtension(), so these variables should be reset to 1.238 + // XkbMajorVersion and XkbMinorVersion before the XkbQueryExtension call. 1.239 + xkbMajorVer = XkbMajorVersion; 1.240 + xkbMinorVer = XkbMinorVersion; 1.241 + int opcode, baseErrorCode; 1.242 + if (!XkbQueryExtension(display, &opcode, &mXKBBaseEventCode, &baseErrorCode, 1.243 + &xkbMajorVer, &xkbMinorVer)) { 1.244 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.245 + ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " 1.246 + "XkbQueryExtension(), display=0x%p", this, display)); 1.247 + return; 1.248 + } 1.249 + 1.250 + if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotify, 1.251 + XkbModifierStateMask, XkbModifierStateMask)) { 1.252 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.253 + ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " 1.254 + "XkbSelectEventDetails() for XModifierStateMask, display=0x%p", 1.255 + this, display)); 1.256 + return; 1.257 + } 1.258 + 1.259 + if (!XkbSelectEventDetails(display, XkbUseCoreKbd, XkbControlsNotify, 1.260 + XkbPerKeyRepeatMask, XkbPerKeyRepeatMask)) { 1.261 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.262 + ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " 1.263 + "XkbSelectEventDetails() for XkbControlsNotify, display=0x%p", 1.264 + this, display)); 1.265 + return; 1.266 + } 1.267 + 1.268 + if (!XGetKeyboardControl(display, &mKeyboardState)) { 1.269 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.270 + ("KeymapWrapper(%p): InitXKBExtension failed due to failure of " 1.271 + "XGetKeyboardControl(), display=0x%p", 1.272 + this, display)); 1.273 + return; 1.274 + } 1.275 + 1.276 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.277 + ("KeymapWrapper(%p): InitXKBExtension, Succeeded", this)); 1.278 +} 1.279 + 1.280 +void 1.281 +KeymapWrapper::InitBySystemSettings() 1.282 +{ 1.283 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.284 + ("KeymapWrapper(%p): InitBySystemSettings, mGdkKeymap=%p", 1.285 + this, mGdkKeymap)); 1.286 + 1.287 + Display* display = 1.288 + gdk_x11_display_get_xdisplay(gdk_display_get_default()); 1.289 + 1.290 + int min_keycode = 0; 1.291 + int max_keycode = 0; 1.292 + XDisplayKeycodes(display, &min_keycode, &max_keycode); 1.293 + 1.294 + int keysyms_per_keycode = 0; 1.295 + KeySym* xkeymap = XGetKeyboardMapping(display, min_keycode, 1.296 + max_keycode - min_keycode + 1, 1.297 + &keysyms_per_keycode); 1.298 + if (!xkeymap) { 1.299 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.300 + ("KeymapWrapper(%p): InitBySystemSettings, " 1.301 + "Failed due to null xkeymap", this)); 1.302 + return; 1.303 + } 1.304 + 1.305 + XModifierKeymap* xmodmap = XGetModifierMapping(display); 1.306 + if (!xmodmap) { 1.307 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.308 + ("KeymapWrapper(%p): InitBySystemSettings, " 1.309 + "Failed due to null xmodmap", this)); 1.310 + XFree(xkeymap); 1.311 + return; 1.312 + } 1.313 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.314 + ("KeymapWrapper(%p): InitBySystemSettings, min_keycode=%d, " 1.315 + "max_keycode=%d, keysyms_per_keycode=%d, max_keypermod=%d", 1.316 + this, min_keycode, max_keycode, keysyms_per_keycode, 1.317 + xmodmap->max_keypermod)); 1.318 + 1.319 + // The modifiermap member of the XModifierKeymap structure contains 8 sets 1.320 + // of max_keypermod KeyCodes, one for each modifier in the order Shift, 1.321 + // Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5. 1.322 + // Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are 1.323 + // ignored. 1.324 + 1.325 + // Note that two or more modifiers may use one modifier flag. E.g., 1.326 + // on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings. 1.327 + // And also Super and Hyper share the Mod4. In such cases, we need to 1.328 + // decide which modifier flag means one of DOM modifiers. 1.329 + 1.330 + // mod[0] is Modifier introduced by Mod1. 1.331 + Modifier mod[5]; 1.332 + int32_t foundLevel[5]; 1.333 + for (uint32_t i = 0; i < ArrayLength(mod); i++) { 1.334 + mod[i] = NOT_MODIFIER; 1.335 + foundLevel[i] = INT32_MAX; 1.336 + } 1.337 + const uint32_t map_size = 8 * xmodmap->max_keypermod; 1.338 + for (uint32_t i = 0; i < map_size; i++) { 1.339 + KeyCode keycode = xmodmap->modifiermap[i]; 1.340 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.341 + ("KeymapWrapper(%p): InitBySystemSettings, " 1.342 + " i=%d, keycode=0x%08X", 1.343 + this, i, keycode)); 1.344 + if (!keycode || keycode < min_keycode || keycode > max_keycode) { 1.345 + continue; 1.346 + } 1.347 + 1.348 + ModifierKey* modifierKey = GetModifierKey(keycode); 1.349 + if (!modifierKey) { 1.350 + modifierKey = mModifierKeys.AppendElement(ModifierKey(keycode)); 1.351 + } 1.352 + 1.353 + const KeySym* syms = 1.354 + xkeymap + (keycode - min_keycode) * keysyms_per_keycode; 1.355 + const uint32_t bit = i / xmodmap->max_keypermod; 1.356 + modifierKey->mMask |= 1 << bit; 1.357 + 1.358 + // We need to know the meaning of Mod1, Mod2, Mod3, Mod4 and Mod5. 1.359 + // Let's skip if current map is for others. 1.360 + if (bit < 3) { 1.361 + continue; 1.362 + } 1.363 + 1.364 + const int32_t modIndex = bit - 3; 1.365 + for (int32_t j = 0; j < keysyms_per_keycode; j++) { 1.366 + Modifier modifier = GetModifierForGDKKeyval(syms[j]); 1.367 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.368 + ("KeymapWrapper(%p): InitBySystemSettings, " 1.369 + " Mod%d, j=%d, syms[j]=%s(0x%X), modifier=%s", 1.370 + this, modIndex + 1, j, gdk_keyval_name(syms[j]), syms[j], 1.371 + GetModifierName(modifier))); 1.372 + 1.373 + switch (modifier) { 1.374 + case NOT_MODIFIER: 1.375 + // Don't overwrite the stored information with 1.376 + // NOT_MODIFIER. 1.377 + break; 1.378 + case CAPS_LOCK: 1.379 + case SHIFT: 1.380 + case CTRL: 1.381 + // Ignore the modifiers defined in GDK spec. They shouldn't 1.382 + // be mapped to Mod1-5 because they must not work on native 1.383 + // GTK applications. 1.384 + break; 1.385 + default: 1.386 + // If new modifier is found in higher level than stored 1.387 + // value, we don't need to overwrite it. 1.388 + if (j > foundLevel[modIndex]) { 1.389 + break; 1.390 + } 1.391 + // If new modifier is more important than stored value, 1.392 + // we should overwrite it with new modifier. 1.393 + if (j == foundLevel[modIndex]) { 1.394 + mod[modIndex] = std::min(modifier, mod[modIndex]); 1.395 + break; 1.396 + } 1.397 + foundLevel[modIndex] = j; 1.398 + mod[modIndex] = modifier; 1.399 + break; 1.400 + } 1.401 + } 1.402 + } 1.403 + 1.404 + for (uint32_t i = 0; i < COUNT_OF_MODIFIER_INDEX; i++) { 1.405 + Modifier modifier; 1.406 + switch (i) { 1.407 + case INDEX_NUM_LOCK: 1.408 + modifier = NUM_LOCK; 1.409 + break; 1.410 + case INDEX_SCROLL_LOCK: 1.411 + modifier = SCROLL_LOCK; 1.412 + break; 1.413 + case INDEX_ALT: 1.414 + modifier = ALT; 1.415 + break; 1.416 + case INDEX_META: 1.417 + modifier = META; 1.418 + break; 1.419 + case INDEX_SUPER: 1.420 + modifier = SUPER; 1.421 + break; 1.422 + case INDEX_HYPER: 1.423 + modifier = HYPER; 1.424 + break; 1.425 + case INDEX_LEVEL3: 1.426 + modifier = LEVEL3; 1.427 + break; 1.428 + case INDEX_LEVEL5: 1.429 + modifier = LEVEL5; 1.430 + break; 1.431 + default: 1.432 + MOZ_CRASH("All indexes must be handled here"); 1.433 + } 1.434 + for (uint32_t j = 0; j < ArrayLength(mod); j++) { 1.435 + if (modifier == mod[j]) { 1.436 + mModifierMasks[i] |= 1 << (j + 3); 1.437 + } 1.438 + } 1.439 + } 1.440 + 1.441 + XFreeModifiermap(xmodmap); 1.442 + XFree(xkeymap); 1.443 +} 1.444 + 1.445 +KeymapWrapper::~KeymapWrapper() 1.446 +{ 1.447 + gdk_window_remove_filter(nullptr, FilterEvents, this); 1.448 + NS_IF_RELEASE(sBidiKeyboard); 1.449 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.450 + ("KeymapWrapper(%p): Destructor", this)); 1.451 +} 1.452 + 1.453 +/* static */ GdkFilterReturn 1.454 +KeymapWrapper::FilterEvents(GdkXEvent* aXEvent, 1.455 + GdkEvent* aGdkEvent, 1.456 + gpointer aData) 1.457 +{ 1.458 + XEvent* xEvent = static_cast<XEvent*>(aXEvent); 1.459 + switch (xEvent->type) { 1.460 + case KeyPress: { 1.461 + // If the key doesn't support auto repeat, ignore the event because 1.462 + // even if such key (e.g., Shift) is pressed during auto repeat of 1.463 + // anoter key, it doesn't stop the auto repeat. 1.464 + KeymapWrapper* self = static_cast<KeymapWrapper*>(aData); 1.465 + if (!self->IsAutoRepeatableKey(xEvent->xkey.keycode)) { 1.466 + break; 1.467 + } 1.468 + if (sRepeatState == NOT_PRESSED) { 1.469 + sRepeatState = FIRST_PRESS; 1.470 + } else if (sLastRepeatableHardwareKeyCode == xEvent->xkey.keycode) { 1.471 + sRepeatState = REPEATING; 1.472 + } else { 1.473 + // If a different key is pressed while another key is pressed, 1.474 + // auto repeat system repeats only the last pressed key. 1.475 + // So, setting new keycode and setting repeat state as first key 1.476 + // press should work fine. 1.477 + sRepeatState = FIRST_PRESS; 1.478 + } 1.479 + sLastRepeatableHardwareKeyCode = xEvent->xkey.keycode; 1.480 + break; 1.481 + } 1.482 + case KeyRelease: { 1.483 + if (sLastRepeatableHardwareKeyCode != xEvent->xkey.keycode) { 1.484 + // This case means the key release event is caused by 1.485 + // a non-repeatable key such as Shift or a repeatable key that 1.486 + // was pressed before sLastRepeatableHardwareKeyCode was 1.487 + // pressed. 1.488 + break; 1.489 + } 1.490 + sRepeatState = NOT_PRESSED; 1.491 + break; 1.492 + } 1.493 + case FocusOut: { 1.494 + // At moving focus, we should reset keyboard repeat state. 1.495 + // Strictly, this causes incorrect behavior. However, this 1.496 + // correctness must be enough for web applications. 1.497 + sRepeatState = NOT_PRESSED; 1.498 + break; 1.499 + } 1.500 + default: { 1.501 + KeymapWrapper* self = static_cast<KeymapWrapper*>(aData); 1.502 + if (xEvent->type != self->mXKBBaseEventCode) { 1.503 + break; 1.504 + } 1.505 + XkbEvent* xkbEvent = (XkbEvent*)xEvent; 1.506 + if (xkbEvent->any.xkb_type != XkbControlsNotify || 1.507 + !(xkbEvent->ctrls.changed_ctrls & XkbPerKeyRepeatMask)) { 1.508 + break; 1.509 + } 1.510 + if (!XGetKeyboardControl(xkbEvent->any.display, 1.511 + &self->mKeyboardState)) { 1.512 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.513 + ("KeymapWrapper(%p): FilterEvents failed due to failure " 1.514 + "of XGetKeyboardControl(), display=0x%p", 1.515 + self, xkbEvent->any.display)); 1.516 + } 1.517 + break; 1.518 + } 1.519 + } 1.520 + 1.521 + return GDK_FILTER_CONTINUE; 1.522 +} 1.523 + 1.524 +/* static */ void 1.525 +KeymapWrapper::OnDestroyKeymap(KeymapWrapper* aKeymapWrapper, 1.526 + GdkKeymap *aGdkKeymap) 1.527 +{ 1.528 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.529 + ("KeymapWrapper: OnDestroyKeymap, aGdkKeymap=%p, aKeymapWrapper=%p", 1.530 + aGdkKeymap, aKeymapWrapper)); 1.531 + MOZ_ASSERT(aKeymapWrapper == sInstance, 1.532 + "Desroying unexpected instance"); 1.533 + delete sInstance; 1.534 + sInstance = nullptr; 1.535 +} 1.536 + 1.537 +/* static */ void 1.538 +KeymapWrapper::OnKeysChanged(GdkKeymap *aGdkKeymap, 1.539 + KeymapWrapper* aKeymapWrapper) 1.540 +{ 1.541 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.542 + ("KeymapWrapper: OnKeysChanged, aGdkKeymap=%p, aKeymapWrapper=%p", 1.543 + aGdkKeymap, aKeymapWrapper)); 1.544 + 1.545 + MOZ_ASSERT(sInstance == aKeymapWrapper, 1.546 + "This instance must be the singleton instance"); 1.547 + 1.548 + // We cannot reintialize here becasue we don't have GdkWindow which is using 1.549 + // the GdkKeymap. We'll reinitialize it when next GetInstance() is called. 1.550 + sInstance->mInitialized = false; 1.551 + 1.552 + // Reset the bidi keyboard settings for the new GdkKeymap 1.553 + if (!sBidiKeyboard) { 1.554 + CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard); 1.555 + } 1.556 + if (sBidiKeyboard) { 1.557 + sBidiKeyboard->Reset(); 1.558 + } 1.559 +} 1.560 + 1.561 +/* static */ guint 1.562 +KeymapWrapper::GetCurrentModifierState() 1.563 +{ 1.564 + GdkModifierType modifiers; 1.565 + gdk_display_get_pointer(gdk_display_get_default(), 1.566 + nullptr, nullptr, nullptr, &modifiers); 1.567 + return static_cast<guint>(modifiers); 1.568 +} 1.569 + 1.570 +/* static */ bool 1.571 +KeymapWrapper::AreModifiersCurrentlyActive(Modifiers aModifiers) 1.572 +{ 1.573 + guint modifierState = GetCurrentModifierState(); 1.574 + return AreModifiersActive(aModifiers, modifierState); 1.575 +} 1.576 + 1.577 +/* static */ bool 1.578 +KeymapWrapper::AreModifiersActive(Modifiers aModifiers, 1.579 + guint aModifierState) 1.580 +{ 1.581 + NS_ENSURE_TRUE(aModifiers, false); 1.582 + 1.583 + KeymapWrapper* keymapWrapper = GetInstance(); 1.584 + for (uint32_t i = 0; i < sizeof(Modifier) * 8 && aModifiers; i++) { 1.585 + Modifier modifier = static_cast<Modifier>(1 << i); 1.586 + if (!(aModifiers & modifier)) { 1.587 + continue; 1.588 + } 1.589 + if (!(aModifierState & keymapWrapper->GetModifierMask(modifier))) { 1.590 + return false; 1.591 + } 1.592 + aModifiers &= ~modifier; 1.593 + } 1.594 + return true; 1.595 +} 1.596 + 1.597 +/* static */ void 1.598 +KeymapWrapper::InitInputEvent(WidgetInputEvent& aInputEvent, 1.599 + guint aModifierState) 1.600 +{ 1.601 + KeymapWrapper* keymapWrapper = GetInstance(); 1.602 + 1.603 + aInputEvent.modifiers = 0; 1.604 + // DOM Meta key should be TRUE only on Mac. We need to discuss this 1.605 + // issue later. 1.606 + if (keymapWrapper->AreModifiersActive(SHIFT, aModifierState)) { 1.607 + aInputEvent.modifiers |= MODIFIER_SHIFT; 1.608 + } 1.609 + if (keymapWrapper->AreModifiersActive(CTRL, aModifierState)) { 1.610 + aInputEvent.modifiers |= MODIFIER_CONTROL; 1.611 + } 1.612 + if (keymapWrapper->AreModifiersActive(ALT, aModifierState)) { 1.613 + aInputEvent.modifiers |= MODIFIER_ALT; 1.614 + } 1.615 + if (keymapWrapper->AreModifiersActive(META, aModifierState)) { 1.616 + aInputEvent.modifiers |= MODIFIER_META; 1.617 + } 1.618 + if (keymapWrapper->AreModifiersActive(SUPER, aModifierState) || 1.619 + keymapWrapper->AreModifiersActive(HYPER, aModifierState)) { 1.620 + aInputEvent.modifiers |= MODIFIER_OS; 1.621 + } 1.622 + if (keymapWrapper->AreModifiersActive(LEVEL3, aModifierState) || 1.623 + keymapWrapper->AreModifiersActive(LEVEL5, aModifierState)) { 1.624 + aInputEvent.modifiers |= MODIFIER_ALTGRAPH; 1.625 + } 1.626 + if (keymapWrapper->AreModifiersActive(CAPS_LOCK, aModifierState)) { 1.627 + aInputEvent.modifiers |= MODIFIER_CAPSLOCK; 1.628 + } 1.629 + if (keymapWrapper->AreModifiersActive(NUM_LOCK, aModifierState)) { 1.630 + aInputEvent.modifiers |= MODIFIER_NUMLOCK; 1.631 + } 1.632 + if (keymapWrapper->AreModifiersActive(SCROLL_LOCK, aModifierState)) { 1.633 + aInputEvent.modifiers |= MODIFIER_SCROLLLOCK; 1.634 + } 1.635 + 1.636 + PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG, 1.637 + ("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X, " 1.638 + "aInputEvent.modifiers=0x%04X (Shift: %s, Control: %s, Alt: %s, " 1.639 + "Meta: %s, OS: %s, AltGr: %s, " 1.640 + "CapsLock: %s, NumLock: %s, ScrollLock: %s)", 1.641 + keymapWrapper, aModifierState, aInputEvent.modifiers, 1.642 + GetBoolName(aInputEvent.modifiers & MODIFIER_SHIFT), 1.643 + GetBoolName(aInputEvent.modifiers & MODIFIER_CONTROL), 1.644 + GetBoolName(aInputEvent.modifiers & MODIFIER_ALT), 1.645 + GetBoolName(aInputEvent.modifiers & MODIFIER_META), 1.646 + GetBoolName(aInputEvent.modifiers & MODIFIER_OS), 1.647 + GetBoolName(aInputEvent.modifiers & MODIFIER_ALTGRAPH), 1.648 + GetBoolName(aInputEvent.modifiers & MODIFIER_CAPSLOCK), 1.649 + GetBoolName(aInputEvent.modifiers & MODIFIER_NUMLOCK), 1.650 + GetBoolName(aInputEvent.modifiers & MODIFIER_SCROLLLOCK))); 1.651 + 1.652 + switch(aInputEvent.eventStructType) { 1.653 + case NS_MOUSE_EVENT: 1.654 + case NS_MOUSE_SCROLL_EVENT: 1.655 + case NS_WHEEL_EVENT: 1.656 + case NS_DRAG_EVENT: 1.657 + case NS_SIMPLE_GESTURE_EVENT: 1.658 + break; 1.659 + default: 1.660 + return; 1.661 + } 1.662 + 1.663 + WidgetMouseEventBase& mouseEvent = *aInputEvent.AsMouseEventBase(); 1.664 + mouseEvent.buttons = 0; 1.665 + if (aModifierState & GDK_BUTTON1_MASK) { 1.666 + mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag; 1.667 + } 1.668 + if (aModifierState & GDK_BUTTON3_MASK) { 1.669 + mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag; 1.670 + } 1.671 + if (aModifierState & GDK_BUTTON2_MASK) { 1.672 + mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag; 1.673 + } 1.674 + 1.675 + PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG, 1.676 + ("KeymapWrapper(%p): InitInputEvent, aInputEvent has buttons, " 1.677 + "aInputEvent.buttons=0x%04X (Left: %s, Right: %s, Middle: %s, " 1.678 + "4th (BACK): %s, 5th (FORWARD): %s)", 1.679 + keymapWrapper, mouseEvent.buttons, 1.680 + GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eLeftButtonFlag), 1.681 + GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eRightButtonFlag), 1.682 + GetBoolName(mouseEvent.buttons & WidgetMouseEvent::eMiddleButtonFlag), 1.683 + GetBoolName(mouseEvent.buttons & WidgetMouseEvent::e4thButtonFlag), 1.684 + GetBoolName(mouseEvent.buttons & WidgetMouseEvent::e5thButtonFlag))); 1.685 +} 1.686 + 1.687 +/* static */ uint32_t 1.688 +KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent) 1.689 +{ 1.690 + // If the keyval indicates it's a modifier key, we should use unshifted 1.691 + // key's modifier keyval. 1.692 + guint keyval = aGdkKeyEvent->keyval; 1.693 + if (GetModifierForGDKKeyval(keyval)) { 1.694 + // But if the keyval without modifiers isn't a modifier key, we 1.695 + // shouldn't use it. E.g., Japanese keyboard layout's 1.696 + // Shift + Eisu-Toggle key is CapsLock. This is an actual rare case, 1.697 + // Windows uses different keycode for a physical key for different 1.698 + // shift key state. 1.699 + guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent); 1.700 + if (GetModifierForGDKKeyval(keyvalWithoutModifier)) { 1.701 + keyval = keyvalWithoutModifier; 1.702 + } 1.703 + // Note that the modifier keycode and activating or deactivating 1.704 + // modifier flag may be mismatched, but it's okay. If a DOM key 1.705 + // event handler is testing a keydown event, it's more likely being 1.706 + // used to test which key is being pressed than to test which 1.707 + // modifier will become active. So, if we computed DOM keycode 1.708 + // from modifier flag which were changing by the physical key, then 1.709 + // there would be no other way for the user to generate the original 1.710 + // keycode. 1.711 + uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval); 1.712 + NS_ASSERTION(DOMKeyCode, "All modifier keys must have a DOM keycode"); 1.713 + return DOMKeyCode; 1.714 + } 1.715 + 1.716 + // If the key isn't printable, let's look at the key pairs. 1.717 + uint32_t charCode = GetCharCodeFor(aGdkKeyEvent); 1.718 + if (!charCode) { 1.719 + // Always use unshifted keycode for the non-printable key. 1.720 + // XXX It might be better to decide DOM keycode from all keyvals of 1.721 + // the hardware keycode. However, I think that it's too excessive. 1.722 + guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent); 1.723 + uint32_t DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyvalWithoutModifier); 1.724 + if (!DOMKeyCode) { 1.725 + // If the unshifted keyval couldn't be mapped to a DOM keycode, 1.726 + // we should fallback to legacy logic, so, we should recompute with 1.727 + // the keyval with aGdkKeyEvent. 1.728 + DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval); 1.729 + } 1.730 + return DOMKeyCode; 1.731 + } 1.732 + 1.733 + // printable numpad keys should be resolved here. 1.734 + switch (keyval) { 1.735 + case GDK_KP_Multiply: return NS_VK_MULTIPLY; 1.736 + case GDK_KP_Add: return NS_VK_ADD; 1.737 + case GDK_KP_Separator: return NS_VK_SEPARATOR; 1.738 + case GDK_KP_Subtract: return NS_VK_SUBTRACT; 1.739 + case GDK_KP_Decimal: return NS_VK_DECIMAL; 1.740 + case GDK_KP_Divide: return NS_VK_DIVIDE; 1.741 + case GDK_KP_0: return NS_VK_NUMPAD0; 1.742 + case GDK_KP_1: return NS_VK_NUMPAD1; 1.743 + case GDK_KP_2: return NS_VK_NUMPAD2; 1.744 + case GDK_KP_3: return NS_VK_NUMPAD3; 1.745 + case GDK_KP_4: return NS_VK_NUMPAD4; 1.746 + case GDK_KP_5: return NS_VK_NUMPAD5; 1.747 + case GDK_KP_6: return NS_VK_NUMPAD6; 1.748 + case GDK_KP_7: return NS_VK_NUMPAD7; 1.749 + case GDK_KP_8: return NS_VK_NUMPAD8; 1.750 + case GDK_KP_9: return NS_VK_NUMPAD9; 1.751 + } 1.752 + 1.753 + KeymapWrapper* keymapWrapper = GetInstance(); 1.754 + 1.755 + // Ignore all modifier state except NumLock. 1.756 + guint baseState = 1.757 + (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK)); 1.758 + 1.759 + // Basically, we should use unmodified character for deciding our keyCode. 1.760 + uint32_t unmodifiedChar = 1.761 + keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, 1.762 + aGdkKeyEvent->group); 1.763 + if (IsBasicLatinLetterOrNumeral(unmodifiedChar)) { 1.764 + // If the unmodified character is an ASCII alphabet or an ASCII 1.765 + // numeric, it's the best hint for deciding our keyCode. 1.766 + return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar); 1.767 + } 1.768 + 1.769 + // If the unmodified character is not an ASCII character, that means we 1.770 + // couldn't find the hint. We should reset it. 1.771 + if (unmodifiedChar > 0x7F) { 1.772 + unmodifiedChar = 0; 1.773 + } 1.774 + 1.775 + // Retry with shifted keycode. 1.776 + guint shiftState = (baseState | keymapWrapper->GetModifierMask(SHIFT)); 1.777 + uint32_t shiftedChar = 1.778 + keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, 1.779 + aGdkKeyEvent->group); 1.780 + if (IsBasicLatinLetterOrNumeral(shiftedChar)) { 1.781 + // A shifted character can be an ASCII alphabet on Hebrew keyboard 1.782 + // layout. And also shifted character can be an ASCII numeric on 1.783 + // AZERTY keyboad layout. Then, it's a good hint for deciding our 1.784 + // keyCode. 1.785 + return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar); 1.786 + } 1.787 + 1.788 + // If the shifted unmodified character isn't an ASCII character, we should 1.789 + // discard it too. 1.790 + if (shiftedChar > 0x7F) { 1.791 + shiftedChar = 0; 1.792 + } 1.793 + 1.794 + // If current keyboard layout isn't ASCII alphabet inputtable layout, 1.795 + // look for ASCII alphabet inputtable keyboard layout. If the key 1.796 + // inputs an ASCII alphabet or an ASCII numeric, we should use it 1.797 + // for deciding our keyCode. 1.798 + // Note that it's important not to use alternative keyboard layout for ASCII 1.799 + // alphabet inputabble keyboard layout because the keycode for the key with 1.800 + // alternative keyboard layout may conflict with another key on current 1.801 + // keyboard layout. 1.802 + if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) { 1.803 + gint minGroup = keymapWrapper->GetFirstLatinGroup(); 1.804 + if (minGroup >= 0) { 1.805 + uint32_t unmodCharLatin = 1.806 + keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, 1.807 + minGroup); 1.808 + if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) { 1.809 + // If the unmodified character is an ASCII alphabet or 1.810 + // an ASCII numeric, we should use it for the keyCode. 1.811 + return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin); 1.812 + } 1.813 + uint32_t shiftedCharLatin = 1.814 + keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, 1.815 + minGroup); 1.816 + if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) { 1.817 + // If the shifted character is an ASCII alphabet or an ASCII 1.818 + // numeric, we should use it for the keyCode. 1.819 + return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin); 1.820 + } 1.821 + } 1.822 + } 1.823 + 1.824 + // If unmodified character is in ASCII range, use it. Otherwise, use 1.825 + // shifted character. 1.826 + if (!unmodifiedChar && !shiftedChar) { 1.827 + return 0; 1.828 + } 1.829 + return WidgetUtils::ComputeKeyCodeFromChar( 1.830 + unmodifiedChar ? unmodifiedChar : shiftedChar); 1.831 +} 1.832 + 1.833 +KeyNameIndex 1.834 +KeymapWrapper::ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent) 1.835 +{ 1.836 + switch (aGdkKeyEvent->keyval) { 1.837 + 1.838 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ 1.839 + case aNativeKey: return aKeyNameIndex; 1.840 + 1.841 +#include "NativeKeyToDOMKeyName.h" 1.842 + 1.843 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.844 + 1.845 + default: 1.846 + break; 1.847 + } 1.848 + 1.849 + return KEY_NAME_INDEX_Unidentified; 1.850 +} 1.851 + 1.852 +/* static */ void 1.853 +KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, 1.854 + GdkEventKey* aGdkKeyEvent) 1.855 +{ 1.856 + KeymapWrapper* keymapWrapper = GetInstance(); 1.857 + 1.858 + aKeyEvent.mKeyNameIndex = 1.859 + keymapWrapper->ComputeDOMKeyNameIndex(aGdkKeyEvent); 1.860 + if (aKeyEvent.mKeyNameIndex == KEY_NAME_INDEX_Unidentified) { 1.861 + uint32_t charCode = GetCharCodeFor(aGdkKeyEvent); 1.862 + if (!charCode) { 1.863 + charCode = keymapWrapper->GetUnmodifiedCharCodeFor(aGdkKeyEvent); 1.864 + } 1.865 + if (charCode) { 1.866 + aKeyEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING; 1.867 + MOZ_ASSERT(aKeyEvent.mKeyValue.IsEmpty(), 1.868 + "Uninitialized mKeyValue must be empty"); 1.869 + AppendUCS4ToUTF16(charCode, aKeyEvent.mKeyValue); 1.870 + } 1.871 + } 1.872 + aKeyEvent.keyCode = ComputeDOMKeyCode(aGdkKeyEvent); 1.873 + 1.874 + // NOTE: The state of given key event indicates adjacent state of 1.875 + // modifier keys. E.g., even if the event is Shift key press event, 1.876 + // the bit for Shift is still false. By the same token, even if the 1.877 + // event is Shift key release event, the bit for Shift is still true. 1.878 + // Unfortunately, gdk_keyboard_get_modifiers() returns current modifier 1.879 + // state. It means if there're some pending modifier key press or 1.880 + // key release events, the result isn't what we want. 1.881 + guint modifierState = aGdkKeyEvent->state; 1.882 + if (aGdkKeyEvent->is_modifier) { 1.883 + Display* display = 1.884 + gdk_x11_display_get_xdisplay(gdk_display_get_default()); 1.885 + if (XEventsQueued(display, QueuedAfterReading)) { 1.886 + XEvent nextEvent; 1.887 + XPeekEvent(display, &nextEvent); 1.888 + if (nextEvent.type == keymapWrapper->mXKBBaseEventCode) { 1.889 + XkbEvent* XKBEvent = (XkbEvent*)&nextEvent; 1.890 + if (XKBEvent->any.xkb_type == XkbStateNotify) { 1.891 + XkbStateNotifyEvent* stateNotifyEvent = 1.892 + (XkbStateNotifyEvent*)XKBEvent; 1.893 + modifierState &= ~0xFF; 1.894 + modifierState |= stateNotifyEvent->lookup_mods; 1.895 + } 1.896 + } 1.897 + } 1.898 + } 1.899 + InitInputEvent(aKeyEvent, modifierState); 1.900 + 1.901 + switch (aGdkKeyEvent->keyval) { 1.902 + case GDK_Shift_L: 1.903 + case GDK_Control_L: 1.904 + case GDK_Alt_L: 1.905 + case GDK_Super_L: 1.906 + case GDK_Hyper_L: 1.907 + case GDK_Meta_L: 1.908 + aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT; 1.909 + break; 1.910 + 1.911 + case GDK_Shift_R: 1.912 + case GDK_Control_R: 1.913 + case GDK_Alt_R: 1.914 + case GDK_Super_R: 1.915 + case GDK_Hyper_R: 1.916 + case GDK_Meta_R: 1.917 + aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT; 1.918 + break; 1.919 + 1.920 + case GDK_KP_0: 1.921 + case GDK_KP_1: 1.922 + case GDK_KP_2: 1.923 + case GDK_KP_3: 1.924 + case GDK_KP_4: 1.925 + case GDK_KP_5: 1.926 + case GDK_KP_6: 1.927 + case GDK_KP_7: 1.928 + case GDK_KP_8: 1.929 + case GDK_KP_9: 1.930 + case GDK_KP_Space: 1.931 + case GDK_KP_Tab: 1.932 + case GDK_KP_Enter: 1.933 + case GDK_KP_F1: 1.934 + case GDK_KP_F2: 1.935 + case GDK_KP_F3: 1.936 + case GDK_KP_F4: 1.937 + case GDK_KP_Home: 1.938 + case GDK_KP_Left: 1.939 + case GDK_KP_Up: 1.940 + case GDK_KP_Right: 1.941 + case GDK_KP_Down: 1.942 + case GDK_KP_Prior: // same as GDK_KP_Page_Up 1.943 + case GDK_KP_Next: // same as GDK_KP_Page_Down 1.944 + case GDK_KP_End: 1.945 + case GDK_KP_Begin: 1.946 + case GDK_KP_Insert: 1.947 + case GDK_KP_Delete: 1.948 + case GDK_KP_Equal: 1.949 + case GDK_KP_Multiply: 1.950 + case GDK_KP_Add: 1.951 + case GDK_KP_Separator: 1.952 + case GDK_KP_Subtract: 1.953 + case GDK_KP_Decimal: 1.954 + case GDK_KP_Divide: 1.955 + aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD; 1.956 + break; 1.957 + 1.958 + default: 1.959 + aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD; 1.960 + break; 1.961 + } 1.962 + 1.963 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.964 + ("KeymapWrapper(%p): InitKeyEvent, modifierState=0x%08X " 1.965 + "aGdkKeyEvent={ type=%s, keyval=%s(0x%X), state=0x%08X, " 1.966 + "hardware_keycode=0x%08X, is_modifier=%s } " 1.967 + "aKeyEvent={ message=%s, isShift=%s, isControl=%s, " 1.968 + "isAlt=%s, isMeta=%s }", 1.969 + keymapWrapper, modifierState, 1.970 + ((aGdkKeyEvent->type == GDK_KEY_PRESS) ? 1.971 + "GDK_KEY_PRESS" : "GDK_KEY_RELEASE"), 1.972 + gdk_keyval_name(aGdkKeyEvent->keyval), 1.973 + aGdkKeyEvent->keyval, aGdkKeyEvent->state, 1.974 + aGdkKeyEvent->hardware_keycode, 1.975 + GetBoolName(aGdkKeyEvent->is_modifier), 1.976 + ((aKeyEvent.message == NS_KEY_DOWN) ? "NS_KEY_DOWN" : 1.977 + (aKeyEvent.message == NS_KEY_PRESS) ? "NS_KEY_PRESS" : 1.978 + "NS_KEY_UP"), 1.979 + GetBoolName(aKeyEvent.IsShift()), GetBoolName(aKeyEvent.IsControl()), 1.980 + GetBoolName(aKeyEvent.IsAlt()), GetBoolName(aKeyEvent.IsMeta()))); 1.981 + 1.982 + if (aKeyEvent.message == NS_KEY_PRESS) { 1.983 + keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent); 1.984 + } 1.985 + 1.986 + // The transformations above and in gdk for the keyval are not invertible 1.987 + // so link to the GdkEvent (which will vanish soon after return from the 1.988 + // event callback) to give plugins access to hardware_keycode and state. 1.989 + // (An XEvent would be nice but the GdkEvent is good enough.) 1.990 + aKeyEvent.pluginEvent = (void *)aGdkKeyEvent; 1.991 + aKeyEvent.time = aGdkKeyEvent->time; 1.992 + aKeyEvent.mNativeKeyEvent = static_cast<void*>(aGdkKeyEvent); 1.993 + aKeyEvent.mIsRepeat = sRepeatState == REPEATING && 1.994 + aGdkKeyEvent->hardware_keycode == sLastRepeatableHardwareKeyCode; 1.995 +} 1.996 + 1.997 +/* static */ uint32_t 1.998 +KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent) 1.999 +{ 1.1000 + // Anything above 0xf000 is considered a non-printable 1.1001 + // Exception: directly encoded UCS characters 1.1002 + if (aGdkKeyEvent->keyval > 0xf000 && 1.1003 + (aGdkKeyEvent->keyval & 0xff000000) != 0x01000000) { 1.1004 + // Keypad keys are an exception: they return a value different 1.1005 + // from their non-keypad equivalents, but mozilla doesn't distinguish. 1.1006 + switch (aGdkKeyEvent->keyval) { 1.1007 + case GDK_KP_Space: return ' '; 1.1008 + case GDK_KP_Equal: return '='; 1.1009 + case GDK_KP_Multiply: return '*'; 1.1010 + case GDK_KP_Add: return '+'; 1.1011 + case GDK_KP_Separator: return ','; 1.1012 + case GDK_KP_Subtract: return '-'; 1.1013 + case GDK_KP_Decimal: return '.'; 1.1014 + case GDK_KP_Divide: return '/'; 1.1015 + case GDK_KP_0: return '0'; 1.1016 + case GDK_KP_1: return '1'; 1.1017 + case GDK_KP_2: return '2'; 1.1018 + case GDK_KP_3: return '3'; 1.1019 + case GDK_KP_4: return '4'; 1.1020 + case GDK_KP_5: return '5'; 1.1021 + case GDK_KP_6: return '6'; 1.1022 + case GDK_KP_7: return '7'; 1.1023 + case GDK_KP_8: return '8'; 1.1024 + case GDK_KP_9: return '9'; 1.1025 + default: return 0; // non-printables 1.1026 + } 1.1027 + } 1.1028 + 1.1029 + static const long MAX_UNICODE = 0x10FFFF; 1.1030 + 1.1031 + // we're supposedly printable, let's try to convert 1.1032 + long ucs = keysym2ucs(aGdkKeyEvent->keyval); 1.1033 + if ((ucs != -1) && (ucs < MAX_UNICODE)) { 1.1034 + return ucs; 1.1035 + } 1.1036 + 1.1037 + // I guess we couldn't convert 1.1038 + return 0; 1.1039 +} 1.1040 + 1.1041 +uint32_t 1.1042 +KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent, 1.1043 + guint aModifierState, 1.1044 + gint aGroup) 1.1045 +{ 1.1046 + guint keyval; 1.1047 + if (!gdk_keymap_translate_keyboard_state(mGdkKeymap, 1.1048 + aGdkKeyEvent->hardware_keycode, 1.1049 + GdkModifierType(aModifierState), 1.1050 + aGroup, &keyval, nullptr, nullptr, nullptr)) { 1.1051 + return 0; 1.1052 + } 1.1053 + GdkEventKey tmpEvent = *aGdkKeyEvent; 1.1054 + tmpEvent.state = aModifierState; 1.1055 + tmpEvent.keyval = keyval; 1.1056 + tmpEvent.group = aGroup; 1.1057 + return GetCharCodeFor(&tmpEvent); 1.1058 +} 1.1059 + 1.1060 +uint32_t 1.1061 +KeymapWrapper::GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent) 1.1062 +{ 1.1063 + guint state = aGdkKeyEvent->state & 1.1064 + (GetModifierMask(SHIFT) | GetModifierMask(CAPS_LOCK) | 1.1065 + GetModifierMask(NUM_LOCK) | GetModifierMask(SCROLL_LOCK) | 1.1066 + GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5)); 1.1067 + uint32_t charCode = GetCharCodeFor(aGdkKeyEvent, GdkModifierType(state), 1.1068 + aGdkKeyEvent->group); 1.1069 + if (charCode) { 1.1070 + return charCode; 1.1071 + } 1.1072 + // If no character is mapped to the key when Level3 Shift or Level5 Shift 1.1073 + // is active, let's return a character which is inputted by the key without 1.1074 + // Level3 nor Level5 Shift. 1.1075 + guint stateWithoutAltGraph = 1.1076 + state & ~(GetModifierMask(LEVEL3) | GetModifierMask(LEVEL5)); 1.1077 + if (state == stateWithoutAltGraph) { 1.1078 + return 0; 1.1079 + } 1.1080 + return GetCharCodeFor(aGdkKeyEvent, GdkModifierType(stateWithoutAltGraph), 1.1081 + aGdkKeyEvent->group); 1.1082 +} 1.1083 + 1.1084 +gint 1.1085 +KeymapWrapper::GetKeyLevel(GdkEventKey *aGdkKeyEvent) 1.1086 +{ 1.1087 + gint level; 1.1088 + if (!gdk_keymap_translate_keyboard_state(mGdkKeymap, 1.1089 + aGdkKeyEvent->hardware_keycode, 1.1090 + GdkModifierType(aGdkKeyEvent->state), 1.1091 + aGdkKeyEvent->group, nullptr, nullptr, &level, nullptr)) { 1.1092 + return -1; 1.1093 + } 1.1094 + return level; 1.1095 +} 1.1096 + 1.1097 +gint 1.1098 +KeymapWrapper::GetFirstLatinGroup() 1.1099 +{ 1.1100 + GdkKeymapKey *keys; 1.1101 + gint count; 1.1102 + gint minGroup = -1; 1.1103 + if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) { 1.1104 + // find the minimum number group for latin inputtable layout 1.1105 + for (gint i = 0; i < count && minGroup != 0; ++i) { 1.1106 + if (keys[i].level != 0 && keys[i].level != 1) { 1.1107 + continue; 1.1108 + } 1.1109 + if (minGroup >= 0 && keys[i].group > minGroup) { 1.1110 + continue; 1.1111 + } 1.1112 + minGroup = keys[i].group; 1.1113 + } 1.1114 + g_free(keys); 1.1115 + } 1.1116 + return minGroup; 1.1117 +} 1.1118 + 1.1119 +bool 1.1120 +KeymapWrapper::IsLatinGroup(guint8 aGroup) 1.1121 +{ 1.1122 + GdkKeymapKey *keys; 1.1123 + gint count; 1.1124 + bool result = false; 1.1125 + if (gdk_keymap_get_entries_for_keyval(mGdkKeymap, GDK_a, &keys, &count)) { 1.1126 + for (gint i = 0; i < count; ++i) { 1.1127 + if (keys[i].level != 0 && keys[i].level != 1) { 1.1128 + continue; 1.1129 + } 1.1130 + if (keys[i].group == aGroup) { 1.1131 + result = true; 1.1132 + break; 1.1133 + } 1.1134 + } 1.1135 + g_free(keys); 1.1136 + } 1.1137 + return result; 1.1138 +} 1.1139 + 1.1140 +bool 1.1141 +KeymapWrapper::IsAutoRepeatableKey(guint aHardwareKeyCode) 1.1142 +{ 1.1143 + uint8_t indexOfArray = aHardwareKeyCode / 8; 1.1144 + MOZ_ASSERT(indexOfArray < ArrayLength(mKeyboardState.auto_repeats), 1.1145 + "invalid index"); 1.1146 + char bitMask = 1 << (aHardwareKeyCode % 8); 1.1147 + return (mKeyboardState.auto_repeats[indexOfArray] & bitMask) != 0; 1.1148 +} 1.1149 + 1.1150 +/* static */ bool 1.1151 +KeymapWrapper::IsBasicLatinLetterOrNumeral(uint32_t aCharCode) 1.1152 +{ 1.1153 + return (aCharCode >= 'a' && aCharCode <= 'z') || 1.1154 + (aCharCode >= 'A' && aCharCode <= 'Z') || 1.1155 + (aCharCode >= '0' && aCharCode <= '9'); 1.1156 +} 1.1157 + 1.1158 +/* static */ guint 1.1159 +KeymapWrapper::GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent) 1.1160 +{ 1.1161 + KeymapWrapper* keymapWrapper = GetInstance(); 1.1162 + guint state = 1.1163 + (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK)); 1.1164 + guint keyval; 1.1165 + if (!gdk_keymap_translate_keyboard_state(keymapWrapper->mGdkKeymap, 1.1166 + aGdkKeyEvent->hardware_keycode, GdkModifierType(state), 1.1167 + aGdkKeyEvent->group, &keyval, nullptr, nullptr, nullptr)) { 1.1168 + return 0; 1.1169 + } 1.1170 + return keyval; 1.1171 +} 1.1172 + 1.1173 +/* static */ uint32_t 1.1174 +KeymapWrapper::GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval) 1.1175 +{ 1.1176 + switch (aGdkKeyval) { 1.1177 + case GDK_Cancel: return NS_VK_CANCEL; 1.1178 + case GDK_BackSpace: return NS_VK_BACK; 1.1179 + case GDK_Tab: 1.1180 + case GDK_ISO_Left_Tab: return NS_VK_TAB; 1.1181 + case GDK_Clear: return NS_VK_CLEAR; 1.1182 + case GDK_Return: return NS_VK_RETURN; 1.1183 + case GDK_Shift_L: 1.1184 + case GDK_Shift_R: 1.1185 + case GDK_Shift_Lock: return NS_VK_SHIFT; 1.1186 + case GDK_Control_L: 1.1187 + case GDK_Control_R: return NS_VK_CONTROL; 1.1188 + case GDK_Alt_L: 1.1189 + case GDK_Alt_R: return NS_VK_ALT; 1.1190 + case GDK_Meta_L: 1.1191 + case GDK_Meta_R: return NS_VK_META; 1.1192 + 1.1193 + // Assume that Super or Hyper is always mapped to physical Win key. 1.1194 + case GDK_Super_L: 1.1195 + case GDK_Super_R: 1.1196 + case GDK_Hyper_L: 1.1197 + case GDK_Hyper_R: return NS_VK_WIN; 1.1198 + 1.1199 + // GTK's AltGraph key is similar to Mac's Option (Alt) key. However, 1.1200 + // unfortunately, browsers on Mac are using NS_VK_ALT for it even though 1.1201 + // it's really different from Alt key on Windows. 1.1202 + // On the other hand, GTK's AltGrapsh keys are really different from 1.1203 + // Alt key. However, there is no AltGrapsh key on Windows. On Windows, 1.1204 + // both Ctrl and Alt keys are pressed internally when AltGr key is 1.1205 + // pressed. For some languages' users, AltGraph key is important, so, 1.1206 + // web applications on such locale may want to know AltGraph key press. 1.1207 + // Therefore, we should map AltGr keycode for them only on GTK. 1.1208 + case GDK_ISO_Level3_Shift: 1.1209 + case GDK_ISO_Level5_Shift: 1.1210 + // We assume that Mode_switch is always used for level3 shift. 1.1211 + case GDK_Mode_switch: return NS_VK_ALTGR; 1.1212 + 1.1213 + case GDK_Pause: return NS_VK_PAUSE; 1.1214 + case GDK_Caps_Lock: return NS_VK_CAPS_LOCK; 1.1215 + case GDK_Kana_Lock: 1.1216 + case GDK_Kana_Shift: return NS_VK_KANA; 1.1217 + case GDK_Hangul: return NS_VK_HANGUL; 1.1218 + // case GDK_XXX: return NS_VK_JUNJA; 1.1219 + // case GDK_XXX: return NS_VK_FINAL; 1.1220 + case GDK_Hangul_Hanja: return NS_VK_HANJA; 1.1221 + case GDK_Kanji: return NS_VK_KANJI; 1.1222 + case GDK_Escape: return NS_VK_ESCAPE; 1.1223 + case GDK_Henkan: return NS_VK_CONVERT; 1.1224 + case GDK_Muhenkan: return NS_VK_NONCONVERT; 1.1225 + // case GDK_XXX: return NS_VK_ACCEPT; 1.1226 + // case GDK_XXX: return NS_VK_MODECHANGE; 1.1227 + case GDK_Page_Up: return NS_VK_PAGE_UP; 1.1228 + case GDK_Page_Down: return NS_VK_PAGE_DOWN; 1.1229 + case GDK_End: return NS_VK_END; 1.1230 + case GDK_Home: return NS_VK_HOME; 1.1231 + case GDK_Left: return NS_VK_LEFT; 1.1232 + case GDK_Up: return NS_VK_UP; 1.1233 + case GDK_Right: return NS_VK_RIGHT; 1.1234 + case GDK_Down: return NS_VK_DOWN; 1.1235 + case GDK_Select: return NS_VK_SELECT; 1.1236 + case GDK_Print: return NS_VK_PRINT; 1.1237 + case GDK_Execute: return NS_VK_EXECUTE; 1.1238 + case GDK_Insert: return NS_VK_INSERT; 1.1239 + case GDK_Delete: return NS_VK_DELETE; 1.1240 + case GDK_Help: return NS_VK_HELP; 1.1241 + 1.1242 + // keypad keys 1.1243 + case GDK_KP_Left: return NS_VK_LEFT; 1.1244 + case GDK_KP_Right: return NS_VK_RIGHT; 1.1245 + case GDK_KP_Up: return NS_VK_UP; 1.1246 + case GDK_KP_Down: return NS_VK_DOWN; 1.1247 + case GDK_KP_Page_Up: return NS_VK_PAGE_UP; 1.1248 + // Not sure what these are 1.1249 + // case GDK_KP_Prior: return NS_VK_; 1.1250 + // case GDK_KP_Next: return NS_VK_; 1.1251 + case GDK_KP_Begin: return NS_VK_CLEAR; // Num-unlocked 5 1.1252 + case GDK_KP_Page_Down: return NS_VK_PAGE_DOWN; 1.1253 + case GDK_KP_Home: return NS_VK_HOME; 1.1254 + case GDK_KP_End: return NS_VK_END; 1.1255 + case GDK_KP_Insert: return NS_VK_INSERT; 1.1256 + case GDK_KP_Delete: return NS_VK_DELETE; 1.1257 + case GDK_KP_Enter: return NS_VK_RETURN; 1.1258 + 1.1259 + case GDK_Num_Lock: return NS_VK_NUM_LOCK; 1.1260 + case GDK_Scroll_Lock: return NS_VK_SCROLL_LOCK; 1.1261 + 1.1262 + // Function keys 1.1263 + case GDK_F1: return NS_VK_F1; 1.1264 + case GDK_F2: return NS_VK_F2; 1.1265 + case GDK_F3: return NS_VK_F3; 1.1266 + case GDK_F4: return NS_VK_F4; 1.1267 + case GDK_F5: return NS_VK_F5; 1.1268 + case GDK_F6: return NS_VK_F6; 1.1269 + case GDK_F7: return NS_VK_F7; 1.1270 + case GDK_F8: return NS_VK_F8; 1.1271 + case GDK_F9: return NS_VK_F9; 1.1272 + case GDK_F10: return NS_VK_F10; 1.1273 + case GDK_F11: return NS_VK_F11; 1.1274 + case GDK_F12: return NS_VK_F12; 1.1275 + case GDK_F13: return NS_VK_F13; 1.1276 + case GDK_F14: return NS_VK_F14; 1.1277 + case GDK_F15: return NS_VK_F15; 1.1278 + case GDK_F16: return NS_VK_F16; 1.1279 + case GDK_F17: return NS_VK_F17; 1.1280 + case GDK_F18: return NS_VK_F18; 1.1281 + case GDK_F19: return NS_VK_F19; 1.1282 + case GDK_F20: return NS_VK_F20; 1.1283 + case GDK_F21: return NS_VK_F21; 1.1284 + case GDK_F22: return NS_VK_F22; 1.1285 + case GDK_F23: return NS_VK_F23; 1.1286 + case GDK_F24: return NS_VK_F24; 1.1287 + 1.1288 + // context menu key, keysym 0xff67, typically keycode 117 on 105-key 1.1289 + // (Microsoft) x86 keyboards, located between right 'Windows' key and 1.1290 + // right Ctrl key 1.1291 + case GDK_Menu: return NS_VK_CONTEXT_MENU; 1.1292 + case GDK_Sleep: return NS_VK_SLEEP; 1.1293 + 1.1294 + case GDK_3270_Attn: return NS_VK_ATTN; 1.1295 + case GDK_3270_CursorSelect: return NS_VK_CRSEL; 1.1296 + case GDK_3270_ExSelect: return NS_VK_EXSEL; 1.1297 + case GDK_3270_EraseEOF: return NS_VK_EREOF; 1.1298 + case GDK_3270_Play: return NS_VK_PLAY; 1.1299 + // case GDK_XXX: return NS_VK_ZOOM; 1.1300 + case GDK_3270_PA1: return NS_VK_PA1; 1.1301 + 1.1302 + // map Sun Keyboard special keysyms on to NS_VK keys 1.1303 + 1.1304 + // Sun F11 key generates SunF36(0x1005ff10) keysym 1.1305 + case 0x1005ff10: return NS_VK_F11; 1.1306 + // Sun F12 key generates SunF37(0x1005ff11) keysym 1.1307 + case 0x1005ff11: return NS_VK_F12; 1.1308 + default: return 0; 1.1309 + } 1.1310 +} 1.1311 + 1.1312 +void 1.1313 +KeymapWrapper::InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent, 1.1314 + GdkEventKey* aGdkKeyEvent) 1.1315 +{ 1.1316 + NS_ENSURE_TRUE_VOID(aKeyEvent.message == NS_KEY_PRESS); 1.1317 + 1.1318 + aKeyEvent.charCode = GetCharCodeFor(aGdkKeyEvent); 1.1319 + if (!aKeyEvent.charCode) { 1.1320 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.1321 + ("KeymapWrapper(%p): InitKeypressEvent, " 1.1322 + "keyCode=0x%02X, charCode=0x%08X", 1.1323 + this, aKeyEvent.keyCode, aKeyEvent.charCode)); 1.1324 + return; 1.1325 + } 1.1326 + 1.1327 + // If the event causes inputting a character, keyCode must be zero. 1.1328 + aKeyEvent.keyCode = 0; 1.1329 + 1.1330 + // If Ctrl or Alt or Meta or OS is pressed, we need to append the key 1.1331 + // details for handling shortcut key. Otherwise, we have no additional 1.1332 + // work. 1.1333 + if (!aKeyEvent.IsControl() && !aKeyEvent.IsAlt() && 1.1334 + !aKeyEvent.IsMeta() && !aKeyEvent.IsOS()) { 1.1335 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.1336 + ("KeymapWrapper(%p): InitKeypressEvent, " 1.1337 + "keyCode=0x%02X, charCode=0x%08X", 1.1338 + this, aKeyEvent.keyCode, aKeyEvent.charCode)); 1.1339 + return; 1.1340 + } 1.1341 + 1.1342 + gint level = GetKeyLevel(aGdkKeyEvent); 1.1343 + if (level != 0 && level != 1) { 1.1344 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.1345 + ("KeymapWrapper(%p): InitKeypressEvent, " 1.1346 + "keyCode=0x%02X, charCode=0x%08X, level=%d", 1.1347 + this, aKeyEvent.keyCode, aKeyEvent.charCode, level)); 1.1348 + return; 1.1349 + } 1.1350 + 1.1351 + guint baseState = aGdkKeyEvent->state & 1.1352 + ~(GetModifierMask(SHIFT) | GetModifierMask(CTRL) | 1.1353 + GetModifierMask(ALT) | GetModifierMask(META) | 1.1354 + GetModifierMask(SUPER) | GetModifierMask(HYPER)); 1.1355 + 1.1356 + // We shold send both shifted char and unshifted char, all keyboard layout 1.1357 + // users can use all keys. Don't change event.charCode. On some keyboard 1.1358 + // layouts, Ctrl/Alt/Meta keys are used for inputting some characters. 1.1359 + AlternativeCharCode altCharCodes(0, 0); 1.1360 + // unshifted charcode of current keyboard layout. 1.1361 + altCharCodes.mUnshiftedCharCode = 1.1362 + GetCharCodeFor(aGdkKeyEvent, baseState, aGdkKeyEvent->group); 1.1363 + bool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF); 1.1364 + // shifted charcode of current keyboard layout. 1.1365 + altCharCodes.mShiftedCharCode = 1.1366 + GetCharCodeFor(aGdkKeyEvent, 1.1367 + baseState | GetModifierMask(SHIFT), 1.1368 + aGdkKeyEvent->group); 1.1369 + isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF); 1.1370 + if (altCharCodes.mUnshiftedCharCode || altCharCodes.mShiftedCharCode) { 1.1371 + aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes); 1.1372 + } 1.1373 + 1.1374 + bool needLatinKeyCodes = !isLatin; 1.1375 + if (!needLatinKeyCodes) { 1.1376 + needLatinKeyCodes = 1.1377 + (IS_ASCII_ALPHABETICAL(altCharCodes.mUnshiftedCharCode) != 1.1378 + IS_ASCII_ALPHABETICAL(altCharCodes.mShiftedCharCode)); 1.1379 + } 1.1380 + 1.1381 + // If current keyboard layout can input Latin characters, we don't need 1.1382 + // more information. 1.1383 + if (!needLatinKeyCodes) { 1.1384 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.1385 + ("KeymapWrapper(%p): InitKeypressEvent, keyCode=0x%02X, " 1.1386 + "charCode=0x%08X, level=%d, altCharCodes={ " 1.1387 + "mUnshiftedCharCode=0x%08X, mShiftedCharCode=0x%08X }", 1.1388 + this, aKeyEvent.keyCode, aKeyEvent.charCode, level, 1.1389 + altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode)); 1.1390 + return; 1.1391 + } 1.1392 + 1.1393 + // Next, find Latin inputtable keyboard layout. 1.1394 + gint minGroup = GetFirstLatinGroup(); 1.1395 + if (minGroup < 0) { 1.1396 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.1397 + ("KeymapWrapper(%p): InitKeypressEvent, " 1.1398 + "Latin keyboard layout isn't found: " 1.1399 + "keyCode=0x%02X, charCode=0x%08X, level=%d, " 1.1400 + "altCharCodes={ mUnshiftedCharCode=0x%08X, " 1.1401 + "mShiftedCharCode=0x%08X }", 1.1402 + this, aKeyEvent.keyCode, aKeyEvent.charCode, level, 1.1403 + altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode)); 1.1404 + return; 1.1405 + } 1.1406 + 1.1407 + AlternativeCharCode altLatinCharCodes(0, 0); 1.1408 + uint32_t unmodifiedCh = 1.1409 + aKeyEvent.IsShift() ? altCharCodes.mShiftedCharCode : 1.1410 + altCharCodes.mUnshiftedCharCode; 1.1411 + 1.1412 + // unshifted charcode of found keyboard layout. 1.1413 + uint32_t ch = GetCharCodeFor(aGdkKeyEvent, baseState, minGroup); 1.1414 + altLatinCharCodes.mUnshiftedCharCode = 1.1415 + IsBasicLatinLetterOrNumeral(ch) ? ch : 0; 1.1416 + // shifted charcode of found keyboard layout. 1.1417 + ch = GetCharCodeFor(aGdkKeyEvent, 1.1418 + baseState | GetModifierMask(SHIFT), 1.1419 + minGroup); 1.1420 + altLatinCharCodes.mShiftedCharCode = 1.1421 + IsBasicLatinLetterOrNumeral(ch) ? ch : 0; 1.1422 + if (altLatinCharCodes.mUnshiftedCharCode || 1.1423 + altLatinCharCodes.mShiftedCharCode) { 1.1424 + aKeyEvent.alternativeCharCodes.AppendElement(altLatinCharCodes); 1.1425 + } 1.1426 + // If the charCode is not Latin, and the level is 0 or 1, we should 1.1427 + // replace the charCode to Latin char if Alt and Meta keys are not 1.1428 + // pressed. (Alt should be sent the localized char for accesskey 1.1429 + // like handling of Web Applications.) 1.1430 + ch = aKeyEvent.IsShift() ? altLatinCharCodes.mShiftedCharCode : 1.1431 + altLatinCharCodes.mUnshiftedCharCode; 1.1432 + if (ch && !(aKeyEvent.IsAlt() || aKeyEvent.IsMeta()) && 1.1433 + aKeyEvent.charCode == unmodifiedCh) { 1.1434 + aKeyEvent.charCode = ch; 1.1435 + } 1.1436 + 1.1437 + PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, 1.1438 + ("KeymapWrapper(%p): InitKeypressEvent, " 1.1439 + "keyCode=0x%02X, charCode=0x%08X, level=%d, minGroup=%d, " 1.1440 + "altCharCodes={ mUnshiftedCharCode=0x%08X, " 1.1441 + "mShiftedCharCode=0x%08X } " 1.1442 + "altLatinCharCodes={ mUnshiftedCharCode=0x%08X, " 1.1443 + "mShiftedCharCode=0x%08X }", 1.1444 + this, aKeyEvent.keyCode, aKeyEvent.charCode, level, minGroup, 1.1445 + altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode, 1.1446 + altLatinCharCodes.mUnshiftedCharCode, 1.1447 + altLatinCharCodes.mShiftedCharCode)); 1.1448 +} 1.1449 + 1.1450 +/* static */ bool 1.1451 +KeymapWrapper::IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent) 1.1452 +{ 1.1453 + // If this is a modifier key event, we shouldn't send keypress event. 1.1454 + switch (ComputeDOMKeyCode(aGdkKeyEvent)) { 1.1455 + case NS_VK_SHIFT: 1.1456 + case NS_VK_CONTROL: 1.1457 + case NS_VK_ALT: 1.1458 + case NS_VK_ALTGR: 1.1459 + case NS_VK_WIN: 1.1460 + case NS_VK_CAPS_LOCK: 1.1461 + case NS_VK_NUM_LOCK: 1.1462 + case NS_VK_SCROLL_LOCK: 1.1463 + return false; 1.1464 + default: 1.1465 + return true; 1.1466 + } 1.1467 +} 1.1468 + 1.1469 +} // namespace widget 1.1470 +} // namespace mozilla