Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Unified Diff: chrome/browser/ui/views/ash/key_rewriter.cc

Issue 10383301: Move modifier remapping code from X to Ash (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/views/ash/key_rewriter.cc
diff --git a/chrome/browser/ui/views/ash/key_rewriter.cc b/chrome/browser/ui/views/ash/key_rewriter.cc
index 951fccaa47c1595cb647981fb2ed4714ebf37bee..9b48930e756d3eea862243a4c984dddbbf8529e7 100644
--- a/chrome/browser/ui/views/ash/key_rewriter.cc
+++ b/chrome/browser/ui/views/ash/key_rewriter.cc
@@ -9,6 +9,8 @@
#include "ash/shell.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "ui/aura/event.h"
#include "ui/aura/root_window.h"
#include "ui/base/keycodes/keyboard_code_conversion.h"
@@ -19,18 +21,97 @@
#include <X11/Xlib.h>
#include "base/chromeos/chromeos_version.h"
+#include "chrome/browser/chromeos/input_method/input_method_manager.h"
+#include "chrome/browser/chromeos/input_method/xkeyboard.h"
#include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h"
+#include "chrome/common/pref_names.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"
#include "ui/base/x/x11_util.h"
+
+using chromeos::input_method::InputMethodManager;
#endif
namespace {
const int kBadDeviceId = -1;
+#if defined(OS_CHROMEOS)
+// A key code and a flag we should use when a key is remapped to |remap_to|.
+const struct ModifierRemapping {
+ int remap_to;
+ int flag;
+ unsigned int native_flag;
+ ui::KeyboardCode keycode;
+ unsigned int native_keysyms[4]; // left, right, shift+left, shift+right.
Daniel Erat 2012/05/23 16:37:32 nit: use KeySym instead?
Yusuke Sato 2012/05/24 08:24:42 Done.
+} kModifierRemappings[] = {
+ { chromeos::input_method::kSearchKey, 0, Mod4Mask, ui::VKEY_LWIN,
+ { XK_Super_L, XK_Super_L, XK_Super_L, XK_Super_L}},
+ { chromeos::input_method::kControlKey, ui::EF_CONTROL_DOWN, ControlMask,
+ ui::VKEY_CONTROL,
+ { XK_Control_L, XK_Control_R, XK_Control_L, XK_Control_R }},
+ { chromeos::input_method::kAltKey, ui::EF_ALT_DOWN, Mod1Mask,
+ ui::VKEY_MENU, { XK_Alt_L, XK_Alt_R, XK_Meta_L, XK_Meta_R }},
+ { chromeos::input_method::kVoidKey, 0, 0U, ui::VKEY_UNKNOWN,
+ { XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol }},
+ { chromeos::input_method::kCapsLockKey, 0, 0U, ui::VKEY_CAPITAL,
+ { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock }},
+};
+
+// A structure for converting |native_flag| to a pair of |flag| and |key_name|.
+const struct ModifierFlagToPrefName {
+ unsigned int native_flag;
Daniel Erat 2012/05/23 16:37:32 nit: native_modifiers?
Yusuke Sato 2012/05/24 08:24:42 Done.
+ int flag;
+ const char* key_name;
Daniel Erat 2012/05/23 16:37:32 nit: pref_name?
Yusuke Sato 2012/05/24 08:24:42 Done.
+} kModifierFlagToPrefName[] = {
+ { Mod4Mask, 0, prefs::kLanguageXkbRemapSearchKeyTo },
+ { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageXkbRemapControlKeyTo },
+ { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageXkbRemapAltKeyTo },
+};
+
+// Gets a remapped key for |key_name| key. For example, to find out which
+// key Search is currently remapped to, call the function with
+// prefs::kLanguageXkbRemapSearchKeyTo.
+const ModifierRemapping* GetRemappedKey(const std::string& key_name,
+ PrefService* pref_service) {
Daniel Erat 2012/05/23 16:37:32 nit: const PrefService&
Yusuke Sato 2012/05/24 08:24:42 Done.
+ if (!pref_service || !pref_service->FindPreference(key_name.c_str()))
+ return NULL; // The |key_name| hasn't been registered. On login screen?
+ const int value = pref_service->GetInteger(key_name.c_str());
+ for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
+ if (value == kModifierRemappings[i].remap_to)
+ return &kModifierRemappings[i];
+ }
+ return NULL;
+}
+
+bool IsRight(unsigned int native_keysym) {
Daniel Erat 2012/05/23 16:37:32 nit: KeySym
Yusuke Sato 2012/05/24 08:24:42 Done.
+ switch (native_keysym) {
+ case XK_Alt_R:
+ case XK_Control_R:
+ case XK_Hyper_R:
+ case XK_Meta_R:
+ case XK_Shift_R:
+ case XK_Super_R:
+ return true;
+ }
+ return false;
+}
+#endif
+
+PrefService* GetPrefService() {
Daniel Erat 2012/05/23 16:37:32 nit: const PrefService* ?
Yusuke Sato 2012/05/24 08:24:42 Done.
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ if (profile)
+ return profile->GetPrefs();
+ return NULL;
+}
+
} // namespace
-KeyRewriter::KeyRewriter() : last_device_id_(kBadDeviceId) {
+KeyRewriter::KeyRewriter()
+ : last_device_id_(kBadDeviceId),
+#if defined(OS_CHROMEOS)
+ xkeyboard_(NULL),
+#endif
+ pref_service_(NULL) {
// The ash shell isn't instantiated for our unit tests.
if (ash::Shell::HasInstance())
ash::Shell::GetInstance()->GetRootWindow()->AddRootWindowObserver(this);
@@ -155,6 +236,13 @@ void KeyRewriter::RefreshKeycodes() {
Display* display = ui::GetXDisplay();
control_l_xkeycode_ = XKeysymToKeycode(display, XK_Control_L);
control_r_xkeycode_ = XKeysymToKeycode(display, XK_Control_R);
+ alt_l_xkeycode_ = XKeysymToKeycode(display, XK_Alt_L);
+ alt_r_xkeycode_ = XKeysymToKeycode(display, XK_Alt_R);
+ meta_l_xkeycode_ = XKeysymToKeycode(display, XK_Meta_L);
+ meta_r_xkeycode_ = XKeysymToKeycode(display, XK_Meta_R);
+ windows_l_xkeycode_ = XKeysymToKeycode(display, XK_Super_L);
+ caps_lock_xkeycode_ = XKeysymToKeycode(display, XK_Caps_Lock);
+ void_symbol_xkeycode_ = XKeysymToKeycode(display, XK_VoidSymbol);
kp_0_xkeycode_ = XKeysymToKeycode(display, XK_KP_0);
kp_1_xkeycode_ = XKeysymToKeycode(display, XK_KP_1);
kp_2_xkeycode_ = XKeysymToKeycode(display, XK_KP_2);
@@ -167,13 +255,59 @@ void KeyRewriter::RefreshKeycodes() {
kp_9_xkeycode_ = XKeysymToKeycode(display, XK_KP_9);
kp_decimal_xkeycode_ = XKeysymToKeycode(display, XK_KP_Decimal);
}
+
+unsigned int KeyRewriter::NativeKeySymToNativeKeycode(int keysym) {
Daniel Erat 2012/05/23 16:37:32 nit: KeySym
Yusuke Sato 2012/05/24 08:24:42 Done.
+ switch (keysym) {
+ case XK_Control_L:
+ return control_l_xkeycode_;
+ case XK_Control_R:
+ return control_r_xkeycode_;
+ case XK_Alt_L:
+ return alt_l_xkeycode_;
+ case XK_Alt_R:
+ return alt_r_xkeycode_;
+ case XK_Meta_L:
+ return meta_l_xkeycode_;
+ case XK_Meta_R:
+ return meta_r_xkeycode_;
+ case XK_Super_L:
+ return windows_l_xkeycode_;
+ case XK_Caps_Lock:
+ return caps_lock_xkeycode_;
+ case XK_VoidSymbol:
+ return void_symbol_xkeycode_;
+ case XK_KP_0:
+ return kp_0_xkeycode_;
+ case XK_KP_1:
+ return kp_1_xkeycode_;
+ case XK_KP_2:
+ return kp_2_xkeycode_;
+ case XK_KP_3:
+ return kp_3_xkeycode_;
+ case XK_KP_4:
+ return kp_4_xkeycode_;
+ case XK_KP_5:
+ return kp_5_xkeycode_;
+ case XK_KP_6:
+ return kp_6_xkeycode_;
+ case XK_KP_7:
+ return kp_7_xkeycode_;
+ case XK_KP_8:
+ return kp_8_xkeycode_;
+ case XK_KP_9:
+ return kp_9_xkeycode_;
+ case XK_KP_Decimal:
+ return kp_decimal_xkeycode_;
+ }
+ return 0U;
+}
#endif
void KeyRewriter::Rewrite(aura::KeyEvent* event) {
RewriteCommandToControl(event);
+ RewriteModifiers(event);
RewriteNumPadKeys(event);
- // TODO(yusukes): Implement crbug.com/115112 (Search/Ctrl/Alt remapping) and
- // crosbug.com/27167 (allow sending function keys) here.
+ // TODO(yusukes): Implement crosbug.com/27167 (allow sending function keys).
}
bool KeyRewriter::RewriteCommandToControl(aura::KeyEvent* event) {
@@ -232,6 +366,91 @@ bool KeyRewriter::RewriteCommandToControl(aura::KeyEvent* event) {
return rewritten;
}
+bool KeyRewriter::RewriteModifiers(aura::KeyEvent* event) {
+ bool rewritten = false;
Daniel Erat 2012/05/23 16:37:32 nit: maybe remove this variable and just return fa
Yusuke Sato 2012/05/24 08:24:42 Sure, removed the variable.
+ PrefService* pref_service = pref_service_ ? pref_service_ : GetPrefService();
+ if (!pref_service)
+ return rewritten;
+
+#if defined(OS_CHROMEOS)
+ XEvent* xev = event->native_event();
+ XKeyEvent* xkey = &(xev->xkey);
+ KeySym keysym = XLookupKeysym(xkey, 0);
+
+ ui::KeyboardCode remapped_keycode = event->key_code();
+ unsigned int remapped_native_keycode = xkey->keycode;
Daniel Erat 2012/05/23 16:37:32 nit: KeyCode
Yusuke Sato 2012/05/24 08:24:42 Done.
+ int remapped_flags = 0;
+ unsigned int remapped_native_flags = 0U;
+
+ // First, remap |keysym|.
+ const char* key_name = NULL;
+ switch (keysym) {
+ case XK_Super_L:
+ key_name = prefs::kLanguageXkbRemapSearchKeyTo;
+ break;
+ case XK_Control_L:
+ case XK_Control_R:
+ key_name = prefs::kLanguageXkbRemapControlKeyTo;
+ break;
+ case XK_Alt_L:
+ case XK_Alt_R:
+ case XK_Meta_L:
+ case XK_Meta_R:
+ key_name = prefs::kLanguageXkbRemapAltKeyTo;
+ break;
Daniel Erat 2012/05/23 16:37:32 nit: add a no-op default? think that some compile
Yusuke Sato 2012/05/24 08:24:42 Done.
+ }
+ if (key_name) {
+ const ModifierRemapping* remapped_key =
+ GetRemappedKey(key_name, pref_service);
+ if (remapped_key) {
+ remapped_keycode = remapped_key->keycode;
+ const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) +
+ (IsRight(keysym) ? (1 << 0) : 0);
+ const KeySym native_keysym = remapped_key->native_keysyms[level];
+ remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym);
+ }
+ }
+
+ // Next, remap modifier bits.
+ for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) {
+ if (xkey->state & kModifierFlagToPrefName[i].native_flag) {
+ const ModifierRemapping* remapped_key =
+ GetRemappedKey(kModifierFlagToPrefName[i].key_name, pref_service);
+ if (remapped_key) {
+ remapped_flags |= remapped_key->flag;
+ remapped_native_flags |= remapped_key->native_flag;
+ } else {
+ remapped_flags |= kModifierFlagToPrefName[i].flag;
+ remapped_native_flags |= kModifierFlagToPrefName[i].native_flag;
+ }
+ }
+ }
+ remapped_flags = (event->flags() & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) |
+ remapped_flags;
+ remapped_native_flags = (xkey->state & ~(Mod4Mask | ControlMask | Mod1Mask)) |
+ remapped_native_flags;
+
+ // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
+ // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
+ // keyboard is pressed) since X can handle that case.
+ if ((event->type() == ui::ET_KEY_PRESSED) &&
+ (event->key_code() != ui::VKEY_CAPITAL) &&
+ (remapped_keycode == ui::VKEY_CAPITAL)) {
+ chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_ ?
+ xkeyboard_ : InputMethodManager::GetInstance()->GetXKeyboard();
+ xkeyboard->SetCapsLockEnabled(!xkeyboard->CapsLockIsEnabled());
+ }
+
+ OverwriteEvent(event,
+ remapped_native_keycode, remapped_native_flags,
+ remapped_keycode, remapped_flags);
+ rewritten = true;
+#else
+ // TODO(yusukes): Support Ash on other platforms if needed.
+#endif
+ return rewritten;
+}
+
bool KeyRewriter::RewriteNumPadKeys(aura::KeyEvent* event) {
bool rewritten = false;
#if defined(OS_CHROMEOS)

Powered by Google App Engine
This is Rietveld 408576698