Commit d415c687 authored by spang's avatar spang Committed by Commit bot

ozone: evdev: Fix possibility of stuck keys with libevdev

Same as previous unplug fix, but for the libevdev/gestures path. This
applies to hybrid keyboards with attached mouse/touchpad.

The SYN_DROPPED part is N/A because that is handled by libevdev.

BUG=463002
TEST=Tested unplug by unplugging devices with shift held.
  Shift gets properly released rather than being stuck.
  (NB: Could not reproduce without adding a delay to expose the race).

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

Cr-Commit-Position: refs/heads/master@{#319673}
parent d50b6df7
...@@ -98,6 +98,10 @@ void EventReaderLibevdevCros::AllowAllKeys() { ...@@ -98,6 +98,10 @@ void EventReaderLibevdevCros::AllowAllKeys() {
delegate_->AllowAllKeys(); delegate_->AllowAllKeys();
} }
void EventReaderLibevdevCros::OnStopped() {
delegate_->OnLibEvdevCrosStopped(&evdev_, &evstate_);
}
// static // static
void EventReaderLibevdevCros::OnSynReport(void* data, void EventReaderLibevdevCros::OnSynReport(void* data,
EventStateRec* evstate, EventStateRec* evstate,
......
...@@ -35,6 +35,9 @@ class EventReaderLibevdevCros : public EventConverterEvdev { ...@@ -35,6 +35,9 @@ class EventReaderLibevdevCros : public EventConverterEvdev {
EventStateRec* state, EventStateRec* state,
const timeval& time) = 0; const timeval& time) = 0;
// Notifier for stop. This is called with the final event state.
virtual void OnLibEvdevCrosStopped(Evdev* evdev, EventStateRec* state) = 0;
// Sets which keyboard keys should be processed. // Sets which keyboard keys should be processed.
virtual void SetAllowedKeys(scoped_ptr<std::set<DomCode>> allowed_keys) = 0; virtual void SetAllowedKeys(scoped_ptr<std::set<DomCode>> allowed_keys) = 0;
...@@ -58,6 +61,7 @@ class EventReaderLibevdevCros : public EventConverterEvdev { ...@@ -58,6 +61,7 @@ class EventReaderLibevdevCros : public EventConverterEvdev {
bool HasCapsLockLed() const override; bool HasCapsLockLed() const override;
void SetAllowedKeys(scoped_ptr<std::set<DomCode>> allowed_keys) override; void SetAllowedKeys(scoped_ptr<std::set<DomCode>> allowed_keys) override;
void AllowAllKeys() override; void AllowAllKeys() override;
void OnStopped() override;
private: private:
static void OnSynReport(void* data, static void OnSynReport(void* data,
......
...@@ -79,10 +79,6 @@ base::TimeDelta StimeToTimedelta(stime_t timestamp) { ...@@ -79,10 +79,6 @@ base::TimeDelta StimeToTimedelta(stime_t timestamp) {
base::Time::kMicrosecondsPerSecond); base::Time::kMicrosecondsPerSecond);
} }
base::TimeDelta TimeValToTimeDelta(const timeval& tv) {
return base::TimeDelta::FromMicroseconds(tv.tv_sec * 1000000 + tv.tv_usec);
}
// Number of fingers for scroll gestures. // Number of fingers for scroll gestures.
const int kGestureScrollFingerCount = 2; const int kGestureScrollFingerCount = 2;
...@@ -160,12 +156,14 @@ void GestureInterpreterLibevdevCros::OnLibEvdevCrosOpen( ...@@ -160,12 +156,14 @@ void GestureInterpreterLibevdevCros::OnLibEvdevCrosOpen(
void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev, void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev,
EventStateRec* evstate, EventStateRec* evstate,
const timeval& time) { const timeval& time) {
// If the device has keys no it, dispatch any presses/release. stime_t timestamp = StimeFromTimeval(&time);
DispatchChangedKeys(evdev, time);
// If the device has keys on it, dispatch any presses/release.
DispatchChangedKeys(evdev->key_state_bitmask, timestamp);
HardwareState hwstate; HardwareState hwstate;
memset(&hwstate, 0, sizeof(hwstate)); memset(&hwstate, 0, sizeof(hwstate));
hwstate.timestamp = StimeFromTimeval(&time); hwstate.timestamp = timestamp;
// Mouse. // Mouse.
hwstate.rel_x = evstate->rel_x; hwstate.rel_x = evstate->rel_x;
...@@ -207,6 +205,12 @@ void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev, ...@@ -207,6 +205,12 @@ void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev,
GestureInterpreterPushHardwareState(interpreter_, &hwstate); GestureInterpreterPushHardwareState(interpreter_, &hwstate);
} }
void GestureInterpreterLibevdevCros::OnLibEvdevCrosStopped(
Evdev* evdev,
EventStateRec* state) {
ReleaseKeys();
}
void GestureInterpreterLibevdevCros::SetAllowedKeys( void GestureInterpreterLibevdevCros::SetAllowedKeys(
scoped_ptr<std::set<DomCode>> allowed_keys) { scoped_ptr<std::set<DomCode>> allowed_keys) {
if (!allowed_keys) { if (!allowed_keys) {
...@@ -421,18 +425,19 @@ void GestureInterpreterLibevdevCros::DispatchMouseButton(unsigned int button, ...@@ -421,18 +425,19 @@ void GestureInterpreterLibevdevCros::DispatchMouseButton(unsigned int button,
allow_remap, StimeToTimedelta(time))); allow_remap, StimeToTimedelta(time)));
} }
void GestureInterpreterLibevdevCros::DispatchChangedKeys(Evdev* evdev, void GestureInterpreterLibevdevCros::DispatchChangedKeys(
const timeval& time) { unsigned long* new_key_state,
stime_t timestamp) {
unsigned long key_state_diff[EVDEV_BITS_TO_LONGS(KEY_CNT)]; unsigned long key_state_diff[EVDEV_BITS_TO_LONGS(KEY_CNT)];
// Find changed keys. // Find changed keys.
for (unsigned long i = 0; i < arraysize(key_state_diff); ++i) for (unsigned long i = 0; i < arraysize(key_state_diff); ++i)
key_state_diff[i] = evdev->key_state_bitmask[i] ^ prev_key_state_[i]; key_state_diff[i] = new_key_state[i] ^ prev_key_state_[i];
// Dispatch events for changed keys. // Dispatch events for changed keys.
for (unsigned long key = 0; key < KEY_CNT; ++key) { for (unsigned long key = 0; key < KEY_CNT; ++key) {
if (EvdevBitIsSet(key_state_diff, key)) { if (EvdevBitIsSet(key_state_diff, key)) {
bool value = EvdevBitIsSet(evdev->key_state_bitmask, key); bool value = EvdevBitIsSet(new_key_state, key);
// Mouse buttons are handled by DispatchMouseButton. // Mouse buttons are handled by DispatchMouseButton.
if (key >= BTN_MOUSE && key < BTN_JOYSTICK) if (key >= BTN_MOUSE && key < BTN_JOYSTICK)
...@@ -447,13 +452,20 @@ void GestureInterpreterLibevdevCros::DispatchChangedKeys(Evdev* evdev, ...@@ -447,13 +452,20 @@ void GestureInterpreterLibevdevCros::DispatchChangedKeys(Evdev* evdev,
// Dispatch key press or release to keyboard. // Dispatch key press or release to keyboard.
dispatcher_->DispatchKeyEvent( dispatcher_->DispatchKeyEvent(
KeyEventParams(id_, key, value, TimeValToTimeDelta(time))); KeyEventParams(id_, key, value, StimeToTimedelta(timestamp)));
} }
} }
// Update internal key state. // Update internal key state.
for (unsigned long i = 0; i < EVDEV_BITS_TO_LONGS(KEY_CNT); ++i) for (unsigned long i = 0; i < EVDEV_BITS_TO_LONGS(KEY_CNT); ++i)
prev_key_state_[i] = evdev->key_state_bitmask[i]; prev_key_state_[i] = new_key_state[i];
}
void GestureInterpreterLibevdevCros::ReleaseKeys() {
unsigned long new_key_state[EVDEV_BITS_TO_LONGS(KEY_CNT)];
memset(&new_key_state, 0, sizeof(new_key_state));
DispatchChangedKeys(new_key_state, StimeNow());
} }
} // namespace ui } // namespace ui
...@@ -51,6 +51,7 @@ class EVENTS_OZONE_EVDEV_EXPORT GestureInterpreterLibevdevCros ...@@ -51,6 +51,7 @@ class EVENTS_OZONE_EVDEV_EXPORT GestureInterpreterLibevdevCros
void OnLibEvdevCrosEvent(Evdev* evdev, void OnLibEvdevCrosEvent(Evdev* evdev,
EventStateRec* evstate, EventStateRec* evstate,
const timeval& time) override; const timeval& time) override;
void OnLibEvdevCrosStopped(Evdev* evdev, EventStateRec* state) override;
void SetAllowedKeys( void SetAllowedKeys(
scoped_ptr<std::set<DomCode>> allowed_keys) override; scoped_ptr<std::set<DomCode>> allowed_keys) override;
void AllowAllKeys() override; void AllowAllKeys() override;
...@@ -79,7 +80,8 @@ class EVENTS_OZONE_EVDEV_EXPORT GestureInterpreterLibevdevCros ...@@ -79,7 +80,8 @@ class EVENTS_OZONE_EVDEV_EXPORT GestureInterpreterLibevdevCros
void DispatchMouseButton(unsigned int modifier, void DispatchMouseButton(unsigned int modifier,
bool down, bool down,
stime_t time); stime_t time);
void DispatchChangedKeys(Evdev* evdev, const timeval& time); void DispatchChangedKeys(unsigned long* changed_keys, stime_t timestamp);
void ReleaseKeys();
// The unique device id. // The unique device id.
int id_; int id_;
......
...@@ -28,12 +28,8 @@ struct GesturesTimer { ...@@ -28,12 +28,8 @@ struct GesturesTimer {
private: private:
void OnTimerExpired() { void OnTimerExpired() {
struct timespec ts;
int fail = clock_gettime(CLOCK_MONOTONIC, &ts);
DCHECK(!fail);
// Run the callback and reschedule the next run if requested. // Run the callback and reschedule the next run if requested.
stime_t next_delay = callback_(StimeFromTimespec(&ts), callback_data_); stime_t next_delay = callback_(ui::StimeNow(), callback_data_);
if (next_delay >= 0) { if (next_delay >= 0) {
timer_.Start(FROM_HERE, timer_.Start(FROM_HERE,
base::TimeDelta::FromMicroseconds( base::TimeDelta::FromMicroseconds(
...@@ -68,6 +64,15 @@ void GesturesTimerFree(void* data, GesturesTimer* timer) { delete timer; } ...@@ -68,6 +64,15 @@ void GesturesTimerFree(void* data, GesturesTimer* timer) { delete timer; }
} // namespace } // namespace
stime_t StimeNow() {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts))
PLOG(FATAL) << "clock_gettime";
return StimeFromTimespec(&ts);
}
const GesturesTimerProvider kGestureTimerProvider = { const GesturesTimerProvider kGestureTimerProvider = {
GesturesTimerCreate, GesturesTimerSet, GesturesTimerCancel, GesturesTimerCreate, GesturesTimerSet, GesturesTimerCancel,
GesturesTimerFree}; GesturesTimerFree};
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
namespace ui { namespace ui {
stime_t StimeNow();
extern const GesturesTimerProvider kGestureTimerProvider; extern const GesturesTimerProvider kGestureTimerProvider;
} // namspace ui } // namspace ui
......
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