[PATCH weston 2/8] evdev-touchpad: Add a finite-state machine
Jonas Ådahl
jadahl at gmail.com
Thu Sep 27 09:40:40 PDT 2012
The finite-state machine is so far used to implement support for tapping
and dragging.
Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
src/evdev-touchpad.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 188 insertions(+)
diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c
index 7a724c8..3ba8f80 100644
--- a/src/evdev-touchpad.c
+++ b/src/evdev-touchpad.c
@@ -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;
@@ -102,6 +121,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;
} hw_abs;
@@ -246,6 +271,147 @@ filter_motion(struct touchpad_dispatch *touchpad,
}
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)
{
int motion_index;
@@ -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;
}
--
1.7.9.5
More information about the wayland-devel
mailing list