blob: 5aa30b565ba46298455d1f7215cb80a676ebcfd6 [file] [log] [blame]
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gesture.h"
#include <gestures/gestures.h>
#include <xorg/xf86_OSproc.h>
#include "cmt.h"
#include "properties.h"
static unsigned MT_XButtons_To_Gestures_Buttons(unsigned);
/*
* Gestures timer functions
*/
static GesturesTimer* Gesture_TimerCreate(void*);
static void Gesture_TimerSet(void*,
GesturesTimer*,
stime_t,
GesturesTimerCallback,
void*);
static void Gesture_TimerCancel(void*, GesturesTimer*);
static void Gesture_TimerFree(void*, GesturesTimer*);
static CARD32 Gesture_TimerCallback(OsTimerPtr, CARD32, pointer);
struct GesturesTimer {
OsTimerPtr timer;
GesturesTimerCallback callback;
void* data;
};
static GesturesTimerProvider Gesture_GesturesTimerProvider = {
.create_fn = Gesture_TimerCreate,
.set_fn = Gesture_TimerSet,
.cancel_fn = Gesture_TimerCancel,
.free_fn = Gesture_TimerFree
};
/*
* Callback for Gestures library.
*/
static void Gesture_Gesture_Ready(void* client_data,
const struct Gesture* gesture);
int
Gesture_Init(GesturePtr rec)
{
rec->interpreter = NewGestureInterpreter();
if (!rec->interpreter)
return !Success;
GestureInterpreterSetTimerProvider(rec->interpreter,
&Gesture_GesturesTimerProvider,
NULL);
return Success;
}
void
Gesture_Free(GesturePtr rec)
{
GestureInterpreterSetTimerProvider(rec->interpreter, NULL, NULL);
DeleteGestureInterpreter(rec->interpreter);
rec->interpreter = NULL;
rec->dev = NULL;
}
void
Gesture_Device_Init(GesturePtr rec, DeviceIntPtr dev)
{
InputInfoPtr info = dev->public.devicePrivate;
CmtDevicePtr cmt = info->private;
CmtPropertiesPtr props = &cmt->props;
EventStatePtr evstate = &cmt->evstate;
struct HardwareProperties hwprops;
/* Store the device for which to generate gestures */
rec->dev = dev;
/* TODO: support different models */
hwprops.left = props->area_left;
hwprops.top = props->area_top;
hwprops.right = props->area_right;
hwprops.bottom = props->area_bottom;
hwprops.res_x = props->res_x;
hwprops.res_y = props->res_y;
hwprops.screen_x_dpi = 133;
hwprops.screen_y_dpi = 133;
hwprops.max_finger_cnt = evstate->slot_count;
hwprops.supports_t5r2 = Event_Get_T5R2(info);;
hwprops.support_semi_mt = Event_Get_Semi_MT(info);
/* buttonpad means a physical button under the touch surface */
hwprops.is_button_pad = Event_Get_Button_Pad(info);
GestureInterpreterSetHardwareProperties(rec->interpreter, &hwprops);
GestureInterpreterSetPropProvider(rec->interpreter, &prop_provider, dev);
}
void
Gesture_Device_On(GesturePtr rec)
{
GestureInterpreterSetCallback(rec->interpreter,
&Gesture_Gesture_Ready,
rec->dev);
}
void
Gesture_Device_Off(GesturePtr rec)
{
GestureInterpreterSetCallback(rec->interpreter, NULL, NULL);
}
void
Gesture_Device_Close(GesturePtr rec)
{
GestureInterpreterSetPropProvider(rec->interpreter, NULL, NULL);
}
static unsigned
MT_XButtons_To_Gestures_Buttons(unsigned xbuttons)
{
unsigned ret = 0;
if (xbuttons & BUTTON_LEFT)
ret |= GESTURES_BUTTON_LEFT;
if (xbuttons & BUTTON_MIDDLE)
ret |= GESTURES_BUTTON_MIDDLE;
if (xbuttons & BUTTON_RIGHT)
ret |= GESTURES_BUTTON_RIGHT;
return ret;
}
void
Gesture_Process_Slots(GesturePtr rec,
EventStatePtr evstate,
struct timeval* tv)
{
int i;
MtSlotPtr slot;
struct FingerState fingers[evstate->slot_count];
struct HardwareState hwstate = {
StimeFromTimeval(tv),
MT_XButtons_To_Gestures_Buttons(evstate->buttons),
0,
fingers
};
int current_finger;
if (!rec->interpreter)
return;
current_finger = 0;
for (i = 0; i < evstate->slot_count; i++) {
slot = &evstate->slots[i];
if (slot->tracking_id == -1)
continue;
fingers[current_finger].touch_major = (float)slot->touch_major;
fingers[current_finger].touch_minor = (float)slot->touch_minor;
fingers[current_finger].width_major = (float)slot->width_major;
fingers[current_finger].width_minor = (float)slot->width_minor;
fingers[current_finger].pressure = (float)slot->pressure;
fingers[current_finger].orientation = (float)slot->orientation;
fingers[current_finger].position_x = (float)slot->position_x;
fingers[current_finger].position_y = (float)slot->position_y;
fingers[current_finger].tracking_id = slot->tracking_id;
current_finger++;
}
hwstate.finger_cnt = current_finger;
GestureInterpreterPushHardwareState(rec->interpreter, &hwstate);
}
static void Gesture_Gesture_Ready(void* client_data,
const struct Gesture* gesture)
{
/* TODO: These constants would be affected by X input driver
button remapping. */
const int kScrollBtnUp = 4;
const int kScrollBtnDown = 5;
const int kScrollBtnLeft = 6;
const int kScrollBtnRight = 7;
DeviceIntPtr dev = client_data;
InputInfoPtr info = dev->public.devicePrivate;
int hscroll, vscroll;
switch (gesture->type) {
case kGestureTypeContactInitiated:
/* TODO(adlr): handle contact initiated */
break;
case kGestureTypeMove:
DBG(info, "Gesture Move: (%d, %d)\n",
(int)gesture->details.move.dx, (int)gesture->details.move.dy);
xf86PostMotionEvent(dev, 0, 0, 2,
(int)gesture->details.move.dx, (int)gesture->details.move.dy);
break;
case kGestureTypeScroll:
hscroll = (int)gesture->details.scroll.dx;
vscroll = (int)gesture->details.scroll.dy;
DBG(info, "Gesture Scroll: (%d, %d)\n", hscroll, vscroll);
for (int type = 0; type < 2; type++) {
int button = 0;
int magnitude = 0;
if (type == 0) { /* hscroll */
magnitude = abs(hscroll);
button = hscroll < 0 ? kScrollBtnLeft : kScrollBtnRight;
} else { /* vscroll */
magnitude = abs(vscroll);
button = vscroll < 0 ? kScrollBtnUp : kScrollBtnDown;
}
for (int i = 0; i < magnitude; i++) {
xf86PostButtonEvent(dev, 0, button, 1, 0, 0);
xf86PostButtonEvent(dev, 0, button, 0, 0, 0);
}
}
break;
case kGestureTypeButtonsChange:
DBG(info, "Gesture Button Change: down=0x%02x up=0x%02x\n",
gesture->details.buttons.down, gesture->details.buttons.up);
if (gesture->details.buttons.down & GESTURES_BUTTON_LEFT)
xf86PostButtonEvent(dev, 0, 1, 1, 0, 0);
if (gesture->details.buttons.down & GESTURES_BUTTON_MIDDLE)
xf86PostButtonEvent(dev, 0, 2, 1, 0, 0);
if (gesture->details.buttons.down & GESTURES_BUTTON_RIGHT)
xf86PostButtonEvent(dev, 0, 3, 1, 0, 0);
if (gesture->details.buttons.up & GESTURES_BUTTON_LEFT)
xf86PostButtonEvent(dev, 0, 1, 0, 0, 0);
if (gesture->details.buttons.up & GESTURES_BUTTON_MIDDLE)
xf86PostButtonEvent(dev, 0, 2, 0, 0, 0);
if (gesture->details.buttons.up & GESTURES_BUTTON_RIGHT)
xf86PostButtonEvent(dev, 0, 3, 0, 0, 0);
break;
}
}
static GesturesTimer*
Gesture_TimerCreate(void* unused)
{
GesturesTimer* ret = (GesturesTimer*)calloc(1, sizeof(GesturesTimer));
if (!ret)
return NULL;
ret->timer = TimerSet(NULL, 0, 0, NULL, 0);
if (!ret->timer) {
free(ret);
return NULL;
}
return ret;
}
static void
Gesture_TimerSet(void* unused,
GesturesTimer* timer,
stime_t delay,
GesturesTimerCallback callback,
void* data)
{
CARD32 ms = delay * 1000.0;
if (!timer)
return;
timer->callback = callback;
timer->data = data;
if (ms == 0)
ms = 1;
TimerSet(timer->timer, 0, ms, Gesture_TimerCallback, timer);
}
static void
Gesture_TimerCancel(void* unused, GesturesTimer* timer)
{
TimerCancel(timer->timer);
}
static void
Gesture_TimerFree(void* unused, GesturesTimer* timer)
{
TimerFree(timer->timer);
timer->timer = NULL;
free(timer);
}
static CARD32
Gesture_TimerCallback(OsTimerPtr timer,
CARD32 millis,
pointer data)
{
int sigstate = xf86BlockSIGIO();
GesturesTimer* tm = (GesturesTimer*)data;
struct timeval tv;
stime_t now;
stime_t rc;
gettimeofday(&tv, NULL);
now = StimeFromTimeval(&tv);
rc = tm->callback(now, tm->data);
if (rc >= 0.0) {
CARD32 ms = rc * 1000.0;
if (ms == 0)
ms = 1;
TimerSet(timer, 0, ms, Gesture_TimerCallback, tm);
}
xf86UnblockSIGIO(sigstate);
return 0;
}