• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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