Chromium Code Reviews| Index: chrome/browser/chromeos/events/event_rewriter.cc |
| diff --git a/chrome/browser/chromeos/events/event_rewriter.cc b/chrome/browser/chromeos/events/event_rewriter.cc |
| index 75e86637fe115839d249d26e928f85961da40f73..81d99a6766663ce21c7564fa45834771dde2f9bd 100644 |
| --- a/chrome/browser/chromeos/events/event_rewriter.cc |
| +++ b/chrome/browser/chromeos/events/event_rewriter.cc |
| @@ -4,10 +4,10 @@ |
| #include "chrome/browser/chromeos/events/event_rewriter.h" |
| +#if defined(USE_X11) |
| #include <X11/extensions/XInput2.h> |
| -#include <X11/keysym.h> |
| -#include <X11/XF86keysym.h> |
| #include <X11/Xlib.h> |
| +#endif |
| // Get rid of macros from Xlib.h that conflicts with other parts of the code. |
| #undef RootWindow |
|
Daniel Erat
2014/04/22 23:58:36
can you move these #undefs into the #if block?
kpschoedel
2014/04/23 15:46:22
Done.
|
| #undef Status |
| @@ -21,7 +21,6 @@ |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/string_util.h" |
| #include "base/sys_info.h" |
| -#include "chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h" |
| #include "chrome/browser/chromeos/login/login_display_host_impl.h" |
| #include "chrome/browser/chromeos/login/user_manager.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| @@ -29,10 +28,8 @@ |
| #include "chromeos/chromeos_switches.h" |
| #include "chromeos/ime/ime_keyboard.h" |
| #include "chromeos/ime/input_method_manager.h" |
| -#include "ui/base/x/x11_util.h" |
| #include "ui/events/event.h" |
| #include "ui/events/event_utils.h" |
| -#include "ui/events/keycodes/keyboard_code_conversion_x.h" |
| #include "ui/events/platform/platform_event_source.h" |
| #include "ui/wm/core/window_util.h" |
| @@ -44,43 +41,34 @@ const int kBadDeviceId = -1; |
| const struct ModifierRemapping { |
| int remap_to; |
| int flag; |
| - unsigned int native_modifier; |
| - ui::KeyboardCode keycode; |
| - KeySym native_keysyms[4]; // left, right, shift+left, shift+right. |
| + ui::KeyboardCode key_code; |
| + const char* pref_name; |
| } 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 }}, |
| - { chromeos::input_method::kEscapeKey, 0, 0U, ui::VKEY_ESCAPE, |
| - { XK_Escape, XK_Escape, XK_Escape, XK_Escape }}, |
| + { chromeos::input_method::kSearchKey, |
| + ui::EF_COMMAND_DOWN, ui::VKEY_LWIN, |
| + prefs::kLanguageRemapSearchKeyTo }, |
| + { chromeos::input_method::kControlKey, |
| + ui::EF_CONTROL_DOWN, ui::VKEY_CONTROL, |
| + prefs::kLanguageRemapControlKeyTo }, |
| + { chromeos::input_method::kAltKey, |
| + ui::EF_ALT_DOWN, ui::VKEY_MENU, |
| + prefs::kLanguageRemapAltKeyTo }, |
| + { chromeos::input_method::kVoidKey, |
| + 0, ui::VKEY_UNKNOWN, |
| + 0 }, |
|
Daniel Erat
2014/04/22 23:58:36
s/0/NULL/
kpschoedel
2014/04/23 15:46:22
Done.
|
| + { chromeos::input_method::kCapsLockKey, |
| + ui::EF_CAPS_LOCK_DOWN, ui::VKEY_CAPITAL, |
| + prefs::kLanguageRemapCapsLockKeyTo }, |
| + { chromeos::input_method::kEscapeKey, |
| + 0, ui::VKEY_ESCAPE, |
| + 0 }, |
|
Daniel Erat
2014/04/22 23:58:36
s/0/NULL/
kpschoedel
2014/04/23 15:46:22
Done.
|
| + { 0, |
| + 0, ui::VKEY_F15, |
| + prefs::kLanguageRemapDiamondKeyTo }, |
| }; |
| const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1]; |
| -// A structure for converting |native_modifier| to a pair of |flag| and |
| -// |pref_name|. |
| -const struct ModifierFlagToPrefName { |
| - unsigned int native_modifier; |
| - int flag; |
| - const char* pref_name; |
| -} kModifierFlagToPrefName[] = { |
| - // TODO(yusukes): When the device has a Chrome keyboard (i.e. the one without |
| - // Caps Lock), we should not check kLanguageRemapCapsLockKeyTo. |
| - { Mod3Mask, 0, prefs::kLanguageRemapCapsLockKeyTo }, |
| - { Mod4Mask, 0, prefs::kLanguageRemapSearchKeyTo }, |
| - { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageRemapControlKeyTo }, |
| - { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageRemapAltKeyTo }, |
| - { Mod2Mask, 0, prefs::kLanguageRemapDiamondKeyTo }, |
| -}; |
| - |
| // Gets a remapped key for |pref_name| key. For example, to find out which |
| // key Search is currently remapped to, call the function with |
| // prefs::kLanguageRemapSearchKeyTo. |
| @@ -96,26 +84,6 @@ const ModifierRemapping* GetRemappedKey(const std::string& pref_name, |
| return NULL; |
| } |
| -bool IsRight(KeySym native_keysym) { |
| - 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; |
| - default: |
| - break; |
| - } |
| - return false; |
| -} |
| - |
| -bool HasDiamondKey() { |
| - return CommandLine::ForCurrentProcess()->HasSwitch( |
| - chromeos::switches::kHasChromeOSDiamondKey); |
| -} |
| - |
| bool IsISOLevel5ShiftUsedByCurrentInputMethod() { |
| // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask, |
| // it's not possible to make both features work. For now, we don't remap |
| @@ -126,36 +94,7 @@ bool IsISOLevel5ShiftUsedByCurrentInputMethod() { |
| return manager->IsISOLevel5ShiftUsedByCurrentInputMethod(); |
| } |
| -} // namespace |
| - |
| -namespace chromeos { |
| - |
| -EventRewriter::EventRewriter() |
| - : last_device_id_(kBadDeviceId), |
| - keyboard_for_testing_(NULL), |
| - pref_service_for_testing_(NULL) { |
| - ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); |
| - if (base::SysInfo::IsRunningOnChromeOS()) { |
| - XInputHierarchyChangedEventListener::GetInstance()->AddObserver(this); |
| - } |
| - RefreshKeycodes(); |
| -} |
| - |
| -EventRewriter::~EventRewriter() { |
| - ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this); |
| - if (base::SysInfo::IsRunningOnChromeOS()) { |
| - XInputHierarchyChangedEventListener::GetInstance()->RemoveObserver(this); |
| - } |
| -} |
| - |
| -EventRewriter::DeviceType EventRewriter::DeviceAddedForTesting( |
| - int device_id, |
| - const std::string& device_name) { |
| - return DeviceAddedInternal(device_id, device_name); |
| -} |
| - |
| -// static |
| -EventRewriter::DeviceType EventRewriter::GetDeviceType( |
| +chromeos::EventRewriter::DeviceType GetDeviceType( |
| const std::string& device_name) { |
| std::vector<std::string> tokens; |
| Tokenize(device_name, " .", &tokens); |
| @@ -170,102 +109,114 @@ EventRewriter::DeviceType EventRewriter::GetDeviceType( |
| if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard")) |
| found_keyboard = true; |
| if (found_apple && found_keyboard) |
| - return kDeviceAppleKeyboard; |
| + return chromeos::EventRewriter::kDeviceAppleKeyboard; |
| } |
| - return kDeviceUnknown; |
| + return chromeos::EventRewriter::kDeviceUnknown; |
| } |
| -void EventRewriter::RewriteForTesting(XEvent* event) { |
| - Rewrite(event); |
| -} |
| +} // namespace |
| -void EventRewriter::DeviceKeyPressedOrReleased(int device_id) { |
| - std::map<int, DeviceType>::const_iterator iter = |
| - device_id_to_type_.find(device_id); |
| - if (iter == device_id_to_type_.end()) { |
| - // |device_id| is unknown. This means the device was connected before |
| - // booting the OS. Query the name of the device and add it to the map. |
| - DeviceAdded(device_id); |
| - } |
| +namespace chromeos { |
| - last_device_id_ = device_id; |
| +EventRewriter::EventRewriter() |
| + : last_device_id_(kBadDeviceId), |
| + ime_keyboard_for_testing_(NULL), |
| + pref_service_for_testing_(NULL) {} |
| + |
| +EventRewriter::~EventRewriter() {} |
| + |
| +EventRewriter::DeviceType EventRewriter::DeviceAddedForTesting( |
| + int device_id, |
| + const std::string& device_name) { |
| + return DeviceAddedInternal(device_id, device_name); |
| } |
| -void EventRewriter::WillProcessEvent(const ui::PlatformEvent& event) { |
| - XEvent* xevent = event; |
| - if (xevent->type == KeyPress || xevent->type == KeyRelease) { |
| - Rewrite(xevent); |
| - } else if (xevent->type == GenericEvent) { |
| - XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data); |
| - if (xievent->evtype == XI_KeyPress || xievent->evtype == XI_KeyRelease) { |
| - if (xievent->deviceid == xievent->sourceid) |
| - DeviceKeyPressedOrReleased(xievent->deviceid); |
| - } else { |
| - RewriteLocatedEvent(xevent); |
| +void EventRewriter::RewriteLocatedEventForTesting( |
| + const ui::Event& event, |
| + int* flags) { |
| + MutableKeyState state = {*flags, ui::VKEY_UNKNOWN}; |
| + RewriteLocatedEvent(event, &state); |
| + *flags = state.flags; |
| +} |
| + |
| +ui::EventRewriteStatus EventRewriter::RewriteEvent( |
| + const ui::Event& event, |
| + scoped_ptr<ui::Event>* rewritten_event) { |
| + if ((event.type() == ui::ET_KEY_PRESSED) || |
|
Daniel Erat
2014/04/22 23:58:36
nit: switch statement instead of if/else here
kpschoedel
2014/04/23 15:46:22
Done.
|
| + (event.type() == ui::ET_KEY_RELEASED)) { |
| + const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event); |
| + MutableKeyState state = {key_event.flags(), key_event.key_code()}; |
| + RewriteModifierKeys(key_event, &state); |
| + RewriteNumPadKeys(key_event, &state); |
| + RewriteExtendedKeys(key_event, &state); |
| + RewriteFunctionKeys(key_event, &state); |
| + if ((key_event.flags() != state.flags) || |
| + (key_event.key_code() != state.key_code)) { |
| + ui::KeyEvent* rewritten_key_event = new ui::KeyEvent(key_event); |
| + rewritten_event->reset(rewritten_key_event); |
| + rewritten_key_event->set_flags(state.flags); |
| + rewritten_key_event->set_key_code(state.key_code); |
| + return ui::EVENT_REWRITE_REWRITTEN; |
| } |
| - } else if (xevent->type == MappingNotify) { |
| - if (xevent->xmapping.request == MappingModifier || |
| - xevent->xmapping.request == MappingKeyboard) { |
| - RefreshKeycodes(); |
| + } else if ((event.type() == ui::ET_MOUSE_PRESSED) || |
| + (event.type() == ui::ET_MOUSE_RELEASED) || |
| + (event.type() == ui::ET_TOUCH_PRESSED) || |
| + (event.type() == ui::ET_TOUCH_RELEASED)) { |
| + MutableKeyState state = {event.flags(), ui::VKEY_UNKNOWN}; |
| + RewriteLocatedEvent(event, &state); |
| + if (event.flags() != state.flags) { |
| + if (event.IsMouseEvent()) |
|
Daniel Erat
2014/04/22 23:58:36
add curly brackets since the statement is more tha
kpschoedel
2014/04/23 15:46:22
Done. Sorry, I mistook the ‘one line’ rule as ‘one
|
| + rewritten_event->reset( |
| + new ui::MouseEvent(static_cast<const ui::MouseEvent&>(event))); |
| + else |
|
Daniel Erat
2014/04/22 23:58:36
here too
kpschoedel
2014/04/23 15:46:22
Done.
|
| + rewritten_event->reset( |
| + new ui::TouchEvent(static_cast<const ui::TouchEvent&>(event))); |
| + rewritten_event->get()->set_flags(state.flags); |
| + return ui::EVENT_REWRITE_REWRITTEN; |
| } |
| } |
| + return ui::EVENT_REWRITE_CONTINUE; |
| } |
| -void EventRewriter::DidProcessEvent(const ui::PlatformEvent& event) { |
| +ui::EventRewriteStatus EventRewriter::NextDispatchEvent( |
| + const ui::Event& last_event, |
| + scoped_ptr<ui::Event>* new_event) { |
| + NOTREACHED(); |
| + return ui::EVENT_REWRITE_CONTINUE; |
| } |
| -void EventRewriter::DeviceHierarchyChanged() {} |
| - |
| -void EventRewriter::DeviceAdded(int device_id) { |
| - DCHECK_NE(XIAllDevices, device_id); |
| - DCHECK_NE(XIAllMasterDevices, device_id); |
| - if (device_id == XIAllDevices || device_id == XIAllMasterDevices) { |
| - LOG(ERROR) << "Unexpected device_id passed: " << device_id; |
| - return; |
| - } |
| - |
| - int ndevices_return = 0; |
| - XIDeviceInfo* device_info = XIQueryDevice(gfx::GetXDisplay(), |
| - device_id, |
| - &ndevices_return); |
| +const PrefService* EventRewriter::GetPrefService() const { |
| + if (pref_service_for_testing_) |
| + return pref_service_for_testing_; |
| + Profile* profile = ProfileManager::GetActiveUserProfile(); |
| + return profile ? profile->GetPrefs() : NULL; |
| +} |
| - // Since |device_id| is neither XIAllDevices nor XIAllMasterDevices, |
| - // the number of devices found should be either 0 (not found) or 1. |
| - if (!device_info) { |
| - LOG(ERROR) << "XIQueryDevice: Device ID " << device_id << " is unknown."; |
| - return; |
| - } |
| +bool EventRewriter::IsAppleKeyboard(const ui::Event& event) const { |
| + if (last_device_id_ == kBadDeviceId) |
| + return false; |
| - DCHECK_EQ(1, ndevices_return); |
| - for (int i = 0; i < ndevices_return; ++i) { |
| - DCHECK_EQ(device_id, device_info[i].deviceid); // see the comment above. |
| - DCHECK(device_info[i].name); |
| - DeviceAddedInternal(device_info[i].deviceid, device_info[i].name); |
| + // Check which device generated |event|. |
| + std::map<int, DeviceType>::const_iterator iter = |
| + device_id_to_type_.find(last_device_id_); |
| + if (iter == device_id_to_type_.end()) { |
| + LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown."; |
| + return false; |
| } |
| - XIFreeDeviceInfo(device_info); |
| -} |
| - |
| -void EventRewriter::DeviceRemoved(int device_id) { |
| - device_id_to_type_.erase(device_id); |
| -} |
| - |
| -void EventRewriter::RefreshKeycodes() { |
| - keysym_to_keycode_map_.clear(); |
| + const DeviceType type = iter->second; |
| + return type == kDeviceAppleKeyboard; |
| } |
| -KeyCode EventRewriter::NativeKeySymToNativeKeycode(KeySym keysym) { |
| - if (keysym_to_keycode_map_.count(keysym)) |
| - return keysym_to_keycode_map_[keysym]; |
| - XDisplay* display = gfx::GetXDisplay(); |
| - KeyCode keycode = XKeysymToKeycode(display, keysym); |
| - keysym_to_keycode_map_[keysym] = keycode; |
| - return keycode; |
| +bool EventRewriter::HasDiamondKey(const ui::Event& event) const { |
| + return CommandLine::ForCurrentProcess()->HasSwitch( |
| + chromeos::switches::kHasChromeOSDiamondKey); |
| } |
| -bool EventRewriter::TopRowKeysAreFunctionKeys(XEvent* event) const { |
| +bool EventRewriter::TopRowKeysAreFunctionKeys( |
| + const ui::Event& event) const { |
| const PrefService* prefs = GetPrefService(); |
| if (prefs && |
| prefs->FindPreference(prefs::kLanguageSendFunctionKeys) && |
| @@ -276,149 +227,68 @@ bool EventRewriter::TopRowKeysAreFunctionKeys(XEvent* event) const { |
| return state ? state->top_row_keys_are_function_keys() : false; |
| } |
| -bool EventRewriter::RewriteWithKeyboardRemappingsByKeySym( |
| - const KeyboardRemapping* remappings, |
| - size_t num_remappings, |
| - KeySym keysym, |
| - unsigned int native_mods, |
| - KeySym* remapped_native_keysym, |
| - unsigned int* remapped_native_mods) { |
| - for (size_t i = 0; i < num_remappings; ++i) { |
| - const KeyboardRemapping& map = remappings[i]; |
| - |
| - if (keysym != map.input_keysym) |
| - continue; |
| - unsigned int matched_mods = native_mods & map.input_native_mods; |
| - if (matched_mods != map.input_native_mods) |
| - continue; |
| - |
| - *remapped_native_keysym = map.output_keysym; |
| - *remapped_native_mods = (native_mods & ~map.input_native_mods) | |
| - map.output_native_mods; |
| - return true; |
| +int EventRewriter::GetRemappedModifierMasks( |
| + const PrefService& pref_service, |
| + const ui::Event& event, |
| + int original_flags) const { |
| + int unmodified_flags = original_flags; |
| + int rewritten_flags = 0; |
| + for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) { |
| + const ModifierRemapping* remapped_key = 0; |
| + if (unmodified_flags & kModifierRemappings[i].flag) { |
| + switch (kModifierRemappings[i].flag) { |
| + default: |
|
Daniel Erat
2014/04/22 23:58:36
huh, i didn't know that putting default first like
kpschoedel
2014/04/23 15:46:22
Done.
|
| + break; |
| + case ui::EF_COMMAND_DOWN: |
| + // Rewrite Command key presses on an Apple keyboard to Control. |
| + if (IsAppleKeyboard(event)) { |
| + DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag); |
| + remapped_key = kModifierRemappingCtrl; |
| + } |
| + break; |
| + case ui::EF_CAPS_LOCK_DOWN: |
| + // If CapsLock is used by the current input method, don't allow the |
| + // CapsLock pref to remap it, or the keyboard behavior will be broken. |
| + if (IsISOLevel5ShiftUsedByCurrentInputMethod()) |
| + continue; |
| + break; |
| + } |
| + if (!remapped_key && kModifierRemappings[i].pref_name) |
|
Daniel Erat
2014/04/22 23:58:36
add curly brackets
kpschoedel
2014/04/23 15:46:22
Done.
|
| + remapped_key = |
| + GetRemappedKey(kModifierRemappings[i].pref_name, pref_service); |
| + if (remapped_key) { |
| + unmodified_flags &= ~kModifierRemappings[i].flag; |
| + rewritten_flags |= remapped_key->flag; |
| + } |
| + } |
| } |
| - |
| - return false; |
| + return rewritten_flags | unmodified_flags; |
| } |
| bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode( |
| const KeyboardRemapping* remappings, |
| size_t num_remappings, |
| - KeyCode keycode, |
| - unsigned int native_mods, |
| - KeySym* remapped_native_keysym, |
| - unsigned int* remapped_native_mods) { |
| + const MutableKeyState& input, |
| + MutableKeyState* remapped) { |
| for (size_t i = 0; i < num_remappings; ++i) { |
| const KeyboardRemapping& map = remappings[i]; |
| - |
| - KeyCode input_keycode = NativeKeySymToNativeKeycode(map.input_keysym); |
| - if (keycode != input_keycode) |
| + if (input.key_code != map.input_key_code) |
| continue; |
| - unsigned int matched_mods = native_mods & map.input_native_mods; |
| - if (matched_mods != map.input_native_mods) |
| + if ((input.flags & map.input_flags) != map.input_flags) |
| continue; |
| - |
| - *remapped_native_keysym = map.output_keysym; |
| - *remapped_native_mods = (native_mods & ~map.input_native_mods) | |
| - map.output_native_mods; |
| + remapped->key_code = map.output_key_code; |
| + remapped->flags = (input.flags & ~map.input_flags) | map.output_flags; |
| return true; |
| } |
| - |
| return false; |
| } |
| -const PrefService* EventRewriter::GetPrefService() const { |
| - if (pref_service_for_testing_) |
| - return pref_service_for_testing_; |
| - Profile* profile = ProfileManager::GetActiveUserProfile(); |
| - return profile ? profile->GetPrefs() : NULL; |
| -} |
| - |
| -void EventRewriter::Rewrite(XEvent* event) { |
| - // Do not rewrite an event sent by ui_controls::SendKeyPress(). See |
| - // crbug.com/136465. |
| - if (event->xkey.send_event) |
| - return; |
| +void EventRewriter::RewriteModifierKeys( |
| + const ui::KeyEvent& key_event, |
| + MutableKeyState* state) { |
| + DCHECK(key_event.type() == ui::ET_KEY_PRESSED || |
| + key_event.type() == ui::ET_KEY_RELEASED); |
| - RewriteModifiers(event); |
| - RewriteNumPadKeys(event); |
| - RewriteExtendedKeys(event); |
| - RewriteFunctionKeys(event); |
| -} |
| - |
| -bool EventRewriter::IsAppleKeyboard() const { |
| - if (last_device_id_ == kBadDeviceId) |
| - return false; |
| - |
| - // Check which device generated |event|. |
| - std::map<int, DeviceType>::const_iterator iter = |
| - device_id_to_type_.find(last_device_id_); |
| - if (iter == device_id_to_type_.end()) { |
| - LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown."; |
| - return false; |
| - } |
| - |
| - const DeviceType type = iter->second; |
| - return type == kDeviceAppleKeyboard; |
| -} |
| - |
| -void EventRewriter::GetRemappedModifierMasks( |
| - unsigned int original_native_modifiers, |
| - unsigned int* remapped_native_modifiers) const { |
| - // TODO(glotov): remove the following condition when we do not restart chrome |
| - // when user logs in as guest. See Rewrite() for details. |
| - if (UserManager::Get()->IsLoggedInAsGuest() && |
| - LoginDisplayHostImpl::default_host()) { |
| - return; |
| - } |
| - |
| - const PrefService* pref_service = GetPrefService(); |
| - if (!pref_service) |
| - return; |
| - |
| - // When a diamond key is not available, a Mod2Mask should not treated as a |
| - // configurable modifier because Mod2Mask may be worked as NumLock mask. |
| - // (cf. http://crbug.com/173956) |
| - const bool skip_mod2 = !HasDiamondKey(); |
| - // If Mod3 is used by the current input method, don't allow the CapsLock |
| - // pref to remap it, or the keyboard behavior will be broken. |
| - const bool skip_mod3 = IsISOLevel5ShiftUsedByCurrentInputMethod(); |
| - |
| - for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { |
| - if ((skip_mod2 && kModifierFlagToPrefName[i].native_modifier == Mod2Mask) || |
| - (skip_mod3 && kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) { |
| - continue; |
| - } |
| - if (original_native_modifiers & |
| - kModifierFlagToPrefName[i].native_modifier) { |
| - const ModifierRemapping* remapped_key = |
| - GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); |
| - // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. |
| - if (IsAppleKeyboard() && |
| - (kModifierFlagToPrefName[i].native_modifier == Mod4Mask)) { |
| - remapped_key = kModifierRemappingCtrl; |
| - } |
| - if (remapped_key) { |
| - *remapped_native_modifiers |= remapped_key->native_modifier; |
| - } else { |
| - *remapped_native_modifiers |= |
| - kModifierFlagToPrefName[i].native_modifier; |
| - } |
| - } |
| - } |
| - |
| - unsigned int native_mask = Mod4Mask | ControlMask | Mod1Mask; |
| - if (!skip_mod2) |
| - native_mask |= Mod2Mask; |
| - if (!skip_mod3) |
| - native_mask |= Mod3Mask; |
| - *remapped_native_modifiers = |
| - (original_native_modifiers & ~native_mask) | |
| - *remapped_native_modifiers; |
| -} |
| - |
| -bool EventRewriter::RewriteModifiers(XEvent* event) { |
| - DCHECK(event->type == KeyPress || event->type == KeyRelease); |
| // Do nothing if we have just logged in as guest but have not restarted chrome |
| // process yet (so we are still on the login screen). In this situations we |
| // have no user profile so can not do anything useful. |
| @@ -426,66 +296,69 @@ bool EventRewriter::RewriteModifiers(XEvent* event) { |
| // restart chrome process. In future this is to be changed. |
| // TODO(glotov): remove the following condition when we do not restart chrome |
| // when user logs in as guest. |
| + // TODO(kpschoedel): check whether this is still necessary. |
| if (UserManager::Get()->IsLoggedInAsGuest() && |
| LoginDisplayHostImpl::default_host()) |
| - return false; |
| + return; |
| const PrefService* pref_service = GetPrefService(); |
| if (!pref_service) |
| - return false; |
| - |
| - DCHECK_EQ(input_method::kControlKey, kModifierRemappingCtrl->remap_to); |
| + return; |
| - XKeyEvent* xkey = &event->xkey; |
| - KeySym keysym = XLookupKeysym(xkey, 0); |
| - ui::KeyboardCode original_keycode = ui::KeyboardCodeFromNative(event); |
| - ui::KeyboardCode remapped_keycode = original_keycode; |
| - KeyCode remapped_native_keycode = xkey->keycode; |
| + MutableKeyState incoming = *state; |
| + state->flags = ui::EF_NONE; |
| + int characteristic_flag = ui::EF_NONE; |
| - // First, remap |keysym|. |
| + // First, remap the key code. |
| const ModifierRemapping* remapped_key = NULL; |
| - switch (keysym) { |
| - // On Chrome OS, XF86XK_Launch6 (F15) with Mod2Mask is sent when Diamond |
| - // key is pressed. |
| - case XF86XK_Launch6: |
| + switch (incoming.key_code) { |
| + // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent |
| + // when Diamond key is pressed. |
| + case ui::VKEY_F15: |
| // When diamond key is not available, the configuration UI for Diamond |
| // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo |
| // syncable pref. |
| - if (HasDiamondKey()) |
| + if (HasDiamondKey(key_event)) |
| remapped_key = |
| GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service); |
| // Default behavior is Ctrl key. |
| - if (!remapped_key) |
| + if (!remapped_key) { |
| + DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code); |
| remapped_key = kModifierRemappingCtrl; |
| + characteristic_flag = ui::EF_CONTROL_DOWN; |
| + } |
| break; |
| // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock |
| // is pressed (with one exception: when |
| // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates |
| // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7). |
| - case XF86XK_Launch7: |
| + case ui::VKEY_F16: |
| + characteristic_flag = ui::EF_CAPS_LOCK_DOWN; |
| remapped_key = |
| GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service); |
| break; |
| - case XK_Super_L: |
| - case XK_Super_R: |
| - // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. |
| - if (IsAppleKeyboard()) |
| + case ui::VKEY_LWIN: |
| + case ui::VKEY_RWIN: |
| + characteristic_flag = ui::EF_COMMAND_DOWN; |
| + // Rewrite Command-L/R key presses on an Apple keyboard to Control. |
| + if (IsAppleKeyboard(key_event)) { |
| + DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code); |
| remapped_key = kModifierRemappingCtrl; |
| - else |
| + } else { |
| remapped_key = |
| GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service); |
| + } |
| // Default behavior is Super key, hence don't remap the event if the pref |
| // is unavailable. |
| break; |
| - case XK_Control_L: |
| - case XK_Control_R: |
| + case ui::VKEY_CONTROL: |
| + characteristic_flag = ui::EF_CONTROL_DOWN; |
| remapped_key = |
| GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service); |
| break; |
| - case XK_Alt_L: |
| - case XK_Alt_R: |
| - case XK_Meta_L: |
| - case XK_Meta_R: |
| + case ui::VKEY_MENU: |
| + // ALT key |
| + characteristic_flag = ui::EF_ALT_DOWN; |
| remapped_key = |
| GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service); |
| break; |
| @@ -494,308 +367,259 @@ bool EventRewriter::RewriteModifiers(XEvent* event) { |
| } |
| if (remapped_key) { |
| - int flags = ui::EventFlagsFromNative(event); |
| - remapped_keycode = remapped_key->keycode; |
| - const size_t level = ((flags & ui::EF_SHIFT_DOWN) ? (1 << 1) : 0) + |
| - (IsRight(keysym) ? (1 << 0) : 0); |
| - const KeySym native_keysym = remapped_key->native_keysyms[level]; |
| - remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym); |
| + state->key_code = remapped_key->key_code; |
| + incoming.flags |= characteristic_flag; |
| + characteristic_flag = remapped_key->flag; |
| } |
| // Next, remap modifier bits. |
| - unsigned int remapped_native_modifiers = 0U; |
| - GetRemappedModifierMasks(xkey->state, &remapped_native_modifiers); |
| + state->flags |= |
| + GetRemappedModifierMasks(*pref_service, key_event, incoming.flags); |
| + if (key_event.type() == ui::ET_KEY_PRESSED) |
| + state->flags |= characteristic_flag; |
| + else |
| + state->flags &= ~characteristic_flag; |
| // 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 == KeyPress && |
| - original_keycode != ui::VKEY_CAPITAL && |
| - remapped_keycode == ui::VKEY_CAPITAL) { |
| - input_method::ImeKeyboard* keyboard = keyboard_for_testing_ ? |
| - keyboard_for_testing_ : |
| - input_method::InputMethodManager::Get()->GetImeKeyboard(); |
| - keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled()); |
| + if (key_event.type() == ui::ET_KEY_PRESSED && |
| + incoming.key_code != ui::VKEY_CAPITAL && |
| + state->key_code == ui::VKEY_CAPITAL) { |
| + chromeos::input_method::ImeKeyboard* ime_keyboard = |
| + ime_keyboard_for_testing_ |
| + ? ime_keyboard_for_testing_ |
| + : chromeos::input_method::InputMethodManager::Get() |
| + ->GetImeKeyboard(); |
| + ime_keyboard->SetCapsLockEnabled(!ime_keyboard->CapsLockIsEnabled()); |
| } |
| - |
| - OverwriteEvent(event, remapped_native_keycode, remapped_native_modifiers); |
| - return true; |
| } |
| -bool EventRewriter::RewriteNumPadKeys(XEvent* event) { |
| - DCHECK(event->type == KeyPress || event->type == KeyRelease); |
| - bool rewritten = false; |
| - XKeyEvent* xkey = &event->xkey; |
| - const KeySym keysym = XLookupKeysym(xkey, 0); |
| - switch (keysym) { |
| - case XK_KP_Insert: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_0), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Delete: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_Decimal), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_End: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_1), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Down: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_2), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Next: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_3), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Left: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_4), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Begin: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_5), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Right: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_6), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Home: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_7), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Up: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_8), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Prior: |
| - OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_9), |
| - xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - case XK_KP_Divide: |
| - case XK_KP_Multiply: |
| - case XK_KP_Subtract: |
| - case XK_KP_Add: |
| - case XK_KP_Enter: |
| - // Add Mod2Mask for consistency. |
| - OverwriteEvent(event, xkey->keycode, xkey->state | Mod2Mask); |
| - rewritten = true; |
| - break; |
| - default: |
| - break; |
| - } |
| - return rewritten; |
| +void EventRewriter::RewriteNumPadKeys( |
| + const ui::KeyEvent& key_event, |
| + MutableKeyState* state) { |
| + DCHECK(key_event.type() == ui::ET_KEY_PRESSED || |
| + key_event.type() == ui::ET_KEY_RELEASED); |
| + if (!(state->flags & ui::EF_NUMPAD_KEY)) |
| + return; |
| + MutableKeyState incoming = *state; |
| + |
| + static const KeyboardRemapping kNumPadRemappings[] = { |
| + { |
| + ui::VKEY_INSERT, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD0, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_DELETE, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_DECIMAL, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_END, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD1, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_DOWN, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD2, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_NEXT, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD3, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_LEFT, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD4, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_CLEAR, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD5, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_RIGHT, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD6, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_HOME, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD7, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_UP, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD8, ui::EF_NUMPAD_KEY |
| + }, |
| + { |
| + ui::VKEY_PRIOR, ui::EF_NUMPAD_KEY, |
| + ui::VKEY_NUMPAD9, ui::EF_NUMPAD_KEY |
| + }, |
| + }; |
| + |
| + RewriteWithKeyboardRemappingsByKeyCode( |
| + kNumPadRemappings, |
| + arraysize(kNumPadRemappings), |
| + incoming, |
| + state); |
| } |
| -bool EventRewriter::RewriteExtendedKeys(XEvent* event) { |
| - DCHECK(event->type == KeyPress || event->type == KeyRelease); |
| - XKeyEvent* xkey = &event->xkey; |
| - const KeySym keysym = XLookupKeysym(xkey, 0); |
| +void EventRewriter::RewriteExtendedKeys( |
| + const ui::KeyEvent& key_event, |
| + MutableKeyState* state) { |
| + DCHECK(key_event.type() == ui::ET_KEY_PRESSED || |
| + key_event.type() == ui::ET_KEY_RELEASED); |
| - KeySym remapped_native_keysym = 0; |
| - unsigned int remapped_native_mods = 0; |
| + MutableKeyState incoming = *state; |
| bool rewritten = false; |
| - if (xkey->state & Mod4Mask) { |
| + if ((incoming.flags & (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) == |
| + (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) { |
| // Allow Search to avoid rewriting extended keys. |
| static const KeyboardRemapping kAvoidRemappings[] = { |
| { // Alt+Backspace |
| - XK_BackSpace, Mod1Mask | Mod4Mask, |
| - XK_BackSpace, Mod1Mask, |
| + ui::VKEY_BACK, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, |
| + ui::VKEY_BACK, ui::EF_ALT_DOWN, |
| }, |
| { // Control+Alt+Up |
| - XK_Up, Mod1Mask | ControlMask | Mod4Mask, |
| - XK_Up, Mod1Mask | ControlMask, |
| + ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | |
| + ui::EF_COMMAND_DOWN, |
| + ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, |
| }, |
| { // Alt+Up |
| - XK_Up, Mod1Mask | Mod4Mask, |
| - XK_Up, Mod1Mask, |
| + ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, |
| + ui::VKEY_UP, ui::EF_ALT_DOWN, |
| }, |
| { // Control+Alt+Down |
| - XK_Down, Mod1Mask | ControlMask | Mod4Mask, |
| - XK_Down, Mod1Mask | ControlMask, |
| + ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | |
| + ui::EF_COMMAND_DOWN, |
| + ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, |
| }, |
| { // Alt+Down |
| - XK_Down, Mod1Mask | Mod4Mask, |
| - XK_Down, Mod1Mask, |
| + ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, |
| + ui::VKEY_DOWN, ui::EF_ALT_DOWN, |
| } |
| }; |
| - rewritten = RewriteWithKeyboardRemappingsByKeySym( |
| + rewritten = RewriteWithKeyboardRemappingsByKeyCode( |
| kAvoidRemappings, |
| arraysize(kAvoidRemappings), |
| - keysym, |
| - xkey->state, |
| - &remapped_native_keysym, |
| - &remapped_native_mods); |
| + incoming, |
| + state); |
| } |
| - if (!rewritten) { |
| + if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) { |
| static const KeyboardRemapping kSearchRemappings[] = { |
| { // Search+BackSpace -> Delete |
| - XK_BackSpace, Mod4Mask, |
| - XK_Delete, 0 |
| + ui::VKEY_BACK, ui::EF_COMMAND_DOWN, |
| + ui::VKEY_DELETE, 0 |
| }, |
| { // Search+Left -> Home |
| - XK_Left, Mod4Mask, |
| - XK_Home, 0 |
| + ui::VKEY_LEFT, ui::EF_COMMAND_DOWN, |
| + ui::VKEY_HOME, 0 |
| }, |
| { // Search+Up -> Prior (aka PageUp) |
| - XK_Up, Mod4Mask, |
| - XK_Prior, 0 |
| + ui::VKEY_UP, ui::EF_COMMAND_DOWN, |
| + ui::VKEY_PRIOR, 0 |
| }, |
| { // Search+Right -> End |
| - XK_Right, Mod4Mask, |
| - XK_End, 0 |
| + ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN, |
| + ui::VKEY_END, 0 |
| }, |
| { // Search+Down -> Next (aka PageDown) |
| - XK_Down, Mod4Mask, |
| - XK_Next, 0 |
| + ui::VKEY_DOWN, ui::EF_COMMAND_DOWN, |
| + ui::VKEY_NEXT, 0 |
| }, |
| { // Search+Period -> Insert |
| - XK_period, Mod4Mask, |
| - XK_Insert, 0 |
| + ui::VKEY_OEM_PERIOD, ui::EF_COMMAND_DOWN, |
| + ui::VKEY_INSERT, 0 |
| } |
| }; |
| - rewritten = RewriteWithKeyboardRemappingsByKeySym( |
| + rewritten = RewriteWithKeyboardRemappingsByKeyCode( |
| kSearchRemappings, |
| arraysize(kSearchRemappings), |
| - keysym, |
| - xkey->state, |
| - &remapped_native_keysym, |
| - &remapped_native_mods); |
| + incoming, |
| + state); |
| } |
| - if (!rewritten) { |
| + if (!rewritten && (incoming.flags & ui::EF_ALT_DOWN)) { |
| static const KeyboardRemapping kNonSearchRemappings[] = { |
| { // Alt+BackSpace -> Delete |
| - XK_BackSpace, Mod1Mask, |
| - XK_Delete, 0 |
| + ui::VKEY_BACK, ui::EF_ALT_DOWN, |
| + ui::VKEY_DELETE, 0 |
| }, |
| { // Control+Alt+Up -> Home |
| - XK_Up, Mod1Mask | ControlMask, |
| - XK_Home, 0 |
| + ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, |
| + ui::VKEY_HOME, 0 |
| }, |
| { // Alt+Up -> Prior (aka PageUp) |
| - XK_Up, Mod1Mask, |
| - XK_Prior, 0 |
| + ui::VKEY_UP, ui::EF_ALT_DOWN, |
| + ui::VKEY_PRIOR, 0 |
| }, |
| { // Control+Alt+Down -> End |
| - XK_Down, Mod1Mask | ControlMask, |
| - XK_End, 0 |
| + ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, |
| + ui::VKEY_END, 0 |
| }, |
| { // Alt+Down -> Next (aka PageDown) |
| - XK_Down, Mod1Mask, |
| - XK_Next, 0 |
| + ui::VKEY_DOWN, ui::EF_ALT_DOWN, |
| + ui::VKEY_NEXT, 0 |
| } |
| }; |
| - rewritten = RewriteWithKeyboardRemappingsByKeySym( |
| + rewritten = RewriteWithKeyboardRemappingsByKeyCode( |
| kNonSearchRemappings, |
| arraysize(kNonSearchRemappings), |
| - keysym, |
| - xkey->state, |
| - &remapped_native_keysym, |
| - &remapped_native_mods); |
| + incoming, |
| + state); |
| } |
| - |
| - if (!rewritten) |
| - return false; |
| - |
| - OverwriteEvent(event, |
| - NativeKeySymToNativeKeycode(remapped_native_keysym), |
| - remapped_native_mods); |
| - return true; |
| } |
| -bool EventRewriter::RewriteFunctionKeys(XEvent* event) { |
| - DCHECK(event->type == KeyPress || event->type == KeyRelease); |
| - XKeyEvent* xkey = &event->xkey; |
| - const KeySym keysym = XLookupKeysym(xkey, 0); |
| - |
| - KeySym remapped_native_keysym = 0; |
| - unsigned int remapped_native_mods = 0; |
| +void EventRewriter::RewriteFunctionKeys( |
| + const ui::KeyEvent& key_event, |
| + MutableKeyState* state) { |
| + CHECK(key_event.type() == ui::ET_KEY_PRESSED || |
| + key_event.type() == ui::ET_KEY_RELEASED); |
| + MutableKeyState incoming = *state; |
| bool rewritten = false; |
| - // By default the top row (F1-F12) keys are special keys for back, forward, |
| - // brightness, volume, etc. However, windows for v2 apps can optionally |
| - // request raw function keys for these keys. |
| - bool top_row_keys_are_special_keys = !TopRowKeysAreFunctionKeys(event); |
| - |
| - if ((xkey->state & Mod4Mask) && top_row_keys_are_special_keys) { |
| - // Allow Search to avoid rewriting F1-F12. |
| - static const KeyboardRemapping kFkeysToFkeys[] = { |
| - { XK_F1, Mod4Mask, XK_F1, }, |
| - { XK_F2, Mod4Mask, XK_F2, }, |
| - { XK_F3, Mod4Mask, XK_F3, }, |
| - { XK_F4, Mod4Mask, XK_F4, }, |
| - { XK_F5, Mod4Mask, XK_F5, }, |
| - { XK_F6, Mod4Mask, XK_F6, }, |
| - { XK_F7, Mod4Mask, XK_F7, }, |
| - { XK_F8, Mod4Mask, XK_F8, }, |
| - { XK_F9, Mod4Mask, XK_F9, }, |
| - { XK_F10, Mod4Mask, XK_F10, }, |
| - { XK_F11, Mod4Mask, XK_F11, }, |
| - { XK_F12, Mod4Mask, XK_F12, }, |
| - }; |
| - |
| - rewritten = RewriteWithKeyboardRemappingsByKeySym( |
| - kFkeysToFkeys, |
| - arraysize(kFkeysToFkeys), |
| - keysym, |
| - xkey->state, |
| - &remapped_native_keysym, |
| - &remapped_native_mods); |
| - } |
| - |
| - if (!rewritten) { |
| - static const KeyboardRemapping kFkeysToSpecialKeys[] = { |
| - { XK_F1, 0, XF86XK_Back, 0 }, |
| - { XK_F2, 0, XF86XK_Forward, 0 }, |
| - { XK_F3, 0, XF86XK_Reload, 0 }, |
| - { XK_F4, 0, XF86XK_LaunchB, 0 }, |
| - { XK_F5, 0, XF86XK_LaunchA, 0 }, |
| - { XK_F6, 0, XF86XK_MonBrightnessDown, 0 }, |
| - { XK_F7, 0, XF86XK_MonBrightnessUp, 0 }, |
| - { XK_F8, 0, XF86XK_AudioMute, 0 }, |
| - { XK_F9, 0, XF86XK_AudioLowerVolume, 0 }, |
| - { XK_F10, 0, XF86XK_AudioRaiseVolume, 0 }, |
| - }; |
| - |
| - if (top_row_keys_are_special_keys) { |
| + if ((incoming.key_code >= ui::VKEY_F1) && |
| + (incoming.key_code <= ui::VKEY_F24)) { |
| + // By default the top row (F1-F12) keys are special keys for back, forward, |
|
Daniel Erat
2014/04/22 23:58:36
s/special/system/g in this section of the code, ma
kpschoedel
2014/04/23 15:46:22
Done.
|
| + // brightness, volume, etc. However, windows for v2 apps can optionally |
| + // request raw function keys for these keys. |
| + bool top_row_keys_are_function_keys = TopRowKeysAreFunctionKeys(key_event); |
| + bool search_is_pressed = (incoming.flags & ui::EF_COMMAND_DOWN) != 0; |
| + |
| + // Search? Top Row Result |
| + // ------- -------- ------ |
| + // No Fn Unchanged |
| + // No Special Fn -> Special |
| + // Yes Fn Fn -> Special |
| + // Yes Special Search+Fn -> Fn |
| + if (top_row_keys_are_function_keys == search_is_pressed) { |
| // Rewrite the F1-F12 keys on a Chromebook keyboard to special keys. |
| - rewritten = RewriteWithKeyboardRemappingsByKeySym( |
| + static const KeyboardRemapping kFkeysToSpecialKeys[] = { |
| + { ui::VKEY_F1, 0, ui::VKEY_BROWSER_BACK, 0 }, |
| + { ui::VKEY_F2, 0, ui::VKEY_BROWSER_FORWARD, 0 }, |
| + { ui::VKEY_F3, 0, ui::VKEY_BROWSER_REFRESH, 0 }, |
| + { ui::VKEY_F4, 0, ui::VKEY_MEDIA_LAUNCH_APP2, 0 }, |
| + { ui::VKEY_F5, 0, ui::VKEY_MEDIA_LAUNCH_APP1, 0 }, |
| + { ui::VKEY_F6, 0, ui::VKEY_BRIGHTNESS_DOWN, 0 }, |
| + { ui::VKEY_F7, 0, ui::VKEY_BRIGHTNESS_UP, 0 }, |
| + { ui::VKEY_F8, 0, ui::VKEY_VOLUME_MUTE, 0 }, |
| + { ui::VKEY_F9, 0, ui::VKEY_VOLUME_DOWN, 0 }, |
| + { ui::VKEY_F10, 0, ui::VKEY_VOLUME_UP, 0 }, |
| + }; |
| + MutableKeyState incoming_without_command = incoming; |
| + incoming_without_command.flags &= ~ui::EF_COMMAND_DOWN; |
| + rewritten = RewriteWithKeyboardRemappingsByKeyCode( |
| kFkeysToSpecialKeys, |
| arraysize(kFkeysToSpecialKeys), |
| - keysym, |
| - xkey->state, |
| - &remapped_native_keysym, |
| - &remapped_native_mods); |
| - } else if (xkey->state & Mod4Mask) { |
| - // Use Search + F1-F12 for the special keys. |
| - rewritten = RewriteWithKeyboardRemappingsByKeySym( |
| - kFkeysToSpecialKeys, |
| - arraysize(kFkeysToSpecialKeys), |
| - keysym, |
| - xkey->state & ~Mod4Mask, |
| - &remapped_native_keysym, |
| - &remapped_native_mods); |
| + incoming_without_command, |
| + state); |
| + } else if (search_is_pressed) { |
| + // Allow Search to avoid rewriting F1-F12. |
| + state->flags &= ~ui::EF_COMMAND_DOWN; |
| + rewritten = true; |
| } |
| } |
| - if (!rewritten && (xkey->state & Mod4Mask)) { |
| + if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) { |
| // Remap Search+<number> to F<number>. |
| // We check the keycode here instead of the keysym, as these keys have |
| // different keysyms when modifiers are pressed, such as shift. |
| @@ -804,53 +628,52 @@ bool EventRewriter::RewriteFunctionKeys(XEvent* event) { |
| // should make layout-specific choices here. For eg. on a french keyboard |
| // "-" and "6" are the same key, so F11 will not be accessible. |
| static const KeyboardRemapping kNumberKeysToFkeys[] = { |
| - { XK_1, Mod4Mask, XK_F1, 0 }, |
| - { XK_2, Mod4Mask, XK_F2, 0 }, |
| - { XK_3, Mod4Mask, XK_F3, 0 }, |
| - { XK_4, Mod4Mask, XK_F4, 0 }, |
| - { XK_5, Mod4Mask, XK_F5, 0 }, |
| - { XK_6, Mod4Mask, XK_F6, 0 }, |
| - { XK_7, Mod4Mask, XK_F7, 0 }, |
| - { XK_8, Mod4Mask, XK_F8, 0 }, |
| - { XK_9, Mod4Mask, XK_F9, 0 }, |
| - { XK_0, Mod4Mask, XK_F10, 0 }, |
| - { XK_minus, Mod4Mask, XK_F11, 0 }, |
| - { XK_equal, Mod4Mask, XK_F12, 0 } |
| + { ui::VKEY_1, ui::EF_COMMAND_DOWN, ui::VKEY_F1, 0 }, |
| + { ui::VKEY_2, ui::EF_COMMAND_DOWN, ui::VKEY_F2, 0 }, |
| + { ui::VKEY_3, ui::EF_COMMAND_DOWN, ui::VKEY_F3, 0 }, |
| + { ui::VKEY_4, ui::EF_COMMAND_DOWN, ui::VKEY_F4, 0 }, |
| + { ui::VKEY_5, ui::EF_COMMAND_DOWN, ui::VKEY_F5, 0 }, |
| + { ui::VKEY_6, ui::EF_COMMAND_DOWN, ui::VKEY_F6, 0 }, |
| + { ui::VKEY_7, ui::EF_COMMAND_DOWN, ui::VKEY_F7, 0 }, |
| + { ui::VKEY_8, ui::EF_COMMAND_DOWN, ui::VKEY_F8, 0 }, |
| + { ui::VKEY_9, ui::EF_COMMAND_DOWN, ui::VKEY_F9, 0 }, |
| + { ui::VKEY_0, ui::EF_COMMAND_DOWN, ui::VKEY_F10, 0 }, |
| + { ui::VKEY_OEM_MINUS, ui::EF_COMMAND_DOWN, ui::VKEY_F11, 0 }, |
| + { ui::VKEY_OEM_PLUS, ui::EF_COMMAND_DOWN, ui::VKEY_F12, 0 } |
| }; |
| - |
| rewritten = RewriteWithKeyboardRemappingsByKeyCode( |
| kNumberKeysToFkeys, |
| arraysize(kNumberKeysToFkeys), |
| - xkey->keycode, |
| - xkey->state, |
| - &remapped_native_keysym, |
| - &remapped_native_mods); |
| + incoming, |
| + state); |
| } |
| - |
| - if (!rewritten) |
| - return false; |
| - |
| - OverwriteEvent(event, |
| - NativeKeySymToNativeKeycode(remapped_native_keysym), |
| - remapped_native_mods); |
| - return true; |
| } |
| -void EventRewriter::RewriteLocatedEvent(XEvent* event) { |
| - DCHECK_EQ(GenericEvent, event->type); |
| - XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data); |
| - if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease) |
| +void EventRewriter::RewriteLocatedEvent( |
| + const ui::Event& event, |
| + MutableKeyState* state) { |
| + const PrefService* pref_service = GetPrefService(); |
| + if (!pref_service) |
| return; |
| // First, remap modifier masks. |
| - unsigned int remapped_native_modifiers = 0U; |
| - GetRemappedModifierMasks(xievent->mods.effective, &remapped_native_modifiers); |
| - xievent->mods.effective = remapped_native_modifiers; |
| + state->flags = GetRemappedModifierMasks(*pref_service, event, state->flags); |
| + |
| +#if defined(USE_X11) |
| + // TODO(kpschoedel): de-X11 with unified device ids from crbug.com/360377 |
| + XEvent* xevent = event.native_event(); |
| + if (xevent->type != GenericEvent) |
| + return; |
| + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data); |
| + if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease) |
| + return; |
| // Then, remap Alt+Button1 to Button3. |
| if ((xievent->evtype == XI_ButtonPress || |
| pressed_device_ids_.count(xievent->sourceid)) && |
| (xievent->mods.effective & Mod1Mask) && xievent->detail == Button1) { |
| + state->flags &= ~(ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON); |
| + state->flags |= ui::EF_RIGHT_MOUSE_BUTTON; |
| xievent->mods.effective &= ~Mod1Mask; |
| xievent->detail = Button3; |
| if (xievent->evtype == XI_ButtonRelease) { |
| @@ -864,21 +687,13 @@ void EventRewriter::RewriteLocatedEvent(XEvent* event) { |
| pressed_device_ids_.insert(xievent->sourceid); |
| } |
| } |
| -} |
| - |
| -void EventRewriter::OverwriteEvent(XEvent* event, |
| - unsigned int new_native_keycode, |
| - unsigned int new_native_state) { |
| - DCHECK(event->type == KeyPress || event->type == KeyRelease); |
| - XKeyEvent* xkey = &event->xkey; |
| - xkey->keycode = new_native_keycode; |
| - xkey->state = new_native_state; |
| +#endif // defined(USE_X11) |
| } |
| EventRewriter::DeviceType EventRewriter::DeviceAddedInternal( |
| int device_id, |
| const std::string& device_name) { |
| - const DeviceType type = EventRewriter::GetDeviceType(device_name); |
| + const DeviceType type = GetDeviceType(device_name); |
| if (type == kDeviceAppleKeyboard) { |
| VLOG(1) << "Apple keyboard '" << device_name << "' connected: " |
| << "id=" << device_id; |