package: directfb
severity: normal

Please, apply the attached patch to directfb 0.9.25 sources: this patch allows DirectFB to handle devices which produce absolute x,y coordinates events (touchpads). This patch proved to work well on all test devices and was recently applied upstream too.

thanks

Attilio
--- linux_input.c.orig	2006-11-15 12:23:52.000000000 +0100
+++ linux_input.c	2006-11-21 23:26:36.000000000 +0100
@@ -59,6 +59,8 @@
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/kd.h>
+#include <stdlib.h>
+
 
 #include <linux/keyboard.h>
 
@@ -283,6 +285,35 @@
 };
 
 /*
+ * 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 +515,11 @@
 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 @@
                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 @@
      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))
      {
@@ -681,10 +715,15 @@
 
           for (i=0; i<readlen; i++) {
                DFBInputEvent devt;
-
+//printf("levt->type = %d, levt->code = %d, levt->value = %d\n", levt[i].type, levt[i].code, levt->value );
                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,7 +739,7 @@
                     }
                }
 
-               flush_xy( data );
+//               flush_xy( data );
 
                dfb_input_dispatch( data->device, &devt );
 
@@ -1082,3 +1121,104 @@
      /* 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;
+}

Reply via email to