mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-05 16:50:29 +01:00
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:
parent
f4706c6779
commit
68449fc8e8
1 changed files with 188 additions and 0 deletions
|
|
@ -23,6 +23,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "filter.h"
|
||||
|
|
@ -34,6 +35,9 @@
|
|||
#define DEFAULT_MAX_ACCEL_FACTOR 1.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 {
|
||||
TOUCHPAD_MODEL_UNKNOWN = 0,
|
||||
TOUCHPAD_MODEL_SYNAPTICS,
|
||||
|
|
@ -83,6 +87,21 @@ enum touchpad_fingers_state {
|
|||
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 evdev_dispatch base;
|
||||
struct evdev_device *device;
|
||||
|
|
@ -101,6 +120,12 @@ struct touchpad_dispatch {
|
|||
|
||||
int reset;
|
||||
|
||||
struct {
|
||||
struct wl_array events;
|
||||
enum fsm_state state;
|
||||
struct wl_event_source *timer_source;
|
||||
} fsm;
|
||||
|
||||
struct {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
@ -245,6 +270,147 @@ filter_motion(struct touchpad_dispatch *touchpad,
|
|||
*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
|
||||
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;
|
||||
|
||||
process_fsm_events(touchpad, time);
|
||||
|
||||
return;
|
||||
}
|
||||
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) &&
|
||||
((int)dx || (int)dy)) {
|
||||
touchpad->state |= TOUCHPAD_STATE_MOVE;
|
||||
push_fsm_event(touchpad, FSM_EVENT_MOTION);
|
||||
}
|
||||
|
||||
process_fsm_events(touchpad, time);
|
||||
}
|
||||
|
||||
static void
|
||||
on_touch(struct touchpad_dispatch *touchpad)
|
||||
{
|
||||
touchpad->state |= TOUCHPAD_STATE_TOUCH;
|
||||
|
||||
push_fsm_event(touchpad, FSM_EVENT_TOUCH);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -332,6 +505,8 @@ on_release(struct touchpad_dispatch *touchpad)
|
|||
|
||||
touchpad->reset = 1;
|
||||
touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
|
||||
|
||||
push_fsm_event(touchpad, FSM_EVENT_RELEASE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -453,6 +628,7 @@ touchpad_destroy(struct evdev_dispatch *dispatch)
|
|||
(struct touchpad_dispatch *) dispatch;
|
||||
|
||||
touchpad->filter->interface->destroy(touchpad->filter);
|
||||
wl_event_source_remove(touchpad->fsm.timer_source);
|
||||
free(dispatch);
|
||||
}
|
||||
|
||||
|
|
@ -466,6 +642,7 @@ touchpad_init(struct touchpad_dispatch *touchpad,
|
|||
struct evdev_device *device)
|
||||
{
|
||||
struct weston_motion_filter *accel;
|
||||
struct wl_event_loop *loop;
|
||||
|
||||
struct input_absinfo absinfo;
|
||||
unsigned long abs_bits[NBITS(ABS_MAX)];
|
||||
|
|
@ -524,6 +701,17 @@ touchpad_init(struct touchpad_dispatch *touchpad,
|
|||
touchpad->last_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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue