Use XInput2 events for keyboard events.

Patch set 1: Use XInput2 events for keyboard events.

XI2 keyboard events are generated, rewritten to core events, and consumed. EventRewriter tests pass with XI2 key events.

Patch set 2: Move source_device_id_ up to |ui::Event|.

Patch set 3: EventRewriter is no longer a PlatformEventObserver or DeviceHierarchyObserver.

|chromeos::EventRewriter| now uses |ui::KeyEvent::source_device_id()| instead of tracking XI2 key events itself as a chromeos::DeviceHierarchyObserver and |ui::PlatformEventObserver|.

Patch set 4: Convert Alt + Left Button rewriter from XI2 events to|ui::Event|s.

BUG=368750

Review URL: https://codereview.chromium.org/336403005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282717 0039d316-1c4b-4281-b951-d872f2087c98
parent 34136d0b
...@@ -15,12 +15,6 @@ ...@@ -15,12 +15,6 @@
#include "ui/events/event.h" #include "ui/events/event.h"
#include "ui/events/event_rewriter.h" #include "ui/events/event_rewriter.h"
#if defined(USE_X11)
#include "chrome/browser/chromeos/device_hierarchy_observer.h"
#include "ui/events/platform/platform_event_observer.h"
typedef union _XEvent XEvent;
#endif
class PrefService; class PrefService;
namespace ash { namespace ash {
...@@ -42,13 +36,7 @@ class ImeKeyboard; ...@@ -42,13 +36,7 @@ class ImeKeyboard;
// - handles various key combinations like Search+Backspace -> Delete // - handles various key combinations like Search+Backspace -> Delete
// and Search+number to Fnumber; // and Search+number to Fnumber;
// - handles key/pointer combinations like Alt+Button1 -> Button3. // - handles key/pointer combinations like Alt+Button1 -> Button3.
class EventRewriter class EventRewriter : public ui::EventRewriter {
:
#if defined(USE_X11)
public DeviceHierarchyObserver,
public ui::PlatformEventObserver,
#endif
public ui::EventRewriter {
public: public:
enum DeviceType { enum DeviceType {
kDeviceUnknown = 0, kDeviceUnknown = 0,
...@@ -61,21 +49,20 @@ class EventRewriter ...@@ -61,21 +49,20 @@ class EventRewriter
explicit EventRewriter(ash::StickyKeysController* sticky_keys_controller); explicit EventRewriter(ash::StickyKeysController* sticky_keys_controller);
virtual ~EventRewriter(); virtual ~EventRewriter();
// Calls DeviceAddedInternal. // Calls KeyboardDeviceAddedInternal.
DeviceType DeviceAddedForTesting(int device_id, DeviceType KeyboardDeviceAddedForTesting(int device_id,
const std::string& device_name); const std::string& device_name);
// Calls RewriteLocatedEvent(). // Calls RewriteMouseEvent().
void RewriteLocatedEventForTesting(const ui::Event& event, int* flags); void RewriteMouseButtonEventForTesting(
const ui::MouseEvent& event,
scoped_ptr<ui::Event>* rewritten_event);
#if defined(USE_X11)
const std::map<int, DeviceType>& device_id_to_type_for_testing() const { const std::map<int, DeviceType>& device_id_to_type_for_testing() const {
return device_id_to_type_; return device_id_to_type_;
} }
#endif void set_last_keyboard_device_id_for_testing(int device_id) {
last_keyboard_device_id_ = device_id;
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) { void set_pref_service_for_testing(const PrefService* pref_service) {
pref_service_for_testing_ = pref_service; pref_service_for_testing_ = pref_service;
...@@ -93,16 +80,12 @@ class EventRewriter ...@@ -93,16 +80,12 @@ class EventRewriter
const ui::Event& last_event, const ui::Event& last_event,
scoped_ptr<ui::Event>* new_event) OVERRIDE; scoped_ptr<ui::Event>* new_event) OVERRIDE;
#if defined(USE_X11) // Generate a new key event from an original key event and the replacement
// ui::PlatformEventObserver: // key code and flags determined by a key rewriter.
virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE; static void BuildRewrittenKeyEvent(const ui::KeyEvent& key_event,
virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE; ui::KeyboardCode key_code,
int flags,
// DeviceHierarchyObserver: scoped_ptr<ui::Event>* rewritten_event);
virtual void DeviceHierarchyChanged() OVERRIDE;
virtual void DeviceAdded(int device_id) OVERRIDE;
virtual void DeviceRemoved(int device_id) OVERRIDE;
#endif
private: private:
// Things that keyboard-related rewriter phases can change about an Event. // Things that keyboard-related rewriter phases can change about an Event.
...@@ -119,18 +102,20 @@ class EventRewriter ...@@ -119,18 +102,20 @@ class EventRewriter
int output_flags; int output_flags;
}; };
#if defined(USE_X11)
void DeviceKeyPressedOrReleased(int device_id); void DeviceKeyPressedOrReleased(int device_id);
#endif
// Returns the PrefService that should be used. // Returns the PrefService that should be used.
const PrefService* GetPrefService() const; const PrefService* GetPrefService() const;
// Adds a device to |device_id_to_type_|.
void KeyboardDeviceAdded(int device_id);
// Checks the type of the |device_name|, and inserts a new entry to // Checks the type of the |device_name|, and inserts a new entry to
// |device_id_to_type_|. // |device_id_to_type_|.
DeviceType DeviceAddedInternal(int device_id, const std::string& device_name); DeviceType KeyboardDeviceAddedInternal(int device_id,
const std::string& device_name);
// Returns true if |last_device_id_| is Apple's. // Returns true if |last_keyboard_device_id_| is Apple's.
bool IsAppleKeyboard() const; bool IsAppleKeyboard() const;
// Returns true if the target for |event| would prefer to receive raw function // Returns true if the target for |event| would prefer to receive raw function
...@@ -178,12 +163,17 @@ class EventRewriter ...@@ -178,12 +163,17 @@ class EventRewriter
void RewriteExtendedKeys(const ui::KeyEvent& event, MutableKeyState* state); void RewriteExtendedKeys(const ui::KeyEvent& event, MutableKeyState* state);
void RewriteFunctionKeys(const ui::KeyEvent& event, MutableKeyState* state); void RewriteFunctionKeys(const ui::KeyEvent& event, MutableKeyState* state);
void RewriteLocatedEvent(const ui::Event& event, int* flags); void RewriteLocatedEvent(const ui::Event& event, int* flags);
int RewriteModifierClick(const ui::MouseEvent& event, int* flags);
// A set of device IDs whose press event has been rewritten. // A set of device IDs whose press event has been rewritten.
// This is to ensure that press and release events are rewritten consistently.
std::set<int> pressed_device_ids_; std::set<int> pressed_device_ids_;
std::map<int, DeviceType> device_id_to_type_; std::map<int, DeviceType> device_id_to_type_;
int last_device_id_;
// The |source_device_id()| of the most recent keyboard event,
// used to interpret modifiers on pointer events.
int last_keyboard_device_id_;
chromeos::input_method::ImeKeyboard* ime_keyboard_for_testing_; chromeos::input_method::ImeKeyboard* ime_keyboard_for_testing_;
const PrefService* pref_service_for_testing_; const PrefService* pref_service_for_testing_;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/events/keyboard_driven_event_rewriter.h" #include "chrome/browser/chromeos/events/keyboard_driven_event_rewriter.h"
#include "chrome/browser/chromeos/events/event_rewriter.h"
#include "chrome/browser/chromeos/login/users/user_manager.h" #include "chrome/browser/chromeos/login/users/user_manager.h"
#include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/chromeos/system/input_device_settings.h"
#include "ui/events/event.h" #include "ui/events/event.h"
...@@ -77,9 +78,11 @@ ui::EventRewriteStatus KeyboardDrivenEventRewriter::Rewrite( ...@@ -77,9 +78,11 @@ ui::EventRewriteStatus KeyboardDrivenEventRewriter::Rewrite(
return ui::EVENT_REWRITE_CONTINUE; return ui::EVENT_REWRITE_CONTINUE;
} }
rewritten_event->reset(new ui::KeyEvent(key_event)); chromeos::EventRewriter::BuildRewrittenKeyEvent(
(*rewritten_event)->set_flags( key_event,
flags & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)); key_event.key_code(),
flags & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN),
rewritten_event);
return ui::EVENT_REWRITE_REWRITTEN; return ui::EVENT_REWRITE_REWRITTEN;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "ui/events/gestures/gesture_recognizer_impl.h" #include "ui/events/gestures/gesture_recognizer_impl.h"
#include "ui/events/gestures/gesture_sequence.h" #include "ui/events/gestures/gesture_sequence.h"
#include "ui/events/gestures/gesture_types.h" #include "ui/events/gestures/gesture_types.h"
#include "ui/events/test/events_test_utils.h"
#include "ui/gfx/point.h" #include "ui/gfx/point.h"
#include "ui/gfx/rect.h" #include "ui/gfx/rect.h"
...@@ -2289,12 +2290,14 @@ TEST_P(GestureRecognizerTest, GestureEventTouchLockIgnoresOtherScreens) { ...@@ -2289,12 +2290,14 @@ TEST_P(GestureRecognizerTest, GestureEventTouchLockIgnoresOtherScreens) {
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(5, 5), ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(5, 5),
kTouchId1, tes.Now()); kTouchId1, tes.Now());
press1.set_source_device_id(1); ui::EventTestApi test_press1(&press1);
test_press1.set_source_device_id(1);
DispatchEventUsingWindowDispatcher(&press1); DispatchEventUsingWindowDispatcher(&press1);
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20), ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20),
kTouchId2, tes.Now()); kTouchId2, tes.Now());
press2.set_source_device_id(2); ui::EventTestApi test_press2(&press2);
test_press2.set_source_device_id(2);
DispatchEventUsingWindowDispatcher(&press2); DispatchEventUsingWindowDispatcher(&press2);
// The second press should not have been locked to the same target as the // The second press should not have been locked to the same target as the
......
...@@ -73,8 +73,6 @@ void SelectXInput2EventsForRootWindow(XDisplay* display, ::Window root_window) { ...@@ -73,8 +73,6 @@ void SelectXInput2EventsForRootWindow(XDisplay* display, ::Window root_window) {
memset(mask, 0, sizeof(mask)); memset(mask, 0, sizeof(mask));
XISetMask(mask, XI_HierarchyChanged); XISetMask(mask, XI_HierarchyChanged);
XISetMask(mask, XI_KeyPress);
XISetMask(mask, XI_KeyRelease);
XIEventMask evmask; XIEventMask evmask;
evmask.deviceid = XIAllDevices; evmask.deviceid = XIAllDevices;
...@@ -417,7 +415,6 @@ uint32_t WindowTreeHostX11::DispatchEvent(const ui::PlatformEvent& event) { ...@@ -417,7 +415,6 @@ uint32_t WindowTreeHostX11::DispatchEvent(const ui::PlatformEvent& event) {
compositor()->ScheduleRedrawRect(damage_rect); compositor()->ScheduleRedrawRect(damage_rect);
break; break;
} }
case FocusOut: case FocusOut:
if (xev->xfocus.mode != NotifyGrab) if (xev->xfocus.mode != NotifyGrab)
OnHostLostWindowCapture(); OnHostLostWindowCapture();
...@@ -692,6 +689,12 @@ void WindowTreeHostX11::DispatchXI2Event(const base::NativeEvent& event) { ...@@ -692,6 +689,12 @@ void WindowTreeHostX11::DispatchXI2Event(const base::NativeEvent& event) {
SendEventToProcessor(&scrollev); SendEventToProcessor(&scrollev);
break; break;
} }
case ui::ET_KEY_PRESSED:
case ui::ET_KEY_RELEASED: {
ui::KeyEvent key_event(xev, false);
SendEventToProcessor(&key_event);
break;
}
case ui::ET_UMA_DATA: case ui::ET_UMA_DATA:
break; break;
case ui::ET_UNKNOWN: case ui::ET_UNKNOWN:
......
...@@ -147,7 +147,8 @@ Event::Event(EventType type, base::TimeDelta time_stamp, int flags) ...@@ -147,7 +147,8 @@ Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
cancelable_(true), cancelable_(true),
target_(NULL), target_(NULL),
phase_(EP_PREDISPATCH), phase_(EP_PREDISPATCH),
result_(ER_UNHANDLED) { result_(ER_UNHANDLED),
source_device_id_(ED_UNKNOWN_DEVICE) {
if (type_ < ET_LAST) if (type_ < ET_LAST)
name_ = EventTypeName(type_); name_ = EventTypeName(type_);
} }
...@@ -163,7 +164,8 @@ Event::Event(const base::NativeEvent& native_event, ...@@ -163,7 +164,8 @@ Event::Event(const base::NativeEvent& native_event,
cancelable_(true), cancelable_(true),
target_(NULL), target_(NULL),
phase_(EP_PREDISPATCH), phase_(EP_PREDISPATCH),
result_(ER_UNHANDLED) { result_(ER_UNHANDLED),
source_device_id_(ED_UNKNOWN_DEVICE) {
base::TimeDelta delta = EventTimeForNow() - time_stamp_; base::TimeDelta delta = EventTimeForNow() - time_stamp_;
if (type_ < ET_LAST) if (type_ < ET_LAST)
name_ = EventTypeName(type_); name_ = EventTypeName(type_);
...@@ -179,6 +181,14 @@ Event::Event(const base::NativeEvent& native_event, ...@@ -179,6 +181,14 @@ Event::Event(const base::NativeEvent& native_event,
100, 100,
base::HistogramBase::kUmaTargetedHistogramFlag); base::HistogramBase::kUmaTargetedHistogramFlag);
counter_for_type->Add(delta.InMicroseconds()); counter_for_type->Add(delta.InMicroseconds());
#if defined(USE_X11)
if (native_event->type == GenericEvent) {
XIDeviceEvent* xiev =
static_cast<XIDeviceEvent*>(native_event->xcookie.data);
source_device_id_ = xiev->deviceid;
}
#endif
} }
Event::Event(const Event& copy) Event::Event(const Event& copy)
...@@ -191,7 +201,8 @@ Event::Event(const Event& copy) ...@@ -191,7 +201,8 @@ Event::Event(const Event& copy)
cancelable_(true), cancelable_(true),
target_(NULL), target_(NULL),
phase_(EP_PREDISPATCH), phase_(EP_PREDISPATCH),
result_(ER_UNHANDLED) { result_(ER_UNHANDLED),
source_device_id_(copy.source_device_id_) {
if (type_ < ET_LAST) if (type_ < ET_LAST)
name_ = EventTypeName(type_); name_ = EventTypeName(type_);
} }
...@@ -428,8 +439,7 @@ TouchEvent::TouchEvent(const base::NativeEvent& native_event) ...@@ -428,8 +439,7 @@ TouchEvent::TouchEvent(const base::NativeEvent& native_event)
radius_x_(GetTouchRadiusX(native_event)), radius_x_(GetTouchRadiusX(native_event)),
radius_y_(GetTouchRadiusY(native_event)), radius_y_(GetTouchRadiusY(native_event)),
rotation_angle_(GetTouchAngle(native_event)), rotation_angle_(GetTouchAngle(native_event)),
force_(GetTouchForce(native_event)), force_(GetTouchForce(native_event)) {
source_device_id_(-1) {
latency()->AddLatencyNumberWithTimestamp( latency()->AddLatencyNumberWithTimestamp(
INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
0, 0,
...@@ -437,11 +447,6 @@ TouchEvent::TouchEvent(const base::NativeEvent& native_event) ...@@ -437,11 +447,6 @@ TouchEvent::TouchEvent(const base::NativeEvent& native_event)
base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
1); 1);
#if defined(USE_X11)
XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(native_event->xcookie.data);
source_device_id_ = xiev->deviceid;
#endif
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
} }
...@@ -454,8 +459,7 @@ TouchEvent::TouchEvent(EventType type, ...@@ -454,8 +459,7 @@ TouchEvent::TouchEvent(EventType type,
radius_x_(0.0f), radius_x_(0.0f),
radius_y_(0.0f), radius_y_(0.0f),
rotation_angle_(0.0f), rotation_angle_(0.0f),
force_(0.0f), force_(0.0f) {
source_device_id_(-1) {
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
} }
...@@ -473,8 +477,7 @@ TouchEvent::TouchEvent(EventType type, ...@@ -473,8 +477,7 @@ TouchEvent::TouchEvent(EventType type,
radius_x_(radius_x), radius_x_(radius_x),
radius_y_(radius_y), radius_y_(radius_y),
rotation_angle_(angle), rotation_angle_(angle),
force_(force), force_(force) {
source_device_id_(-1) {
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
} }
...@@ -590,7 +593,10 @@ uint16 KeyEvent::GetCharacter() const { ...@@ -590,7 +593,10 @@ uint16 KeyEvent::GetCharacter() const {
return GetCharacterFromKeyCode(key_code_, flags()); return GetCharacterFromKeyCode(key_code_, flags());
DCHECK(native_event()->type == KeyPress || DCHECK(native_event()->type == KeyPress ||
native_event()->type == KeyRelease); native_event()->type == KeyRelease ||
(native_event()->type == GenericEvent &&
(native_event()->xgeneric.evtype == XI_KeyPress ||
native_event()->xgeneric.evtype == XI_KeyRelease)));
// When a control key is held, prefer ASCII characters to non ASCII // When a control key is held, prefer ASCII characters to non ASCII
// characters in order to use it for shortcut keys. GetCharacterFromKeyCode // characters in order to use it for shortcut keys. GetCharacterFromKeyCode
......
...@@ -68,6 +68,8 @@ class EVENTS_EXPORT Event { ...@@ -68,6 +68,8 @@ class EVENTS_EXPORT Event {
const LatencyInfo* latency() const { return &latency_; } const LatencyInfo* latency() const { return &latency_; }
void set_latency(const LatencyInfo& latency) { latency_ = latency; } void set_latency(const LatencyInfo& latency) { latency_ = latency; }
int source_device_id() const { return source_device_id_; }
// By default, events are "cancelable", this means any default processing that // By default, events are "cancelable", this means any default processing that
// the containing abstraction layer may perform can be prevented by calling // the containing abstraction layer may perform can be prevented by calling
// SetHandled(). SetHandled() or StopPropagation() must not be called for // SetHandled(). SetHandled() or StopPropagation() must not be called for
...@@ -230,6 +232,10 @@ class EVENTS_EXPORT Event { ...@@ -230,6 +232,10 @@ class EVENTS_EXPORT Event {
EventTarget* target_; EventTarget* target_;
EventPhase phase_; EventPhase phase_;
EventResult result_; EventResult result_;
// The device id the event came from, or ED_UNKNOWN_DEVICE if the information
// is not available.
int source_device_id_;
}; };
class EVENTS_EXPORT CancelModeEvent : public Event { class EVENTS_EXPORT CancelModeEvent : public Event {
...@@ -388,6 +394,7 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent { ...@@ -388,6 +394,7 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
// NOTE: during a press and release flags() contains the complete set of // NOTE: during a press and release flags() contains the complete set of
// flags. Use this to determine the button that was pressed or released. // flags. Use this to determine the button that was pressed or released.
int changed_button_flags() const { return changed_button_flags_; } int changed_button_flags() const { return changed_button_flags_; }
void set_changed_button_flags(int flags) { changed_button_flags_ = flags; }
private: private:
// Returns the repeat count based on the previous mouse click, if it is // Returns the repeat count based on the previous mouse click, if it is
...@@ -455,8 +462,7 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent { ...@@ -455,8 +462,7 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
radius_x_(model.radius_x_), radius_x_(model.radius_x_),
radius_y_(model.radius_y_), radius_y_(model.radius_y_),
rotation_angle_(model.rotation_angle_), rotation_angle_(model.rotation_angle_),
force_(model.force_), force_(model.force_) {
source_device_id_(model.source_device_id_) {
} }
TouchEvent(EventType type, TouchEvent(EventType type,
...@@ -481,14 +487,10 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent { ...@@ -481,14 +487,10 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
float radius_y() const { return radius_y_; } float radius_y() const { return radius_y_; }
float rotation_angle() const { return rotation_angle_; } float rotation_angle() const { return rotation_angle_; }
float force() const { return force_; } float force() const { return force_; }
int source_device_id() const { return source_device_id_; }
// Used for unit tests. // Used for unit tests.
void set_radius_x(const float r) { radius_x_ = r; } void set_radius_x(const float r) { radius_x_ = r; }
void set_radius_y(const float r) { radius_y_ = r; } void set_radius_y(const float r) { radius_y_ = r; }
void set_source_device_id(int source_device_id) {
source_device_id_ = source_device_id;
}
// Overridden from LocatedEvent. // Overridden from LocatedEvent.
virtual void UpdateForRootTransform( virtual void UpdateForRootTransform(
...@@ -522,9 +524,6 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent { ...@@ -522,9 +524,6 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
// Force (pressure) of the touch. Normalized to be [0, 1]. Default to be 0.0. // Force (pressure) of the touch. Normalized to be [0, 1]. Default to be 0.0.
float force_; float force_;
// The device id of the screen the event came from. Default to be -1.
int source_device_id_;
}; };
class EVENTS_EXPORT KeyEvent : public Event { class EVENTS_EXPORT KeyEvent : public Event {
......
...@@ -134,6 +134,11 @@ enum EventPhase { ...@@ -134,6 +134,11 @@ enum EventPhase {
EP_POSTDISPATCH EP_POSTDISPATCH
}; };
// Device ID for Touch and Key Events.
enum EventDeviceId {
ED_UNKNOWN_DEVICE = -1
};
} // namespace ui } // namespace ui
#endif // UI_EVENTS_EVENT_CONSTANTS_H_ #endif // UI_EVENTS_EVENT_CONSTANTS_H_
...@@ -7,10 +7,11 @@ ...@@ -7,10 +7,11 @@
#include <algorithm> #include <algorithm>
#define XK_3270 // for XK_3270_BackTab #define XK_3270 // for XK_3270_BackTab
#include <X11/keysym.h> #include <X11/XF86keysym.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/XF86keysym.h> #include <X11/extensions/XInput2.h>
#include <X11/keysym.h>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -460,7 +461,7 @@ KeyboardCode FindVK(const T_MAP& key, const T_MAP* map, size_t size) { ...@@ -460,7 +461,7 @@ KeyboardCode FindVK(const T_MAP& key, const T_MAP* map, size_t size) {
} // namespace } // namespace
// Get an ui::KeyboardCode from an X keyevent // Get an ui::KeyboardCode from an X keyevent
KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) { KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev) {
// Gets correct VKEY code from XEvent is performed as the following steps: // Gets correct VKEY code from XEvent is performed as the following steps:
// 1. Gets the keysym without modifier states. // 1. Gets the keysym without modifier states.
// 2. For [a-z] & [0-9] cases, returns the VKEY code accordingly. // 2. For [a-z] & [0-9] cases, returns the VKEY code accordingly.
...@@ -475,11 +476,19 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) { ...@@ -475,11 +476,19 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
// 8. If not found, fallback to find with the hardware code in US layout. // 8. If not found, fallback to find with the hardware code in US layout.
KeySym keysym = NoSymbol; KeySym keysym = NoSymbol;
XKeyEvent xkey = xev->xkey; XEvent xkeyevent;
xkey.state &= (~0xFF | Mod2Mask); // Clears the xkey's state except numlock. if (xev->type == GenericEvent) {
// Convert the XI2 key event into a core key event so that we can
// continue to use XLookupString() until crbug.com/367732 is complete.
InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
} else {
xkeyevent.xkey = xev->xkey;
}
XKeyEvent* xkey = &xkeyevent.xkey;
xkey->state &= (~0xFF | Mod2Mask); // Clears the xkey's state except numlock.
// XLookupKeysym does not take into consideration the state of the lock/shift // XLookupKeysym does not take into consideration the state of the lock/shift
// etc. keys. So it is necessary to use XLookupString instead. // etc. keys. So it is necessary to use XLookupString instead.
XLookupString(&xkey, NULL, 0, &keysym, NULL); XLookupString(xkey, NULL, 0, &keysym, NULL);
// [a-z] cases. // [a-z] cases.
if (keysym >= XK_a && keysym <= XK_z) if (keysym >= XK_a && keysym <= XK_z)
...@@ -499,24 +508,24 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) { ...@@ -499,24 +508,24 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
if (keycode != VKEY_UNKNOWN) if (keycode != VKEY_UNKNOWN)
return keycode; return keycode;
MAP1 key1 = {keysym & 0xFFFF, xkey.keycode, 0}; MAP1 key1 = {keysym & 0xFFFF, xkey->keycode, 0};
keycode = FindVK(key1, map1, arraysize(map1)); keycode = FindVK(key1, map1, arraysize(map1));
if (keycode != VKEY_UNKNOWN) if (keycode != VKEY_UNKNOWN)
return keycode; return keycode;
KeySym keysym_shift = NoSymbol; KeySym keysym_shift = NoSymbol;
xkey.state |= ShiftMask; xkey->state |= ShiftMask;
XLookupString(&xkey, NULL, 0, &keysym_shift, NULL); XLookupString(xkey, NULL, 0, &keysym_shift, NULL);
MAP2 key2 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF, 0}; MAP2 key2 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0};
keycode = FindVK(key2, map2, arraysize(map2)); keycode = FindVK(key2, map2, arraysize(map2));
if (keycode != VKEY_UNKNOWN) if (keycode != VKEY_UNKNOWN)
return keycode; return keycode;
KeySym keysym_altgr = NoSymbol; KeySym keysym_altgr = NoSymbol;
xkey.state &= ~ShiftMask; xkey->state &= ~ShiftMask;
xkey.state |= Mod1Mask; xkey->state |= Mod1Mask;
XLookupString(&xkey, NULL, 0, &keysym_altgr, NULL); XLookupString(xkey, NULL, 0, &keysym_altgr, NULL);
MAP3 key3 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF, MAP3 key3 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF,
keysym_altgr & 0xFFFF, 0}; keysym_altgr & 0xFFFF, 0};
keycode = FindVK(key3, map3, arraysize(map3)); keycode = FindVK(key3, map3, arraysize(map3));
if (keycode != VKEY_UNKNOWN) if (keycode != VKEY_UNKNOWN)
...@@ -525,7 +534,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) { ...@@ -525,7 +534,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
// On Linux some keys has AltGr char but not on Windows. // On Linux some keys has AltGr char but not on Windows.
// So if cannot find VKEY with (ch0+sc+ch1+ch2) in map3, tries to fallback // So if cannot find VKEY with (ch0+sc+ch1+ch2) in map3, tries to fallback
// to just find VKEY with (ch0+sc+ch1). This is the best we could do. // to just find VKEY with (ch0+sc+ch1). This is the best we could do.
MAP3 key4 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF, 0xFFFF, MAP3 key4 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0xFFFF,
0}; 0};
const MAP3* p = const MAP3* p =
std::lower_bound(map3, map3 + arraysize(map3), key4, MAP3()); std::lower_bound(map3, map3 + arraysize(map3), key4, MAP3());
...@@ -536,7 +545,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) { ...@@ -536,7 +545,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
keycode = KeyboardCodeFromXKeysym(keysym); keycode = KeyboardCodeFromXKeysym(keysym);
if (keycode == VKEY_UNKNOWN) if (keycode == VKEY_UNKNOWN)
keycode = DefaultKeyboardCodeFromHardwareKeycode(xkey.keycode); keycode = DefaultKeyboardCodeFromHardwareKeycode(xkey->keycode);
return keycode; return keycode;
} }
...@@ -823,14 +832,27 @@ KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) { ...@@ -823,14 +832,27 @@ KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
return VKEY_UNKNOWN; return VKEY_UNKNOWN;
} }
const char* CodeFromXEvent(XEvent* xev) { const char* CodeFromXEvent(const XEvent* xev) {
return KeycodeConverter::GetInstance()->NativeKeycodeToCode( int keycode = (xev->type == GenericEvent)
xev->xkey.keycode); ? static_cast<XIDeviceEvent*>(xev->xcookie.data)->detail
: xev->xkey.keycode;
return KeycodeConverter::GetInstance()->NativeKeycodeToCode(keycode);
} }
uint16 GetCharacterFromXEvent(XEvent* xev) { uint16 GetCharacterFromXEvent(const XEvent* xev) {
XEvent xkeyevent;
const XKeyEvent* xkey = NULL;
char buf[6]; char buf[6];
int bytes_written = XLookupString(&xev->xkey, buf, 6, NULL, NULL); if (xev->type == GenericEvent) {
// Convert the XI2 key event into a core key event so that we can
// continue to use XLookupString() until crbug.com/367732 is complete.
InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
xkey = &xkeyevent.xkey;
} else {
xkey = &xev->xkey;
}
int bytes_written =
XLookupString(const_cast<XKeyEvent*>(xkey), buf, 6, NULL, NULL);
DCHECK_LE(bytes_written, 6); DCHECK_LE(bytes_written, 6);
if (bytes_written <= 0) if (bytes_written <= 0)
...@@ -1276,4 +1298,33 @@ int XKeysymForWindowsKeyCode(KeyboardCode keycode, bool shift) { ...@@ -1276,4 +1298,33 @@ int XKeysymForWindowsKeyCode(KeyboardCode keycode, bool shift) {
} }
} }
void InitXKeyEventFromXIDeviceEvent(const XEvent& src, XEvent* xkeyevent) {
DCHECK(src.type == GenericEvent);
XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(src.xcookie.data);
switch (xievent->evtype) {
case XI_KeyPress:
xkeyevent->type = KeyPress;
break;
case XI_KeyRelease:
xkeyevent->type = KeyRelease;
break;
default:
NOTREACHED();
}
xkeyevent->xkey.serial = xievent->serial;
xkeyevent->xkey.send_event = xievent->send_event;
xkeyevent->xkey.display = xievent->display;
xkeyevent->xkey.window = xievent->event;
xkeyevent->xkey.root = xievent->root;
xkeyevent->xkey.subwindow = xievent->child;
xkeyevent->xkey.time = xievent->time;
xkeyevent->xkey.x = xievent->event_x;
xkeyevent->xkey.y = xievent->event_y;
xkeyevent->xkey.x_root = xievent->root_x;
xkeyevent->xkey.y_root = xievent->root_y;
xkeyevent->xkey.state = xievent->mods.effective;
xkeyevent->xkey.keycode = xievent->detail;
xkeyevent->xkey.same_screen = 1;
}
} // namespace ui } // namespace ui
...@@ -13,14 +13,14 @@ typedef union _XEvent XEvent; ...@@ -13,14 +13,14 @@ typedef union _XEvent XEvent;
namespace ui { namespace ui {
EVENTS_BASE_EXPORT KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev); EVENTS_BASE_EXPORT KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev);
EVENTS_BASE_EXPORT KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym); EVENTS_BASE_EXPORT KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym);
EVENTS_BASE_EXPORT const char* CodeFromXEvent(XEvent* xev); EVENTS_BASE_EXPORT const char* CodeFromXEvent(const XEvent* xev);
// Returns a character on a standard US PC keyboard from an XEvent. // Returns a character on a standard US PC keyboard from an XEvent.
EVENTS_BASE_EXPORT uint16 GetCharacterFromXEvent(XEvent* xev); EVENTS_BASE_EXPORT uint16 GetCharacterFromXEvent(const XEvent* xev);
// Converts a KeyboardCode into an X KeySym. // Converts a KeyboardCode into an X KeySym.
EVENTS_BASE_EXPORT int XKeysymForWindowsKeyCode(KeyboardCode keycode, EVENTS_BASE_EXPORT int XKeysymForWindowsKeyCode(KeyboardCode keycode,
...@@ -30,6 +30,10 @@ EVENTS_BASE_EXPORT int XKeysymForWindowsKeyCode(KeyboardCode keycode, ...@@ -30,6 +30,10 @@ EVENTS_BASE_EXPORT int XKeysymForWindowsKeyCode(KeyboardCode keycode,
EVENTS_BASE_EXPORT KeyboardCode EVENTS_BASE_EXPORT KeyboardCode
DefaultKeyboardCodeFromHardwareKeycode(unsigned int hardware_code); DefaultKeyboardCodeFromHardwareKeycode(unsigned int hardware_code);
// Initializes a core XKeyEvent from an XI2 key event.
EVENTS_BASE_EXPORT void InitXKeyEventFromXIDeviceEvent(const XEvent& src,
XEvent* dst);
} // namespace ui } // namespace ui
#endif // UI_EVENTS_KEYCODES_KEYBOARD_CODE_CONVERSION_X_H_ #endif // UI_EVENTS_KEYCODES_KEYBOARD_CODE_CONVERSION_X_H_
...@@ -22,6 +22,10 @@ class EventTestApi { ...@@ -22,6 +22,10 @@ class EventTestApi {
event_->time_stamp_ = time_stamp; event_->time_stamp_ = time_stamp;
} }
void set_source_device_id(int source_device_id) {
event_->source_device_id_ = source_device_id;
}
private: private:
EventTestApi(); EventTestApi();
......
...@@ -45,6 +45,18 @@ int XKeyEventType(ui::EventType type) { ...@@ -45,6 +45,18 @@ int XKeyEventType(ui::EventType type) {
} }
} }
// Converts EventType to XI2 event type.
int XIKeyEventType(ui::EventType type) {
switch (type) {
case ui::ET_KEY_PRESSED:
return XI_KeyPress;
case ui::ET_KEY_RELEASED:
return XI_KeyRelease;
default:
return 0;
}
}
int XIButtonEventType(ui::EventType type) { int XIButtonEventType(ui::EventType type) {
switch (type) { switch (type) {
case ui::ET_MOUSEWHEEL: case ui::ET_MOUSEWHEEL:
...@@ -169,6 +181,21 @@ void ScopedXI2Event::InitKeyEvent(EventType type, ...@@ -169,6 +181,21 @@ void ScopedXI2Event::InitKeyEvent(EventType type,
event_->xkey.same_screen = 1; event_->xkey.same_screen = 1;
} }
void ScopedXI2Event::InitGenericKeyEvent(int deviceid,
EventType type,
KeyboardCode key_code,
int flags) {
event_.reset(
CreateXInput2Event(deviceid, XIKeyEventType(type), 0, gfx::Point()));
XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event_->xcookie.data);
CHECK_NE(0, xievent->evtype);
XDisplay* display = gfx::GetXDisplay();
event_->xgeneric.display = display;
xievent->display = display;
xievent->mods.effective = XEventState(flags);
xievent->detail = XKeyEventKeyCode(key_code, flags, display);
}
void ScopedXI2Event::InitGenericButtonEvent(int deviceid, void ScopedXI2Event::InitGenericButtonEvent(int deviceid,
EventType type, EventType type,
const gfx::Point& location, const gfx::Point& location,
......
...@@ -42,6 +42,11 @@ class ScopedXI2Event { ...@@ -42,6 +42,11 @@ class ScopedXI2Event {
KeyboardCode key_code, KeyboardCode key_code,
int flags); int flags);
void InitGenericKeyEvent(int deviceid,
EventType type,
KeyboardCode key_code,
int flags);
void InitGenericButtonEvent(int deviceid, void InitGenericButtonEvent(int deviceid,
EventType type, EventType type,
const gfx::Point& location, const gfx::Point& location,
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/XKBlib.h>
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
...@@ -42,43 +43,55 @@ class XModifierStateWatcher{ ...@@ -42,43 +43,55 @@ class XModifierStateWatcher{
return Singleton<XModifierStateWatcher>::get(); return Singleton<XModifierStateWatcher>::get();
} }
void UpdateStateFromEvent(const base::NativeEvent& native_event) { int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) {
switch (keyboard_code) {
case ui::VKEY_CONTROL:
return ControlMask;
case ui::VKEY_SHIFT:
return ShiftMask;
case ui::VKEY_MENU:
return Mod1Mask;
case ui::VKEY_CAPITAL:
return LockMask;
default:
return 0;
}
}
void UpdateStateFromXEvent(const base::NativeEvent& native_event) {
ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
unsigned int mask = StateFromKeyboardCode(keyboard_code);
// Floating device can't access the modifer state from master device. // Floating device can't access the modifer state from master device.
// We need to track the states of modifier keys in a singleton for // We need to track the states of modifier keys in a singleton for
// floating devices such as touch screen. Issue 106426 is one example // floating devices such as touch screen. Issue 106426 is one example
// of why we need the modifier states for floating device. // of why we need the modifier states for floating device.
state_ = native_event->xkey.state; switch (native_event->type) {
// master_state is the state before key press. We need to track the case KeyPress:
// state after key press for floating device. Currently only ctrl, state_ = native_event->xkey.state | mask;
// shift, alt and caps lock keys are tracked.
ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
unsigned int mask = 0;
switch (keyboard_code) {
case ui::VKEY_CONTROL: {
mask = ControlMask;
break;
}
case ui::VKEY_SHIFT: {
mask = ShiftMask;
break; break;
} case KeyRelease:
case ui::VKEY_MENU: { state_ = native_event->xkey.state & ~mask;
mask = Mod1Mask;
break; break;
} case GenericEvent: {
case ui::VKEY_CAPITAL: { XIDeviceEvent* xievent =
mask = LockMask; static_cast<XIDeviceEvent*>(native_event->xcookie.data);
switch (xievent->evtype) {
case XI_KeyPress:
state_ = xievent->mods.effective |= mask;
break;
case XI_KeyRelease:
state_ = xievent->mods.effective &= ~mask;
break;
default:
NOTREACHED();
break;
}
break; break;
} }
default: default:
NOTREACHED();
break; break;
} }
if (native_event->type == KeyPress)
state_ |= mask;
else
state_ &= ~mask;
} }
// Returns the current modifer state in master device. It only contains the // Returns the current modifer state in master device. It only contains the
...@@ -182,6 +195,18 @@ int GetEventFlagsFromXKeyEvent(XEvent* xevent) { ...@@ -182,6 +195,18 @@ int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
ime_fabricated_flag; ime_fabricated_flag;
} }
int GetEventFlagsFromXGenericEvent(XEvent* xevent) {
DCHECK(xevent->type == GenericEvent);
XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
DCHECK((xievent->evtype == XI_KeyPress) ||
(xievent->evtype == XI_KeyRelease));
return GetEventFlagsFromXState(xievent->mods.effective) |
(IsKeypadKey(
XkbKeycodeToKeysym(xievent->display, xievent->detail, 0, 0))
? ui::EF_NUMPAD_KEY
: 0);
}
// Get the event flag for the button in XButtonEvent. During a ButtonPress // Get the event flag for the button in XButtonEvent. During a ButtonPress
// event, |state| in XButtonEvent does not include the button that has just been // event, |state| in XButtonEvent does not include the button that has just been
// pressed. Instead |state| contains flags for the buttons (if any) that had // pressed. Instead |state| contains flags for the buttons (if any) that had
...@@ -354,10 +379,13 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) { ...@@ -354,10 +379,13 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
return ET_UMA_DATA; return ET_UMA_DATA;
} else if (GetButtonMaskForX2Event(xievent)) { } else if (GetButtonMaskForX2Event(xievent)) {
return ET_MOUSE_DRAGGED; return ET_MOUSE_DRAGGED;
} else {
return ET_MOUSE_MOVED;
} }
return ET_MOUSE_MOVED;
} }
case XI_KeyPress:
return ET_KEY_PRESSED;
case XI_KeyRelease:
return ET_KEY_RELEASED;
} }
} }
default: default:
...@@ -370,7 +398,7 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) { ...@@ -370,7 +398,7 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
switch (native_event->type) { switch (native_event->type) {
case KeyPress: case KeyPress:
case KeyRelease: { case KeyRelease: {
XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event); XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
return GetEventFlagsFromXKeyEvent(native_event); return GetEventFlagsFromXKeyEvent(native_event);
} }
case ButtonPress: case ButtonPress:
...@@ -406,7 +434,7 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) { ...@@ -406,7 +434,7 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
const bool touch = const bool touch =
TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid); TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
int flags = GetButtonMaskForX2Event(xievent) | int flags = GetButtonMaskForX2Event(xievent) |
GetEventFlagsFromXState(xievent->mods.effective); GetEventFlagsFromXState(xievent->mods.effective);
if (touch) { if (touch) {
flags |= GetEventFlagsFromXState( flags |= GetEventFlagsFromXState(
XModifierStateWatcher::GetInstance()->state()); XModifierStateWatcher::GetInstance()->state());
...@@ -419,8 +447,14 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) { ...@@ -419,8 +447,14 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
return flags; return flags;
} }
case XI_Motion: case XI_Motion:
return GetButtonMaskForX2Event(xievent) | return GetButtonMaskForX2Event(xievent) |
GetEventFlagsFromXState(xievent->mods.effective); GetEventFlagsFromXState(xievent->mods.effective);
case XI_KeyPress:
case XI_KeyRelease: {
XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
native_event);
return GetEventFlagsFromXGenericEvent(native_event);
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment