On Fri, Dec 16, 2011 at 10:59 AM, Tiago Vignatti <vigna...@freedesktop.org> wrote: > From: Tiago Vignatti <tiago.vigna...@intel.com> > > This adds support to ABS_MT_* support for direct touch devices and notifies > the compositor. The compositor has a stub for now. > > Signed-off-by: Tiago Vignatti <tiago.vigna...@intel.com> > --- > compositor/compositor.c | 12 ++++ > compositor/compositor.h | 4 + > compositor/evdev.c | 158 > ++++++++++++++++++++++++++++++++++++++++------- > 3 files changed, 151 insertions(+), 23 deletions(-) > > diff --git a/compositor/compositor.c b/compositor/compositor.c > index cb9b41f..2c461d8 100644 > --- a/compositor/compositor.c > +++ b/compositor/compositor.c > @@ -1493,6 +1493,18 @@ notify_keyboard_focus(struct wl_input_device *device, > } > } > > +/** > + * notify_touch - emulates button touches and notifies surfaces accordingly. > + * > + * It assumes always the correct cycle sequence until it gets here: > touch_down > + * → touch_update → ... → touch_update → touch_end. The driver is responsible > + * for sending along such order. > + */ > +WL_EXPORT void > +notify_touch(struct wl_input_device *device, uint32_t time, int touch_id, > + int x, int y, int touch_type) > +{ > +} > > static void > input_device_attach(struct wl_client *client, > diff --git a/compositor/compositor.h b/compositor/compositor.h > index 0b3f82e..676ded0 100644 > --- a/compositor/compositor.h > +++ b/compositor/compositor.h > @@ -296,6 +296,10 @@ notify_keyboard_focus(struct wl_input_device *device, > struct wl_array *keys); > > void > +notify_touch(struct wl_input_device *device, uint32_t time, int touch_id, > + int x, int y, int touch_type); > + > +void > wlsc_output_finish_frame(struct wlsc_output *output, int msecs); > void > wlsc_output_damage(struct wlsc_output *output); > diff --git a/compositor/evdev.c b/compositor/evdev.c > index 83812bf..262f452 100644 > --- a/compositor/evdev.c > +++ b/compositor/evdev.c > @@ -47,16 +47,19 @@ struct evdev_input_device { > int min_x, max_x, min_y, max_y; > int old_x, old_y, reset_x, reset_y; > } abs; > - int is_touchpad; > + int slot_mt, slot_open, slot_close; /* TODO: inside abs */ > + int is_touchpad, is_mt; > }; > > /* event type flags */ > -#define EVDEV_ABSOLUTE_MOTION (1 << 0) > -#define EVDEV_RELATIVE_MOTION (1 << 1) > +#define EVDEV_ABSOLUTE_MOTION (1 << 0) > +#define EVDEV_ABSOLUTE_MT_MOTION (1 << 1) > +#define EVDEV_RELATIVE_MOTION (1 << 2) > > struct evdev_motion_accumulator { > int x, y; > int dx, dy; > + int mt_x, mt_y; > int type; /* event type flags */ > }; > > @@ -82,8 +85,14 @@ evdev_process_key(struct evdev_input_device *device, > device->abs.reset_y = 1; > } > break; > - > case BTN_TOUCH: > + /* Multitouch touchscreen devices might not send individually > + * button events each time a new finger is down. So we don't > + * send notification for such devices and we solve the button > + * case emulating on compositor side. */ > + if (device->is_mt) > + break; > + > /* Treat BTN_TOUCH from devices that only have BTN_TOUCH as > * BTN_LEFT */ > e->code = BTN_LEFT; > @@ -107,6 +116,73 @@ evdev_process_key(struct evdev_input_device *device, > } > } > > +/* > + * evdev_notify_touch - notify the compositor about non-motion touch events > + */ > +static void > +evdev_notify_touch(struct evdev_input_device *device, int time, > + struct evdev_motion_accumulator *accum) > +{ > + if (device->slot_mt < 0) > + return; > + > + if (device->slot_close) { > + notify_touch(&device->master->base.input_device, time, > + device->slot_mt, 0, 0, WL_INPUT_DEVICE_TOUCH_UP); > + device->slot_close = 0; > + } else if (device->slot_open) { > + notify_touch(&device->master->base.input_device, time, > + device->slot_mt, 0, 0, > + WL_INPUT_DEVICE_TOUCH_DOWN); > + device->slot_open = 0; > + } > +} > + > +static void > +evdev_process_touch(struct evdev_input_device *device, > + struct input_event *e, int time, > + struct evdev_motion_accumulator *accum) > +{ > + switch (e->code) { > + case ABS_MT_SLOT: > + device->slot_mt = e->value; > + break; > + case ABS_MT_TRACKING_ID: > + if (e->value >= 0) > + device->slot_open = 1; > + else > + device->slot_close = 1; > + > + evdev_notify_touch(device, time, accum); > + } > + return; > +} > + > +static void > +evdev_process_touch_motion(struct evdev_input_device *device, > + struct input_event *e, int time, > + struct evdev_motion_accumulator *accum) > +{ > + const int screen_width = device->output->current->width; > + const int screen_height = device->output->current->height; > + > + switch (e->code) { > + case ABS_MT_POSITION_X: > + accum->mt_x = (e->value - device->abs.min_x) * screen_width / > + (device->abs.max_x - device->abs.min_x) + > + device->output->x; > + accum->type |= EVDEV_ABSOLUTE_MT_MOTION; > + break; > + case ABS_MT_POSITION_Y: > + accum->mt_y = (e->value - device->abs.min_y) * screen_height / > + (device->abs.max_y - device->abs.min_y) + > + device->output->y; > + accum->type |= EVDEV_ABSOLUTE_MT_MOTION; > + break; > + } > + return; > +}
Can we just fold these three functions into one evdev_process_touch() with a switch over e->code? Also to get coordinates on the touch_down event, we need to treat the first ABS_MT_POSITION_X/Y as touch down (which it is), so I suggest adding a new accumulator flag: EVDEV_ABSOLUTE_MT_DOWN and set that when we receive positive tracking ID. Then in flush we check for that flag and send the down event if it's set otherwise if the MT_MOTION is set we send motion, and in either case we clear both. We also need an accumulator flag for touch up, that is, when we get a negative tracking ID for a slot. We won't need the slot_open and slot_close flags then. > static inline void > evdev_process_absolute_motion(struct evdev_input_device *device, > struct input_event *e, struct evdev_motion_accumulator *accum) > @@ -119,13 +195,13 @@ evdev_process_absolute_motion(struct evdev_input_device > *device, > accum->x = (e->value - device->abs.min_x) * screen_width / > (device->abs.max_x - device->abs.min_x) + > device->output->x; > - accum->type = EVDEV_ABSOLUTE_MOTION; > + accum->type |= EVDEV_ABSOLUTE_MOTION; > break; > case ABS_Y: > accum->y = (e->value - device->abs.min_y) * screen_height / > (device->abs.max_y - device->abs.min_y) + > device->output->y; > - accum->type = EVDEV_ABSOLUTE_MOTION; > + accum->type |= EVDEV_ABSOLUTE_MOTION; > break; > } > } > @@ -148,7 +224,7 @@ evdev_process_absolute_motion_touchpad(struct > evdev_input_device *device, > (device->abs.max_x - device->abs.min_x); > } > device->abs.old_x = e->value; > - accum->type = EVDEV_RELATIVE_MOTION; > + accum->type |= EVDEV_RELATIVE_MOTION; > break; > case ABS_Y: > e->value -= device->abs.min_y; > @@ -161,7 +237,7 @@ evdev_process_absolute_motion_touchpad(struct > evdev_input_device *device, > (device->abs.max_y - device->abs.min_y); > } > device->abs.old_y = e->value; > - accum->type = EVDEV_RELATIVE_MOTION; > + accum->type |= EVDEV_RELATIVE_MOTION; > break; > } > } > @@ -173,15 +249,32 @@ evdev_process_relative_motion(struct input_event *e, > switch (e->code) { > case REL_X: > accum->dx += e->value; > - accum->type = EVDEV_RELATIVE_MOTION; > + accum->type |= EVDEV_RELATIVE_MOTION; > break; > case REL_Y: > accum->dy += e->value; > - accum->type = EVDEV_RELATIVE_MOTION; > + accum->type |= EVDEV_RELATIVE_MOTION; > break; > } > } > > +static inline void > +evdev_process_absolute(struct evdev_input_device *device, > + struct input_event *e, int time, > + struct evdev_motion_accumulator *accum) > +{ > + if (device->is_touchpad) > + evdev_process_absolute_motion_touchpad(device, e, accum); > + else { use else if (device->is_mt) { instead to avoid indentation > + if (device->is_mt) { > + evdev_process_touch(device, e, time, accum); > + evdev_process_touch_motion(device, e, time, accum); This becomes just evdev_process_touch_mt(). > + } > + else else on the same line as { (and I normally use {}'s in both branches of an if-statement if one of them requires it...) > + evdev_process_absolute_motion(device, e, accum); > + } > +} > + > static int > is_motion_event(struct input_event *e) > { > @@ -196,6 +289,8 @@ is_motion_event(struct input_event *e) > switch (e->code) { > case ABS_X: > case ABS_Y: > + case ABS_MT_POSITION_X: > + case ABS_MT_POSITION_Y: > return 1; > } > } > @@ -213,24 +308,37 @@ evdev_reset_accum(struct wl_input_device *device, > * through the bytestream whereas the other could be omitted. For > * this, we have to save the old value that will be forwarded without > * modifications to the compositor. */ > - accum->x = device->x; > - accum->y = device->y; > + accum->mt_x = accum->x = device->x; > + accum->mt_y = accum->y = device->y; > } > > static void > evdev_flush_motion(struct wl_input_device *device, uint32_t time, > - struct evdev_motion_accumulator *accum) > + struct evdev_motion_accumulator *accum, int slot_mt) > { > + int save_types; > + > if (!accum->type) > return; > > - if (accum->type == EVDEV_RELATIVE_MOTION) > + if (accum->type & EVDEV_RELATIVE_MOTION) { > notify_motion(device, time, > device->x + accum->dx, device->y + accum->dy); > - if (accum->type == EVDEV_ABSOLUTE_MOTION) > + accum->type &= ~EVDEV_RELATIVE_MOTION; > + } > + if (accum->type & EVDEV_ABSOLUTE_MT_MOTION) { > + notify_touch(device, time, slot_mt, accum->mt_x, accum->mt_y, > + WL_INPUT_DEVICE_TOUCH_MOTION); > + accum->type &= ~EVDEV_ABSOLUTE_MT_MOTION; > + } > + if (accum->type & EVDEV_ABSOLUTE_MOTION) { > notify_motion(device, time, accum->x, accum->y); > + accum->type &= ~EVDEV_ABSOLUTE_MOTION; > + } > > + save_types = accum->type; > evdev_reset_accum(device, accum); > + accum->type = save_types; I think we can just set dx and dy to 0 in the EVDEV_RELATIVE_MOTION case and skip save_types and the call to evdev_reset_accum() instead. > } > > static int > @@ -265,18 +373,13 @@ evdev_input_device_data(int fd, uint32_t mask, void > *data) > * events and send as a bunch */ > if (!is_motion_event(e)) > evdev_flush_motion(&device->master->base.input_device, > - time, &accumulator); > + time, &accumulator, > device->slot_mt); > switch (e->type) { > case EV_REL: > evdev_process_relative_motion(e, &accumulator); > break; > case EV_ABS: > - if (device->is_touchpad) > - evdev_process_absolute_motion_touchpad(device, > - e, &accumulator); > - else > - evdev_process_absolute_motion(device, e, > - &accumulator); > + evdev_process_absolute(device, e, time, &accumulator); > break; > case EV_KEY: > evdev_process_key(device, e, time); > @@ -284,7 +387,8 @@ evdev_input_device_data(int fd, uint32_t mask, void *data) > } > } > > - evdev_flush_motion(&device->master->base.input_device, time, > &accumulator); > + evdev_flush_motion(&device->master->base.input_device, time, > + &accumulator, device->slot_mt); > > return 1; > } > @@ -328,6 +432,10 @@ evdev_configure_device(struct evdev_input_device *device) > device->abs.min_y = absinfo.minimum; > device->abs.max_y = absinfo.maximum; > } > + if (TEST_BIT(abs_bits, ABS_MT_SLOT)) { > + device->is_mt = 1; > + device->slot_mt = 0; > + } > } > if (TEST_BIT(ev_bits, EV_KEY)) { > has_key = 1; > @@ -365,7 +473,11 @@ evdev_input_device_create(struct evdev_input *master, > > device->master = master; > device->is_touchpad = 0; > + device->is_mt = 0; > device->devnode = strdup(path); > + device->slot_mt = -1; > + device->slot_open = 0; > + device->slot_close = 0; > > device->fd = open(path, O_RDONLY); > if (device->fd < 0) > -- > 1.7.5.4 > > _______________________________________________ > wayland-devel mailing list > wayland-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/wayland-devel _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel