evdev-touchpad: Add a finite-state machine
The finite-state machine is so far used to implement support for tapping and dragging. Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
committed by
Kristian Høgsberg
parent
c689493b1a
commit
87b0735273
@@ -23,6 +23,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
@@ -34,6 +35,9 @@
|
|||||||
#define DEFAULT_MAX_ACCEL_FACTOR 1.0
|
#define DEFAULT_MAX_ACCEL_FACTOR 1.0
|
||||||
#define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
|
#define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
|
||||||
|
|
||||||
|
#define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
|
||||||
|
#define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
|
||||||
|
|
||||||
enum touchpad_model {
|
enum touchpad_model {
|
||||||
TOUCHPAD_MODEL_UNKNOWN = 0,
|
TOUCHPAD_MODEL_UNKNOWN = 0,
|
||||||
TOUCHPAD_MODEL_SYNAPTICS,
|
TOUCHPAD_MODEL_SYNAPTICS,
|
||||||
@@ -83,6 +87,21 @@ enum touchpad_fingers_state {
|
|||||||
TOUCHPAD_FINGERS_THREE = (1 << 2)
|
TOUCHPAD_FINGERS_THREE = (1 << 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum fsm_event {
|
||||||
|
FSM_EVENT_TOUCH,
|
||||||
|
FSM_EVENT_RELEASE,
|
||||||
|
FSM_EVENT_MOTION,
|
||||||
|
FSM_EVENT_TIMEOUT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fsm_state {
|
||||||
|
FSM_IDLE,
|
||||||
|
FSM_TOUCH,
|
||||||
|
FSM_TAP,
|
||||||
|
FSM_TAP_2,
|
||||||
|
FSM_DRAG
|
||||||
|
};
|
||||||
|
|
||||||
struct touchpad_dispatch {
|
struct touchpad_dispatch {
|
||||||
struct evdev_dispatch base;
|
struct evdev_dispatch base;
|
||||||
struct evdev_device *device;
|
struct evdev_device *device;
|
||||||
@@ -101,6 +120,12 @@ struct touchpad_dispatch {
|
|||||||
|
|
||||||
int reset;
|
int reset;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_array events;
|
||||||
|
enum fsm_state state;
|
||||||
|
struct wl_event_source *timer_source;
|
||||||
|
} fsm;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
int32_t y;
|
||||||
@@ -245,6 +270,147 @@ filter_motion(struct touchpad_dispatch *touchpad,
|
|||||||
*dy = motion.dy;
|
*dy = motion.dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||||
|
{
|
||||||
|
notify_button(touchpad->device->seat, time,
|
||||||
|
DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
|
||||||
|
WL_POINTER_BUTTON_STATE_PRESSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||||
|
{
|
||||||
|
notify_button(touchpad->device->seat, time,
|
||||||
|
DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
|
||||||
|
WL_POINTER_BUTTON_STATE_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||||
|
{
|
||||||
|
notify_button_pressed(touchpad, time);
|
||||||
|
notify_button_released(touchpad, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||||
|
{
|
||||||
|
uint32_t timeout = UINT32_MAX;
|
||||||
|
enum fsm_event *pevent;
|
||||||
|
enum fsm_event event;
|
||||||
|
|
||||||
|
if (touchpad->fsm.events.size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wl_array_for_each(pevent, &touchpad->fsm.events) {
|
||||||
|
event = *pevent;
|
||||||
|
timeout = 0;
|
||||||
|
|
||||||
|
switch (touchpad->fsm.state) {
|
||||||
|
case FSM_IDLE:
|
||||||
|
switch (event) {
|
||||||
|
case FSM_EVENT_TOUCH:
|
||||||
|
touchpad->fsm.state = FSM_TOUCH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FSM_TOUCH:
|
||||||
|
switch (event) {
|
||||||
|
case FSM_EVENT_RELEASE:
|
||||||
|
timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
|
||||||
|
touchpad->fsm.state = FSM_TAP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FSM_TAP:
|
||||||
|
switch (event) {
|
||||||
|
case FSM_EVENT_TIMEOUT:
|
||||||
|
notify_tap(touchpad, time);
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
case FSM_EVENT_TOUCH:
|
||||||
|
notify_button_pressed(touchpad, time);
|
||||||
|
touchpad->fsm.state = FSM_TAP_2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FSM_TAP_2:
|
||||||
|
switch (event) {
|
||||||
|
case FSM_EVENT_MOTION:
|
||||||
|
touchpad->fsm.state = FSM_DRAG;
|
||||||
|
break;
|
||||||
|
case FSM_EVENT_RELEASE:
|
||||||
|
notify_button_released(touchpad, time);
|
||||||
|
notify_tap(touchpad, time);
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FSM_DRAG:
|
||||||
|
switch (event) {
|
||||||
|
case FSM_EVENT_RELEASE:
|
||||||
|
notify_button_released(touchpad, time);
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
weston_log("evdev-touchpad: Unknown state %d",
|
||||||
|
touchpad->fsm.state);
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout != UINT32_MAX)
|
||||||
|
wl_event_source_timer_update(touchpad->fsm.timer_source,
|
||||||
|
timeout);
|
||||||
|
|
||||||
|
wl_array_release(&touchpad->fsm.events);
|
||||||
|
wl_array_init(&touchpad->fsm.events);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
push_fsm_event(struct touchpad_dispatch *touchpad,
|
||||||
|
enum fsm_event event)
|
||||||
|
{
|
||||||
|
enum fsm_event *pevent;
|
||||||
|
|
||||||
|
pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
|
||||||
|
if (pevent)
|
||||||
|
*pevent = event;
|
||||||
|
else
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fsm_timout_handler(void *data)
|
||||||
|
{
|
||||||
|
struct touchpad_dispatch *touchpad = data;
|
||||||
|
|
||||||
|
if (touchpad->fsm.events.size == 0) {
|
||||||
|
push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
|
||||||
|
process_fsm_events(touchpad, weston_compositor_get_time());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
|
touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||||
{
|
{
|
||||||
@@ -262,6 +428,8 @@ touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
|
|||||||
|
|
||||||
touchpad->last_finger_state = touchpad->finger_state;
|
touchpad->last_finger_state = touchpad->finger_state;
|
||||||
|
|
||||||
|
process_fsm_events(touchpad, time);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
touchpad->last_finger_state = touchpad->finger_state;
|
touchpad->last_finger_state = touchpad->finger_state;
|
||||||
@@ -317,13 +485,18 @@ touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
|
|||||||
if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
|
if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
|
||||||
((int)dx || (int)dy)) {
|
((int)dx || (int)dy)) {
|
||||||
touchpad->state |= TOUCHPAD_STATE_MOVE;
|
touchpad->state |= TOUCHPAD_STATE_MOVE;
|
||||||
|
push_fsm_event(touchpad, FSM_EVENT_MOTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_fsm_events(touchpad, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_touch(struct touchpad_dispatch *touchpad)
|
on_touch(struct touchpad_dispatch *touchpad)
|
||||||
{
|
{
|
||||||
touchpad->state |= TOUCHPAD_STATE_TOUCH;
|
touchpad->state |= TOUCHPAD_STATE_TOUCH;
|
||||||
|
|
||||||
|
push_fsm_event(touchpad, FSM_EVENT_TOUCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -332,6 +505,8 @@ on_release(struct touchpad_dispatch *touchpad)
|
|||||||
|
|
||||||
touchpad->reset = 1;
|
touchpad->reset = 1;
|
||||||
touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
|
touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
|
||||||
|
|
||||||
|
push_fsm_event(touchpad, FSM_EVENT_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -453,6 +628,7 @@ touchpad_destroy(struct evdev_dispatch *dispatch)
|
|||||||
(struct touchpad_dispatch *) dispatch;
|
(struct touchpad_dispatch *) dispatch;
|
||||||
|
|
||||||
touchpad->filter->interface->destroy(touchpad->filter);
|
touchpad->filter->interface->destroy(touchpad->filter);
|
||||||
|
wl_event_source_remove(touchpad->fsm.timer_source);
|
||||||
free(dispatch);
|
free(dispatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +642,7 @@ touchpad_init(struct touchpad_dispatch *touchpad,
|
|||||||
struct evdev_device *device)
|
struct evdev_device *device)
|
||||||
{
|
{
|
||||||
struct weston_motion_filter *accel;
|
struct weston_motion_filter *accel;
|
||||||
|
struct wl_event_loop *loop;
|
||||||
|
|
||||||
struct input_absinfo absinfo;
|
struct input_absinfo absinfo;
|
||||||
unsigned long abs_bits[NBITS(ABS_MAX)];
|
unsigned long abs_bits[NBITS(ABS_MAX)];
|
||||||
@@ -524,6 +701,17 @@ touchpad_init(struct touchpad_dispatch *touchpad,
|
|||||||
touchpad->last_finger_state = 0;
|
touchpad->last_finger_state = 0;
|
||||||
touchpad->finger_state = 0;
|
touchpad->finger_state = 0;
|
||||||
|
|
||||||
|
wl_array_init(&touchpad->fsm.events);
|
||||||
|
touchpad->fsm.state = FSM_IDLE;
|
||||||
|
|
||||||
|
loop = wl_display_get_event_loop(device->seat->compositor->wl_display);
|
||||||
|
touchpad->fsm.timer_source =
|
||||||
|
wl_event_loop_add_timer(loop, fsm_timout_handler, touchpad);
|
||||||
|
if (touchpad->fsm.timer_source == NULL) {
|
||||||
|
accel->interface->destroy(accel);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user