// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_UI_ASH_EVENT_REWRITER_H_ #define CHROME_BROWSER_UI_ASH_EVENT_REWRITER_H_ #include <map> #include <string> #include "ash/event_rewriter_delegate.h" #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "ui/aura/root_window_observer.h" #include "ui/events/keycodes/keyboard_codes.h" #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/device_hierarchy_observer.h" #endif class PrefService; namespace aura { class RootWindow; } #if defined(OS_CHROMEOS) namespace chromeos { class KeyboardDrivenEventRewriter; namespace input_method { class XKeyboard; } } #endif class EventRewriter : public ash::EventRewriterDelegate, public aura::RootWindowObserver #if defined(OS_CHROMEOS) , public chromeos::DeviceHierarchyObserver #endif { public: enum DeviceType { kDeviceUnknown = 0, kDeviceAppleKeyboard, }; EventRewriter(); virtual ~EventRewriter(); // Calls DeviceAddedInternal. DeviceType DeviceAddedForTesting(int device_id, const std::string& device_name); // Calls Rewrite. void RewriteForTesting(ui::KeyEvent* event); const std::map<int, DeviceType>& device_id_to_type_for_testing() const { return device_id_to_type_; } void set_last_device_id_for_testing(int device_id) { last_device_id_ = device_id; } void set_pref_service_for_testing(const PrefService* pref_service) { pref_service_for_testing_ = pref_service; } #if defined(OS_CHROMEOS) void set_xkeyboard_for_testing(chromeos::input_method::XKeyboard* xkeyboard) { xkeyboard_for_testing_ = xkeyboard; } #endif // Gets DeviceType from the |device_name|. static DeviceType GetDeviceType(const std::string& device_name); private: friend class EventRewriterAshTest; // ash::EventRewriterDelegate overrides: virtual ash::EventRewriterDelegate::Action RewriteOrFilterKeyEvent( ui::KeyEvent* event) OVERRIDE; virtual ash::EventRewriterDelegate::Action RewriteOrFilterLocatedEvent( ui::LocatedEvent* event) OVERRIDE; // aura::RootWindowObserver overrides: virtual void OnKeyboardMappingChanged(const aura::RootWindow* root) OVERRIDE; #if defined(OS_CHROMEOS) // chromeos::DeviceHierarchyObserver overrides: virtual void DeviceHierarchyChanged() OVERRIDE {} virtual void DeviceAdded(int device_id) OVERRIDE; virtual void DeviceRemoved(int device_id) OVERRIDE; virtual void DeviceKeyPressedOrReleased(int device_id) OVERRIDE; // We don't want to include Xlib.h here since it has polluting macros, so // define these locally. typedef unsigned long KeySym; typedef unsigned char KeyCode; // Updates |*_xkeycode_| in response to a keyboard map change. void RefreshKeycodes(); // Converts an X key symbol like XK_Control_L to a key code. unsigned char NativeKeySymToNativeKeycode(KeySym keysym); struct KeyboardRemapping { KeySym input_keysym; unsigned int input_mods; unsigned int input_native_mods; KeySym output_keysym; ui::KeyboardCode output_keycode; unsigned int output_mods; unsigned int output_native_mods; }; // Returns true if the target for |event| would prefer to receive raw function // keys instead of having them rewritten into back, forward, brightness, // volume, etc. or if the user has specified that they desire top-row keys to // be treated as function keys globally. bool TopRowKeysAreFunctionKeys(ui::KeyEvent* event) const; // Given a set of KeyboardRemapping structs, it finds a matching struct // if possible, and updates the remapped event values. Returns true if a // remapping was found and remapped values were updated. bool RewriteWithKeyboardRemappingsByKeySym( const KeyboardRemapping* remappings, size_t num_remappings, KeySym keysym, unsigned int native_mods, unsigned int mods, KeySym* remapped_native_keysym, unsigned int* remapped_native_mods, ui::KeyboardCode* remapped_keycode, unsigned int* remapped_mods); // Given a set of KeyboardRemapping structs, it finds a matching struct // if possible, and updates the remapped event values. This function converts // the KeySym in the KeyboardRemapping struct into the KeyCode before matching // to allow any KeyCode on the same physical key as the given KeySym to match. // Returns true if a remapping was found and remapped values were updated. bool RewriteWithKeyboardRemappingsByKeyCode( const KeyboardRemapping* remappings, size_t num_remappings, KeyCode keycode, unsigned int native_mods, unsigned int mods, KeySym* remapped_native_keysym, unsigned int* remapped_native_mods, ui::KeyboardCode* remapped_keycode, unsigned int* remapped_mods); #endif // Returns the PrefService that should be used. const PrefService* GetPrefService() const; // Rewrites the |event| by applying all RewriteXXX functions as needed. void Rewrite(ui::KeyEvent* event); // Rewrites a modifier key press/release following the current user // preferences. bool RewriteModifiers(ui::KeyEvent* event); // Rewrites Fn key press/release to Control. In some cases, Fn key is not // intercepted by the EC, but generates a key event like "XK_F15 + Mod3Mask" // as shown in crosbug.com/p/14339. bool RewriteFnKey(ui::KeyEvent* event); // Rewrites a NumPad key press/release without Num Lock to a corresponding key // press/release with the lock. Returns true when |event| is rewritten. bool RewriteNumPadKeys(ui::KeyEvent* event); // Rewrites Backspace and Arrow keys following the Chrome OS keyboard spec. // * Alt+Backspace -> Delete // * Alt+Up -> Prior (aka PageUp) // * Alt+Down -> Next (aka PageDown) // * Ctrl+Alt+Up -> Home // * Ctrl+Alt+Down -> End // When the Search key acts as a function key, it instead maps: // * Search+Backspace -> Delete // * Search+Up -> Prior (aka PageUp) // * Search+Down -> Next (aka PageDown) // * Search+Left -> Home // * Search+Right -> End // * Search+. -> Insert // Returns true when the |event| is rewritten. bool RewriteExtendedKeys(ui::KeyEvent* event); // When the Search key acts as a function key, it remaps Search+1 // through Search+= to F1 through F12. Returns true when the |event| is // rewritten. bool RewriteFunctionKeys(ui::KeyEvent* event); // Rewrites the located |event|. void RewriteLocatedEvent(ui::LocatedEvent* event); // Overwrites |event| with the keycodes and flags. void OverwriteEvent(ui::KeyEvent* event, unsigned int new_native_keycode, unsigned int new_native_state, ui::KeyboardCode new_keycode, int new_flags); // Checks the type of the |device_name|, and inserts a new entry to // |device_id_to_type_|. DeviceType DeviceAddedInternal(int device_id, const std::string& device_name); // Returns true if |last_device_id_| is Apple's. bool IsAppleKeyboard() const; // Remaps |original_flags| to |remapped_flags| and |original_native_modifiers| // to |remapped_native_modifiers| following the current user prefs. void GetRemappedModifierMasks(int original_flags, unsigned int original_native_modifiers, int* remapped_flags, unsigned int* remapped_native_modifiers) const; std::map<int, DeviceType> device_id_to_type_; int last_device_id_; #if defined(OS_CHROMEOS) // A mapping from X11 KeySym keys to KeyCode values. base::hash_map<unsigned long, unsigned long> keysym_to_keycode_map_; chromeos::input_method::XKeyboard* xkeyboard_for_testing_; scoped_ptr<chromeos::KeyboardDrivenEventRewriter> keyboard_driven_event_rewriter_; #endif const PrefService* pref_service_for_testing_; DISALLOW_COPY_AND_ASSIGN(EventRewriter); }; #endif // CHROME_BROWSER_UI_ASH_EVENT_REWRITER_H_