#DPATCHLEVEL=0 --- inputdrivers/linux_input/linux_input.c 2006-04-07 19:44:16.000000000 +0300 +++ inputdrivers/linux_input/linux_input.c 2006-12-04 08:38:19.000000000 +0200 @@ -59,6 +59,7 @@ typedef unsigned long kernel_ulong_t; #include #include #include +#include #include @@ -283,6 +284,35 @@ int ext_keycodes [] = { }; /* + * Touchpads related stuff + */ +#define TOUCHPAD_SCALING_FACTOR 5 +#define TOUCHPAD_FSM_START 0 +#define TOUCHPAD_FSM_MAIN 1 +#define TOUCHPAD_FSM_END 2 + +/* expressed in usecs + */ +#define TOUCHPAD_SINGLE_CLICK_TIMEOUT 250000 + +/* lower touchpad pressure treshold for the mouse cursor to start moving + */ +#define TOUCHPAD_START_MOTION_PRESSURE_TRESHOLD 20 + +/* motion is reduced in a indirectly proportional way to finger pressure, + * this is the unit treshold + */ +#define TOUCHPAD_SCALING_FACTOR_PRESSURE 35 + +int x_old = -1, y_old = -1, dx, dy, last_pressure, fire_single_click_flag = 0; +struct timeval *last_mousetouch; +int touchpad_state = TOUCHPAD_FSM_START; + +static int +touchpad_fsm ( struct input_event *levt, + DFBInputEvent *devt ); + +/* * Translates a Linux input keycode into a DirectFB keycode. */ static int @@ -484,11 +514,12 @@ static int key_event( struct input_event *levt, DFBInputEvent *devt ) { - /* map touchscreen and smartpad events to button mouse */ - if (levt->code == BTN_TOUCH || levt->code == BTN_TOOL_FINGER) - levt->code = BTN_MOUSE; + /* don't map touchscreen and smartpad events to button mouse */ +// if (levt->code == BTN_TOUCH || levt->code == BTN_TOOL_FINGER) +// levt->code = BTN_MOUSE; - if (levt->code >= BTN_MOUSE && levt->code < BTN_JOYSTICK) { + if ( (levt->code >= BTN_MOUSE && levt->code < BTN_JOYSTICK) || + levt->code == BTN_TOUCH) { devt->type = levt->value ? DIET_BUTTONPRESS : DIET_BUTTONRELEASE; /* don't set DIEF_BUTTONS, it will be set by the input core */ devt->button = DIBI_FIRST + levt->code - BTN_MOUSE; @@ -579,8 +610,9 @@ abs_event( struct input_event *levt, break; default: - if (levt->code >= ABS_PRESSURE || levt->code > DIAI_LAST) - return 0; +// why this ? +// if (levt->code >= ABS_PRESSURE || levt->code > DIAI_LAST) +// return 0; devt->axis = levt->code; } @@ -669,6 +701,8 @@ linux_input_EventThread( DirectThread *t int readlen; struct input_event levt[64]; + last_mousetouch = malloc ( sizeof(struct timeval)); + while ((readlen = read(data->fd, levt, sizeof(levt)) / sizeof(levt[0])) > 0 || (readlen < 0 && errno == EINTR)) { @@ -685,6 +719,15 @@ linux_input_EventThread( DirectThread *t if (!translate_event( &levt[i], &devt )) continue; + if ( (devt.type == DIET_AXISMOTION + && (devt.flags & DIEF_AXISABS)) + || levt[i].code == BTN_TOUCH + || ( levt[i].type == EV_ABS && + levt[i].code == ABS_PRESSURE ) ) { + if (touchpad_fsm ( &levt[i], &devt ) == 0) + continue; + } + if (devt.type == DIET_AXISMOTION && (devt.flags & DIEF_AXISREL)) { switch (devt.axis) { case DIAI_X: @@ -700,8 +743,6 @@ linux_input_EventThread( DirectThread *t } } - flush_xy( data ); - dfb_input_dispatch( data->device, &devt ); if (data->has_leds && (devt.locks != data->locks)) { @@ -1082,3 +1123,104 @@ driver_close_device( void *driver_data ) /* free private data */ D_FREE( data ); } + +/* + * This FSM takes into accout finger landing on touchpad and leaving and + * translates absolute DFBInputEvent into a relative one + */ +static int +touchpad_fsm ( struct input_event *levt, + DFBInputEvent *devt ) +{ + int ret_val; + + if ( levt->type == EV_ABS && levt->code == ABS_PRESSURE ) { + last_pressure = levt->value; + return 0; + } + + switch (touchpad_state) { + + case TOUCHPAD_FSM_START: + /* finger is landing */ + if ((levt->type == EV_KEY && levt->code == BTN_TOUCH && levt->value == 1) || (last_pressure > TOUCHPAD_START_MOTION_PRESSURE_TRESHOLD)) { + last_mousetouch->tv_sec = (levt->time).tv_sec; + last_mousetouch->tv_usec = (levt->time).tv_usec; + if (last_pressure > TOUCHPAD_START_MOTION_PRESSURE_TRESHOLD) + touchpad_state = TOUCHPAD_FSM_MAIN; + } + ret_val = 0; + break; + + case TOUCHPAD_FSM_MAIN: + /* translating mouse movements into relative coordinates */ + if (levt->type == EV_ABS && (levt->code == ABS_X || levt->code == ABS_Y)) { + switch (devt->axis) { + case DIAI_X: + if (x_old == -1) + x_old = devt->axisabs; + dx = (devt->axisabs - x_old ) / TOUCHPAD_SCALING_FACTOR; + dx = dx * (last_pressure/ TOUCHPAD_SCALING_FACTOR_PRESSURE); + x_old = devt->axisabs; + devt->axisrel = dx; + devt->flags = devt->flags |= DIEF_AXISABS; + devt->flags = devt->flags |= DIEF_AXISREL; + ret_val = 1; + break; + case DIAI_Y: + if (y_old == -1) + y_old = devt->axisabs; + dy = (devt->axisabs - y_old ) / TOUCHPAD_SCALING_FACTOR; + dy = dy * (last_pressure/ TOUCHPAD_SCALING_FACTOR_PRESSURE); + y_old = devt->axisabs; + devt->axisrel = dy; + devt->flags = devt->flags |= DIEF_AXISABS; + devt->flags = devt->flags |= DIEF_AXISREL; + ret_val = 1; + break; + default: + ret_val = 0; + break; + } + } + + /* finger is leaving */ + else if (levt->type == EV_KEY && levt->code == BTN_TOUCH && levt->value == 0) { + if ( ((levt->time).tv_sec * 1000000 + (levt->time).tv_usec) -\ + (last_mousetouch->tv_sec * 1000000 + last_mousetouch->tv_usec)\ + <= TOUCHPAD_SINGLE_CLICK_TIMEOUT) { + devt->type = DIET_BUTTONPRESS; + devt->button = DIBI_FIRST; + fire_single_click_flag = 1; + ret_val = 1; + } + else + ret_val = 0; + + touchpad_state = TOUCHPAD_FSM_END; + } + else + ret_val = 0; + break; + + case TOUCHPAD_FSM_END: + x_old = y_old = last_pressure = -1; + touchpad_state = TOUCHPAD_FSM_START; + + if (fire_single_click_flag == 1) { + fire_single_click_flag = 0; + devt->type = DIET_BUTTONRELEASE; + devt->button = DIBI_FIRST; + ret_val = 1; + } + else + ret_val = 0; + break; + + default: + ret_val = 0; + break; + } + + return ret_val; +}