event_rewriter.h revision a02191e04bc25c4935f804f2c080ae28663d096d
1// Copyright 2014 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_CHROMEOS_EVENTS_EVENT_REWRITER_H_
6#define CHROME_BROWSER_CHROMEOS_EVENTS_EVENT_REWRITER_H_
7
8#include <map>
9#include <set>
10#include <string>
11
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 "chrome/browser/chromeos/device_hierarchy_observer.h"
17#include "chromeos/ime/ime_keyboard.h"
18#include "ui/events/keycodes/keyboard_codes.h"
19#include "ui/events/platform/platform_event_observer.h"
20
21class PrefService;
22typedef union _XEvent XEvent;
23
24namespace chromeos {
25class KeyboardDrivenEventRewriter;
26namespace input_method {
27class ImeKeyboard;
28}
29
30class EventRewriter : public DeviceHierarchyObserver,
31                      public ui::PlatformEventObserver {
32 public:
33  enum DeviceType {
34    kDeviceUnknown = 0,
35    kDeviceAppleKeyboard,
36  };
37
38  EventRewriter();
39  virtual ~EventRewriter();
40
41  // Calls DeviceAddedInternal.
42  DeviceType DeviceAddedForTesting(int device_id,
43                                   const std::string& device_name);
44  // Calls Rewrite.
45  void RewriteForTesting(XEvent* event);
46
47  const std::map<int, DeviceType>& device_id_to_type_for_testing() const {
48    return device_id_to_type_;
49  }
50  void set_last_device_id_for_testing(int device_id) {
51    last_device_id_ = device_id;
52  }
53  void set_pref_service_for_testing(const PrefService* pref_service) {
54    pref_service_for_testing_ = pref_service;
55  }
56  void set_keyboard_for_testing(input_method::ImeKeyboard* keyboard) {
57    keyboard_for_testing_ = keyboard;
58  }
59
60  // Gets DeviceType from the |device_name|.
61  static DeviceType GetDeviceType(const std::string& device_name);
62
63 private:
64  friend class EventRewriterAshTest;
65  friend class EventRewriterTest;
66
67  void DeviceKeyPressedOrReleased(int device_id);
68
69  // ui::PlatformEventObserver:
70  virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
71  virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
72
73  // DeviceHierarchyObserver:
74  virtual void DeviceHierarchyChanged() OVERRIDE;
75  virtual void DeviceAdded(int device_id) OVERRIDE;
76  virtual void DeviceRemoved(int device_id) OVERRIDE;
77
78  // We don't want to include Xlib.h here since it has polluting macros, so
79  // define these locally.
80  typedef unsigned long KeySym;
81  typedef unsigned char KeyCode;
82
83  // Updates |*_xkeycode_| in response to a keyboard map change.
84  void RefreshKeycodes();
85  // Converts an X key symbol like XK_Control_L to a key code.
86  unsigned char NativeKeySymToNativeKeycode(KeySym keysym);
87
88  struct KeyboardRemapping {
89    KeySym input_keysym;
90    unsigned int input_native_mods;
91    KeySym output_keysym;
92    unsigned int output_native_mods;
93  };
94
95  // Returns true if the target for |event| would prefer to receive raw function
96  // keys instead of having them rewritten into back, forward, brightness,
97  // volume, etc. or if the user has specified that they desire top-row keys to
98  // be treated as function keys globally.
99  bool TopRowKeysAreFunctionKeys(XEvent* event) const;
100
101  // Given a set of KeyboardRemapping structs, it finds a matching struct
102  // if possible, and updates the remapped event values. Returns true if a
103  // remapping was found and remapped values were updated.
104  bool RewriteWithKeyboardRemappingsByKeySym(
105      const KeyboardRemapping* remappings,
106      size_t num_remappings,
107      KeySym keysym,
108      unsigned int native_mods,
109      KeySym* remapped_native_keysym,
110      unsigned int* remapped_native_mods);
111
112  // Given a set of KeyboardRemapping structs, it finds a matching struct
113  // if possible, and updates the remapped event values. This function converts
114  // the KeySym in the KeyboardRemapping struct into the KeyCode before matching
115  // to allow any KeyCode on the same physical key as the given KeySym to match.
116  // Returns true if a remapping was found and remapped values were updated.
117  bool RewriteWithKeyboardRemappingsByKeyCode(
118      const KeyboardRemapping* remappings,
119      size_t num_remappings,
120      KeyCode keycode,
121      unsigned int native_mods,
122      KeySym* remapped_native_keysym,
123      unsigned int* remapped_native_mods);
124
125  // Returns the PrefService that should be used.
126  const PrefService* GetPrefService() const;
127
128  // Rewrites the |event| by applying all RewriteXXX functions as needed.
129  void Rewrite(XEvent* event);
130
131  // Rewrites a modifier key press/release following the current user
132  // preferences.
133  bool RewriteModifiers(XEvent* event);
134
135  // Rewrites Fn key press/release to Control. In some cases, Fn key is not
136  // intercepted by the EC, but generates a key event like "XK_F15 + Mod3Mask"
137  // as shown in crosbug.com/p/14339.
138  bool RewriteFnKey(XEvent* event);
139
140  // Rewrites a NumPad key press/release without Num Lock to a corresponding key
141  // press/release with the lock.  Returns true when |event| is rewritten.
142  bool RewriteNumPadKeys(XEvent* event);
143
144  // Rewrites Backspace and Arrow keys following the Chrome OS keyboard spec.
145  //  * Alt+Backspace -> Delete
146  //  * Alt+Up -> Prior (aka PageUp)
147  //  * Alt+Down -> Next (aka PageDown)
148  //  * Ctrl+Alt+Up -> Home
149  //  * Ctrl+Alt+Down -> End
150  // When the Search key acts as a function key, it instead maps:
151  //  * Search+Backspace -> Delete
152  //  * Search+Up -> Prior (aka PageUp)
153  //  * Search+Down -> Next (aka PageDown)
154  //  * Search+Left -> Home
155  //  * Search+Right -> End
156  //  * Search+. -> Insert
157  // Returns true when the |event| is rewritten.
158  bool RewriteExtendedKeys(XEvent* event);
159
160  // When the Search key acts as a function key, it remaps Search+1
161  // through Search+= to F1 through F12. Returns true when the |event| is
162  // rewritten.
163  bool RewriteFunctionKeys(XEvent* event);
164
165  // Rewrites the located |event|.
166  void RewriteLocatedEvent(XEvent* event);
167
168  // Overwrites |event| with the keycodes and flags.
169  void OverwriteEvent(XEvent* event,
170                      unsigned int new_native_keycode,
171                      unsigned int new_native_state);
172
173  // Checks the type of the |device_name|, and inserts a new entry to
174  // |device_id_to_type_|.
175  DeviceType DeviceAddedInternal(int device_id, const std::string& device_name);
176
177  // Returns true if |last_device_id_| is Apple's.
178  bool IsAppleKeyboard() const;
179
180  // Remaps |original_native_modifiers| to |remapped_native_modifiers| following
181  // the current user prefs.
182  void GetRemappedModifierMasks(unsigned int original_native_modifiers,
183                                unsigned int* remapped_native_modifiers) const;
184
185  std::map<int, DeviceType> device_id_to_type_;
186  int last_device_id_;
187
188  // A mapping from X11 KeySym keys to KeyCode values.
189  base::hash_map<unsigned long, unsigned long> keysym_to_keycode_map_;
190
191  // A set of device IDs whose press event has been rewritten.
192  std::set<int> pressed_device_ids_;
193
194  input_method::ImeKeyboard* keyboard_for_testing_;
195
196  scoped_ptr<KeyboardDrivenEventRewriter>
197      keyboard_driven_event_rewriter_;
198
199  const PrefService* pref_service_for_testing_;
200
201  DISALLOW_COPY_AND_ASSIGN(EventRewriter);
202};
203
204}  // namespace chromeos
205
206#endif  // CHROME_BROWSER_CHROMEOS_EVENTS_EVENT_REWRITER_H_
207