1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_ASH_EVENT_REWRITER_H_ 6 #define CHROME_BROWSER_UI_ASH_EVENT_REWRITER_H_ 7 8 #include <map> 9 #include <string> 10 11 #include "ash/event_rewriter_delegate.h" 12 #include "base/basictypes.h" 13 #include "base/compiler_specific.h" 14 #include "base/containers/hash_tables.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "ui/aura/root_window_observer.h" 17 #include "ui/base/keycodes/keyboard_codes.h" 18 19 #if defined(OS_CHROMEOS) 20 #include "chrome/browser/chromeos/device_hierarchy_observer.h" 21 #endif 22 23 class PrefService; 24 25 namespace aura { 26 class RootWindow; 27 } 28 29 #if defined(OS_CHROMEOS) 30 namespace chromeos { 31 32 class KeyboardDrivenEventRewriter; 33 34 namespace input_method { 35 class XKeyboard; 36 } 37 } 38 #endif 39 40 class EventRewriter : public ash::EventRewriterDelegate, 41 public aura::RootWindowObserver 42 #if defined(OS_CHROMEOS) 43 , public chromeos::DeviceHierarchyObserver 44 #endif 45 { 46 public: 47 enum DeviceType { 48 kDeviceUnknown = 0, 49 kDeviceAppleKeyboard, 50 }; 51 52 EventRewriter(); 53 virtual ~EventRewriter(); 54 55 // Calls DeviceAddedInternal. 56 DeviceType DeviceAddedForTesting(int device_id, 57 const std::string& device_name); 58 // Calls Rewrite. 59 void RewriteForTesting(ui::KeyEvent* event); 60 61 const std::map<int, DeviceType>& device_id_to_type_for_testing() const { 62 return device_id_to_type_; 63 } 64 void set_last_device_id_for_testing(int device_id) { 65 last_device_id_ = device_id; 66 } 67 void set_pref_service_for_testing(const PrefService* pref_service) { 68 pref_service_ = pref_service; 69 } 70 #if defined(OS_CHROMEOS) 71 void set_xkeyboard_for_testing(chromeos::input_method::XKeyboard* xkeyboard) { 72 xkeyboard_ = xkeyboard; 73 } 74 #endif 75 76 // Gets DeviceType from the |device_name|. 77 static DeviceType GetDeviceType(const std::string& device_name); 78 79 private: 80 // ash::EventRewriterDelegate overrides: 81 virtual ash::EventRewriterDelegate::Action RewriteOrFilterKeyEvent( 82 ui::KeyEvent* event) OVERRIDE; 83 virtual ash::EventRewriterDelegate::Action RewriteOrFilterLocatedEvent( 84 ui::LocatedEvent* event) OVERRIDE; 85 86 // aura::RootWindowObserver overrides: 87 virtual void OnKeyboardMappingChanged(const aura::RootWindow* root) OVERRIDE; 88 89 #if defined(OS_CHROMEOS) 90 // chromeos::DeviceHierarchyObserver overrides: 91 virtual void DeviceHierarchyChanged() OVERRIDE {} 92 virtual void DeviceAdded(int device_id) OVERRIDE; 93 virtual void DeviceRemoved(int device_id) OVERRIDE; 94 virtual void DeviceKeyPressedOrReleased(int device_id) OVERRIDE; 95 96 // We don't want to include Xlib.h here since it has polluting macros, so 97 // define these locally. 98 typedef unsigned long KeySym; 99 typedef unsigned char KeyCode; 100 101 // Updates |*_xkeycode_| in response to a keyboard map change. 102 void RefreshKeycodes(); 103 // Converts an X key symbol like XK_Control_L to a key code. 104 unsigned char NativeKeySymToNativeKeycode(KeySym keysym); 105 106 struct KeyboardRemapping { 107 KeySym input_keysym; 108 unsigned int input_mods; 109 unsigned int input_native_mods; 110 KeySym output_keysym; 111 ui::KeyboardCode output_keycode; 112 unsigned int output_mods; 113 unsigned int output_native_mods; 114 }; 115 116 // Given a set of KeyboardRemapping structs, it finds a matching struct 117 // if possible, and updates the remapped event values. Returns true if a 118 // remapping was found and remapped values were updated. 119 bool RewriteWithKeyboardRemappingsByKeySym( 120 const KeyboardRemapping* remappings, 121 size_t num_remappings, 122 KeySym keysym, 123 unsigned int native_mods, 124 unsigned int mods, 125 KeySym* remapped_native_keysym, 126 unsigned int* remapped_native_mods, 127 ui::KeyboardCode* remapped_keycode, 128 unsigned int* remapped_mods); 129 130 // Given a set of KeyboardRemapping structs, it finds a matching struct 131 // if possible, and updates the remapped event values. This function converts 132 // the KeySym in the KeyboardRemapping struct into the KeyCode before matching 133 // to allow any KeyCode on the same physical key as the given KeySym to match. 134 // Returns true if a remapping was found and remapped values were updated. 135 bool RewriteWithKeyboardRemappingsByKeyCode( 136 const KeyboardRemapping* remappings, 137 size_t num_remappings, 138 KeyCode keycode, 139 unsigned int native_mods, 140 unsigned int mods, 141 KeySym* remapped_native_keysym, 142 unsigned int* remapped_native_mods, 143 ui::KeyboardCode* remapped_keycode, 144 unsigned int* remapped_mods); 145 #endif 146 147 // Rewrites the |event| by applying all RewriteXXX functions as needed. 148 void Rewrite(ui::KeyEvent* event); 149 150 // Rewrites a modifier key press/release following the current user 151 // preferences. 152 bool RewriteModifiers(ui::KeyEvent* event); 153 154 // Rewrites Fn key press/release to Control. In some cases, Fn key is not 155 // intercepted by the EC, but generates a key event like "XK_F15 + Mod3Mask" 156 // as shown in crosbug.com/p/14339. 157 bool RewriteFnKey(ui::KeyEvent* event); 158 159 // Rewrites a NumPad key press/release without Num Lock to a corresponding key 160 // press/release with the lock. Returns true when |event| is rewritten. 161 bool RewriteNumPadKeys(ui::KeyEvent* event); 162 163 // Rewrites Backspace and Arrow keys following the Chrome OS keyboard spec. 164 // * Alt+Backspace -> Delete 165 // * Alt+Up -> Prior (aka PageUp) 166 // * Alt+Down -> Next (aka PageDown) 167 // * Ctrl+Alt+Up -> Home 168 // * Ctrl+Alt+Down -> End 169 // When the Search key acts as a function key, it instead maps: 170 // * Search+Backspace -> Delete 171 // * Search+Up -> Prior (aka PageUp) 172 // * Search+Down -> Next (aka PageDown) 173 // * Search+Left -> Home 174 // * Search+Right -> End 175 // * Search+. -> Insert 176 // Returns true when the |event| is rewritten. 177 bool RewriteExtendedKeys(ui::KeyEvent* event); 178 179 // When the Search key acts as a function key, it remaps Search+1 180 // through Search+= to F1 through F12. Returns true when the |event| is 181 // rewritten. 182 bool RewriteFunctionKeys(ui::KeyEvent* event); 183 184 // Rewrites the located |event|. 185 void RewriteLocatedEvent(ui::LocatedEvent* event); 186 187 // Overwrites |event| with the keycodes and flags. 188 void OverwriteEvent(ui::KeyEvent* event, 189 unsigned int new_native_keycode, 190 unsigned int new_native_state, 191 ui::KeyboardCode new_keycode, 192 int new_flags); 193 194 // Checks the type of the |device_name|, and inserts a new entry to 195 // |device_id_to_type_|. 196 DeviceType DeviceAddedInternal(int device_id, const std::string& device_name); 197 198 // Returns true if |last_device_id_| is Apple's. 199 bool IsAppleKeyboard() const; 200 201 // Remaps |original_flags| to |remapped_flags| and |original_native_modifiers| 202 // to |remapped_native_modifiers| following the current user prefs. 203 void GetRemappedModifierMasks(int original_flags, 204 unsigned int original_native_modifiers, 205 int* remapped_flags, 206 unsigned int* remapped_native_modifiers) const; 207 208 std::map<int, DeviceType> device_id_to_type_; 209 int last_device_id_; 210 211 #if defined(OS_CHROMEOS) 212 // A mapping from X11 KeySym keys to KeyCode values. 213 base::hash_map<unsigned long, unsigned long> keysym_to_keycode_map_; 214 215 chromeos::input_method::XKeyboard* xkeyboard_; // for testing. 216 217 scoped_ptr<chromeos::KeyboardDrivenEventRewriter> 218 keyboard_driven_event_rewritter_; 219 #endif 220 221 const PrefService* pref_service_; // for testing. 222 223 DISALLOW_COPY_AND_ASSIGN(EventRewriter); 224 }; 225 226 #endif // CHROME_BROWSER_UI_ASH_EVENT_REWRITER_H_ 227