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/events/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 device_id_to_type_for_testing()61 const std::map<int, DeviceType>& device_id_to_type_for_testing() const { 62 return device_id_to_type_; 63 } set_last_device_id_for_testing(int device_id)64 void set_last_device_id_for_testing(int device_id) { 65 last_device_id_ = device_id; 66 } set_pref_service_for_testing(const PrefService * pref_service)67 void set_pref_service_for_testing(const PrefService* pref_service) { 68 pref_service_for_testing_ = pref_service; 69 } 70 #if defined(OS_CHROMEOS) set_xkeyboard_for_testing(chromeos::input_method::XKeyboard * xkeyboard)71 void set_xkeyboard_for_testing(chromeos::input_method::XKeyboard* xkeyboard) { 72 xkeyboard_for_testing_ = 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 friend class EventRewriterAshTest; 81 82 // ash::EventRewriterDelegate overrides: 83 virtual ash::EventRewriterDelegate::Action RewriteOrFilterKeyEvent( 84 ui::KeyEvent* event) OVERRIDE; 85 virtual ash::EventRewriterDelegate::Action RewriteOrFilterLocatedEvent( 86 ui::LocatedEvent* event) OVERRIDE; 87 88 // aura::RootWindowObserver overrides: 89 virtual void OnKeyboardMappingChanged(const aura::RootWindow* root) OVERRIDE; 90 91 #if defined(OS_CHROMEOS) 92 // chromeos::DeviceHierarchyObserver overrides: DeviceHierarchyChanged()93 virtual void DeviceHierarchyChanged() OVERRIDE {} 94 virtual void DeviceAdded(int device_id) OVERRIDE; 95 virtual void DeviceRemoved(int device_id) OVERRIDE; 96 virtual void DeviceKeyPressedOrReleased(int device_id) OVERRIDE; 97 98 // We don't want to include Xlib.h here since it has polluting macros, so 99 // define these locally. 100 typedef unsigned long KeySym; 101 typedef unsigned char KeyCode; 102 103 // Updates |*_xkeycode_| in response to a keyboard map change. 104 void RefreshKeycodes(); 105 // Converts an X key symbol like XK_Control_L to a key code. 106 unsigned char NativeKeySymToNativeKeycode(KeySym keysym); 107 108 struct KeyboardRemapping { 109 KeySym input_keysym; 110 unsigned int input_mods; 111 unsigned int input_native_mods; 112 KeySym output_keysym; 113 ui::KeyboardCode output_keycode; 114 unsigned int output_mods; 115 unsigned int output_native_mods; 116 }; 117 118 // Returns true if the target for |event| would prefer to receive raw function 119 // keys instead of having them rewritten into back, forward, brightness, 120 // volume, etc. or if the user has specified that they desire top-row keys to 121 // be treated as function keys globally. 122 bool TopRowKeysAreFunctionKeys(ui::KeyEvent* event) const; 123 124 // Given a set of KeyboardRemapping structs, it finds a matching struct 125 // if possible, and updates the remapped event values. Returns true if a 126 // remapping was found and remapped values were updated. 127 bool RewriteWithKeyboardRemappingsByKeySym( 128 const KeyboardRemapping* remappings, 129 size_t num_remappings, 130 KeySym keysym, 131 unsigned int native_mods, 132 unsigned int mods, 133 KeySym* remapped_native_keysym, 134 unsigned int* remapped_native_mods, 135 ui::KeyboardCode* remapped_keycode, 136 unsigned int* remapped_mods); 137 138 // Given a set of KeyboardRemapping structs, it finds a matching struct 139 // if possible, and updates the remapped event values. This function converts 140 // the KeySym in the KeyboardRemapping struct into the KeyCode before matching 141 // to allow any KeyCode on the same physical key as the given KeySym to match. 142 // Returns true if a remapping was found and remapped values were updated. 143 bool RewriteWithKeyboardRemappingsByKeyCode( 144 const KeyboardRemapping* remappings, 145 size_t num_remappings, 146 KeyCode keycode, 147 unsigned int native_mods, 148 unsigned int mods, 149 KeySym* remapped_native_keysym, 150 unsigned int* remapped_native_mods, 151 ui::KeyboardCode* remapped_keycode, 152 unsigned int* remapped_mods); 153 #endif 154 155 // Returns the PrefService that should be used. 156 const PrefService* GetPrefService() const; 157 158 // Rewrites the |event| by applying all RewriteXXX functions as needed. 159 void Rewrite(ui::KeyEvent* event); 160 161 // Rewrites a modifier key press/release following the current user 162 // preferences. 163 bool RewriteModifiers(ui::KeyEvent* event); 164 165 // Rewrites Fn key press/release to Control. In some cases, Fn key is not 166 // intercepted by the EC, but generates a key event like "XK_F15 + Mod3Mask" 167 // as shown in crosbug.com/p/14339. 168 bool RewriteFnKey(ui::KeyEvent* event); 169 170 // Rewrites a NumPad key press/release without Num Lock to a corresponding key 171 // press/release with the lock. Returns true when |event| is rewritten. 172 bool RewriteNumPadKeys(ui::KeyEvent* event); 173 174 // Rewrites Backspace and Arrow keys following the Chrome OS keyboard spec. 175 // * Alt+Backspace -> Delete 176 // * Alt+Up -> Prior (aka PageUp) 177 // * Alt+Down -> Next (aka PageDown) 178 // * Ctrl+Alt+Up -> Home 179 // * Ctrl+Alt+Down -> End 180 // When the Search key acts as a function key, it instead maps: 181 // * Search+Backspace -> Delete 182 // * Search+Up -> Prior (aka PageUp) 183 // * Search+Down -> Next (aka PageDown) 184 // * Search+Left -> Home 185 // * Search+Right -> End 186 // * Search+. -> Insert 187 // Returns true when the |event| is rewritten. 188 bool RewriteExtendedKeys(ui::KeyEvent* event); 189 190 // When the Search key acts as a function key, it remaps Search+1 191 // through Search+= to F1 through F12. Returns true when the |event| is 192 // rewritten. 193 bool RewriteFunctionKeys(ui::KeyEvent* event); 194 195 // Rewrites the located |event|. 196 void RewriteLocatedEvent(ui::LocatedEvent* event); 197 198 // Overwrites |event| with the keycodes and flags. 199 void OverwriteEvent(ui::KeyEvent* event, 200 unsigned int new_native_keycode, 201 unsigned int new_native_state, 202 ui::KeyboardCode new_keycode, 203 int new_flags); 204 205 // Checks the type of the |device_name|, and inserts a new entry to 206 // |device_id_to_type_|. 207 DeviceType DeviceAddedInternal(int device_id, const std::string& device_name); 208 209 // Returns true if |last_device_id_| is Apple's. 210 bool IsAppleKeyboard() const; 211 212 // Remaps |original_flags| to |remapped_flags| and |original_native_modifiers| 213 // to |remapped_native_modifiers| following the current user prefs. 214 void GetRemappedModifierMasks(int original_flags, 215 unsigned int original_native_modifiers, 216 int* remapped_flags, 217 unsigned int* remapped_native_modifiers) const; 218 219 std::map<int, DeviceType> device_id_to_type_; 220 int last_device_id_; 221 222 #if defined(OS_CHROMEOS) 223 // A mapping from X11 KeySym keys to KeyCode values. 224 base::hash_map<unsigned long, unsigned long> keysym_to_keycode_map_; 225 226 chromeos::input_method::XKeyboard* xkeyboard_for_testing_; 227 228 scoped_ptr<chromeos::KeyboardDrivenEventRewriter> 229 keyboard_driven_event_rewriter_; 230 #endif 231 232 const PrefService* pref_service_for_testing_; 233 234 DISALLOW_COPY_AND_ASSIGN(EventRewriter); 235 }; 236 237 #endif // CHROME_BROWSER_UI_ASH_EVENT_REWRITER_H_ 238