diff --git a/INSTALL b/INSTALL index c25ab32..4bd7942 100644 --- a/INSTALL +++ b/INSTALL @@ -34,7 +34,7 @@ Section "InputDevice" Option "TopEdge" "3900" Option "BottomEdge" "1800" Option "Finger" "25 30" - Option "MaxTapTime" "15" + Option "MaxTapTime" "180" Option "MaxTapMove" "220" Option "VertScrollDelta" "100" Option "MinSpeed" "0.02" diff --git a/PARAMETER b/PARAMETER index 3f4e33e..9e4c3e1 100644 --- a/PARAMETER +++ b/PARAMETER @@ -8,7 +8,7 @@ TopEdge Int coordinates for top edge BottomEdge Int coordinates for bottom edge FingerLow Int min. finger pressure after ending with movement FingerHigh Int max. finger pressure before beginning with movement -MaxTapTime Int max. time (time of 1/80s) for detecting a tap +MaxTapTime Int max. time (in milliseconds) for detecting a tap MaxTapMove Int max. movement of the finger for detecting a tap VertScrollDelta Int move-distance of the finger for a scroll event HorizScrollDelta Int move-distance of the finger for a scroll event @@ -20,4 +20,4 @@ AccelFactor Float acceleration-factor UpDownScrolling Bool If on, the up/down buttons generate button 4/5 events. If off, the up button generates a double click and the down button generates a button 2 event. -EmulateMidButtonTime Int max time (time of 1/80s) for middle button emulation. +EmulateMidButtonTime Int max time (in milliseconds) for middle button emulation. diff --git a/synaptics.c b/synaptics.c index 8a6c89a..f74015f 100644 --- a/synaptics.c +++ b/synaptics.c @@ -79,7 +79,8 @@ typedef enum { } edge_type; #define MAX(a, b) (((a)>(b))?(a):(b)) -#define DIFF_TIME(a, b) (((a)>(b))?(a)-(b):(b)-(a)) +#define MIN(a, b) (((a)<(b))?(a):(b)) +#define TIME_DIFF(a, b) ((long)((a)-(b))) #define VERSION "0.11.3p2" @@ -149,6 +150,7 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags) #endif char *str_par; int shmid; + unsigned long now; /* allocate memory for SynaticsPrivateRec */ priv = xcalloc (1, sizeof (SynapticsPrivateRec)); @@ -196,8 +198,14 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags) xf86ErrorFVerb( 6, "port opened successfully\n" ); /* initialize variables */ - priv->repeat_timer = NULL; + priv->timer = NULL; priv->repeatButtons = 0; + priv->nextRepeat = 0; + now = GetTimeInMillis(); + priv->finger_millis = now; + priv->tapping_millis = now; + priv->button_delay_millis = now; + priv->touch_on.millis = now; /* install shared memory or normal memory for parameter */ priv->shm_config = FALSE; @@ -498,31 +506,29 @@ edge_detection( SynapticsPrivatePtr priv, int x, int y ) } static CARD32 -updownTimer(OsTimerPtr timer, CARD32 now, pointer arg) +timerFunc(OsTimerPtr timer, CARD32 now, pointer arg) { LocalDevicePtr local = (LocalDevicePtr) (arg); SynapticsPrivatePtr priv = (SynapticsPrivatePtr) (local->private); - int sigstate, change, id; + struct SynapticsHwState hw; + int delay; + int sigstate; sigstate = xf86BlockSIGIO (); - change = priv->repeatButtons; - while(change) { - id = ffs(change); - change &= ~(1 << (id - 1)); - xf86PostButtonEvent(local->dev, FALSE, id, FALSE, 0, 0); - xf86PostButtonEvent(local->dev, FALSE, id, TRUE, 0, 0); - } + hw = priv->hwState; + hw.millis = GetTimeInMillis(); + delay = HandleState(local, &hw); xf86UnblockSIGIO (sigstate); - priv->repeat_timer = TimerSet(priv->repeat_timer, 0, 100, updownTimer, local); + priv->timer = TimerSet(priv->timer, 0, delay, timerFunc, local); return 0; } -#define MOVE_HIST(a) ((priv->count_packet_finger-(a))%SYNAPTICS_MOVE_HISTORY) +#define MOVE_HIST(a) (priv->move_hist[((priv->move_hist_idx-(a))%SYNAPTICS_MOVE_HISTORY)]) static int clamp(int val, int min, int max) { @@ -540,11 +546,35 @@ static int clamp(int val, int min, int max) */ static void ReadInput(LocalDevicePtr local) +{ + SynapticsPrivatePtr priv = (SynapticsPrivatePtr) (local->private); + struct SynapticsHwState hw; + int delay = 0; + Bool newDelay = FALSE; + + while(SynapticsGetHwState(local, priv, &hw) == Success) + { + hw.millis = GetTimeInMillis(); + delay = HandleState(local, &hw); + newDelay = TRUE; + } + + if (newDelay) + priv->timer = TimerSet(priv->timer, 0, delay, timerFunc, local); +} + +/* + * React on changes in the hardware state. This function is called every time + * the hardware state changes. The return value is used to specify how many + * milliseconds to wait before calling the function again if no state change + * occurs. + */ +static int +HandleState(LocalDevicePtr local, struct SynapticsHwState* hw) { SynapticsPrivatePtr priv = (SynapticsPrivatePtr) (local->private); SynapticsSHMPtr para = priv->synpara; Bool finger; - struct SynapticsHwState hw; int dist, dx, dy, buttons, id; edge_type edge; Bool mid; @@ -553,453 +583,481 @@ ReadInput(LocalDevicePtr local) int scroll_up, scroll_down, scroll_left, scroll_right; int double_click; Bool done; + int delay = 3600000; + long timeleft; - /* - * set blocking to -1 on the first call because we know there is data to - * read. Xisb automatically clears it after one successful read so that - * succeeding reads are preceeded by a select with a 0 timeout to prevent - * read from blocking indefinately. - */ - XisbBlockDuration(priv->buffer, -1); - while(SynapticsGetHwState(local, priv, &hw) == Success) - { - mid = FALSE; + mid = FALSE; - edge = edge_detection(priv, hw.x, hw.y); + edge = edge_detection(priv, hw->x, hw->y); - dx = dy = 0; + dx = dy = 0; - /* update finger position in shared memory */ - para->x = hw.x; - para->y = hw.y; - para->z = hw.z; - para->w = hw.w; - para->left = hw.left; - para->right = hw.right; - para->up = hw.up; - para->down = hw.down; + /* update finger position in shared memory */ + para->x = hw->x; + para->y = hw->y; + para->z = hw->z; + para->w = hw->w; + para->left = hw->left; + para->right = hw->right; + para->up = hw->up; + para->down = hw->down; - /* 3rd button emulation */ - done = FALSE; - while (!done) { - Bool timeout; - switch (priv->mid_emu_state) { - case MBE_OFF: - if (hw.left) { - priv->mid_emu_state = MBE_LEFT; - } else if (hw.right) { - priv->mid_emu_state = MBE_RIGHT; - } else { - priv->count_button_delay = priv->count_packet; - done = TRUE; - } - break; - case MBE_LEFT: - timeout = DIFF_TIME(priv->count_packet, priv->count_button_delay) >= - para->emulate_mid_button_time; - if (!hw.left || timeout) { - hw.left = TRUE; - priv->mid_emu_state = MBE_OFF; - done = TRUE; - } else if (hw.right) { - priv->mid_emu_state = MBE_MID; - } else { - hw.left = FALSE; - done = TRUE; - } - break; - case MBE_RIGHT: - timeout = DIFF_TIME(priv->count_packet, priv->count_button_delay) >= - para->emulate_mid_button_time; - if (!hw.right || timeout) { - hw.right = TRUE; - priv->mid_emu_state = MBE_OFF; - done = TRUE; - } else if (hw.left) { - priv->mid_emu_state = MBE_MID; - } else { - hw.right = FALSE; - done = TRUE; - } - break; - case MBE_MID: - if (!hw.left && !hw.right) { - priv->mid_emu_state = MBE_OFF; - } else { - mid = TRUE; - hw.left = hw.right = FALSE; - done = TRUE; - } - break; + /* 3rd button emulation */ + done = FALSE; + while (!done) { + switch (priv->mid_emu_state) { + case MBE_OFF: + priv->button_delay_millis = hw->millis; + if (hw->left) { + priv->mid_emu_state = MBE_LEFT; + } else if (hw->right) { + priv->mid_emu_state = MBE_RIGHT; + } else { + done = TRUE; + } + break; + case MBE_LEFT: + timeleft = TIME_DIFF(priv->button_delay_millis + para->emulate_mid_button_time, + hw->millis); + if (timeleft > 0) + delay = MIN(delay, timeleft); + if (!hw->left || (timeleft <= 0)) { + hw->left = TRUE; + priv->mid_emu_state = MBE_TIMEOUT; + done = TRUE; + } else if (hw->right) { + priv->mid_emu_state = MBE_MID; + } else { + hw->left = FALSE; + done = TRUE; + } + break; + case MBE_RIGHT: + timeleft = TIME_DIFF(priv->button_delay_millis + para->emulate_mid_button_time, + hw->millis); + if (timeleft > 0) + delay = MIN(delay, timeleft); + if (!hw->right || (timeleft <= 0)) { + hw->right = TRUE; + priv->mid_emu_state = MBE_TIMEOUT; + done = TRUE; + } else if (hw->left) { + priv->mid_emu_state = MBE_MID; + } else { + hw->right = FALSE; + done = TRUE; + } + break; + case MBE_MID: + if (!hw->left && !hw->right) { + priv->mid_emu_state = MBE_OFF; + } else { + mid = TRUE; + hw->left = hw->right = FALSE; + done = TRUE; + } + break; + case MBE_TIMEOUT: + if (!hw->left && !hw->right) { + priv->mid_emu_state = MBE_OFF; + } else { + done = TRUE; } } + } - /* Up/Down-button scrolling or middle/double-click */ - double_click = FALSE; - if (!para->updown_button_scrolling) + /* Up/Down-button scrolling or middle/double-click */ + double_click = FALSE; + if (!para->updown_button_scrolling) { - if (hw.down) - { /* map down-button to middle-button */ - mid = TRUE; - } + if (hw->down) + { /* map down-button to middle-button */ + mid = TRUE; + } - if (hw.up) - { /* up-button generates double-click */ - if (!priv->prev_up) - double_click = TRUE; - } - priv->prev_up = hw.up; + if (hw->up) + { /* up-button generates double-click */ + if (!priv->prev_up) + double_click = TRUE; + } + priv->prev_up = hw->up; /* reset up/down button events */ - hw.up = hw.down = FALSE; + hw->up = hw->down = FALSE; } - /* finger detection thru pressure an threshold */ - finger = (((hw.z > para->finger_high) && !priv->finger_flag) || - ((hw.z > para->finger_low) && priv->finger_flag)); + /* finger detection thru pressure an threshold */ + finger = (((hw->z > para->finger_high) && !priv->finger_flag) || + ((hw->z > para->finger_low) && priv->finger_flag)); - /* palm detection */ - if(finger) { - if((hw.z > 200) && (hw.w > 10)) - priv->palm = TRUE; - } else { - priv->palm = FALSE; - } - if(hw.x == 0) - priv->avg_w = 0; - else - priv->avg_w += (hw.w - priv->avg_w + 1) / 2; - if(finger && !priv->finger_flag) { - int safe_w = MAX(hw.w, priv->avg_w); - if(hw.w < 2) - finger = TRUE; /* more than one finger -> not a palm */ - else if((safe_w < 6) && (priv->prev_z < para->finger_high)) - finger = TRUE; /* thin finger, distinct touch -> not a palm */ - else if((safe_w < 7) && (priv->prev_z < para->finger_high / 2)) - finger = TRUE; /* thin finger, distinct touch -> not a palm */ - else if(hw.z > priv->prev_z + 1) /* z not stable, may be a palm */ - finger = FALSE; - else if(hw.z < priv->prev_z - 5) /* z not stable, may be a palm */ - finger = FALSE; - else if(hw.z > 200) /* z too large -> probably palm */ - finger = FALSE; - else if(hw.w > 10) /* w too large -> probably palm */ - finger = FALSE; - } - priv->prev_z = hw.z; + /* palm detection */ + if(finger) { + if((hw->z > 200) && (hw->w > 10)) + priv->palm = TRUE; + } else { + priv->palm = FALSE; + } + if(hw->x == 0) + priv->avg_w = 0; + else + priv->avg_w += (hw->w - priv->avg_w + 1) / 2; + if(finger && !priv->finger_flag) { + int safe_w = MAX(hw->w, priv->avg_w); + if(hw->w < 2) + finger = TRUE; /* more than one finger -> not a palm */ + else if((safe_w < 6) && (priv->prev_z < para->finger_high)) + finger = TRUE; /* thin finger, distinct touch -> not a palm */ + else if((safe_w < 7) && (priv->prev_z < para->finger_high / 2)) + finger = TRUE; /* thin finger, distinct touch -> not a palm */ + else if(hw->z > priv->prev_z + 1) /* z not stable, may be a palm */ + finger = FALSE; + else if(hw->z < priv->prev_z - 5) /* z not stable, may be a palm */ + finger = FALSE; + else if(hw->z > 200) /* z too large -> probably palm */ + finger = FALSE; + else if(hw->w > 10) /* w too large -> probably palm */ + finger = FALSE; + } + priv->prev_z = hw->z; - /* tap and drag detection */ - if(priv->palm) { - /* Palm detected, skip tap/drag processing */ - } else if(finger && !priv->finger_flag) + /* tap and drag detection */ + if(priv->palm) { + /* Palm detected, skip tap/drag processing */ + } else if(finger && !priv->finger_flag) { /* touched */ - DBG(7, ErrorF("touched - x:%d, y:%d packet:%lu\n", hw.x, hw.y, priv->count_packet)); + DBG(7, ErrorF("touched - x:%d, y:%d millis:%lu\n", hw->x, hw->y, hw->millis)); if(priv->tap) - { - DBG(7, ErrorF("drag detected - tap time:%lu\n", priv->count_packet_tapping)); - priv->drag = TRUE; /* drag gesture */ - } - priv->touch_on.x = hw.x; - priv->touch_on.y = hw.y; - priv->touch_on.packet = priv->count_packet; + { + DBG(7, ErrorF("drag detected - tap time:%lu\n", priv->tapping_millis)); + priv->drag = TRUE; /* drag gesture */ + } + priv->touch_on.x = hw->x; + priv->touch_on.y = hw->y; + priv->touch_on.millis = hw->millis; } - else if(!finger && priv->finger_flag) + else if(!finger && priv->finger_flag) { /* untouched */ - DBG(7, ErrorF("untouched - x:%d, y:%d packet:%lu finger:%d\n", - hw.x, hw.y, priv->count_packet, priv->finger_count)); + DBG(7, ErrorF("untouched - x:%d, y:%d millis:%lu finger:%d\n", + hw->x, hw->y, hw->millis, priv->finger_count)); /* check if 1. the tap is in tap_time 2. the max movement is in tap_move or more than one finger are tapped */ - if((DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) && - (((abs(hw.x - priv->touch_on.x) < para->tap_move) && - (abs(hw.y - priv->touch_on.y) < para->tap_move)) || - priv->finger_count)) - { + if((TIME_DIFF(hw->millis, priv->touch_on.millis + para->tap_time) < 0) && + (((abs(hw->x - priv->touch_on.x) < para->tap_move) && + (abs(hw->y - priv->touch_on.y) < para->tap_move)) || + priv->finger_count)) + { if(priv->drag) - { - DBG(7, ErrorF("double tapping detected\n")); - priv->doubletap = TRUE; - priv->tap = FALSE; - } - else - { - DBG(7, ErrorF("tapping detected @ ")); - priv->count_packet_tapping = priv->count_packet; - priv->tap = TRUE; - if(priv->finger_count == 0) { - switch(edge) - { - case RIGHT_TOP_EDGE: - DBG(7, ErrorF("right top edge\n")); - priv->tap_mid = TRUE; - break; - case RIGHT_BOTTOM_EDGE: - DBG(7, ErrorF("right bottom edge\n")); - priv->tap_right = TRUE; - break; - case LEFT_TOP_EDGE: - DBG(7, ErrorF("left top edge\n")); - break; - case LEFT_BOTTOM_EDGE: - DBG(7, ErrorF("left bottom edge\n")); - break; - default: - DBG(7, ErrorF("no edge\n")); - priv->tap_left = TRUE; - } + DBG(7, ErrorF("double tapping detected\n")); + priv->doubletap = TRUE; + priv->tap = FALSE; } - else + else { - switch(priv->finger_count) - { - case 2: - DBG(7, ErrorF("two finger tap\n")); - priv->tap_mid = TRUE; - break; - case 3: - DBG(7, ErrorF("three finger tap\n")); - priv->tap_right = TRUE; - break; - default: - DBG(7, ErrorF("one finger\n")); - priv->tap_left = TRUE; - } + DBG(7, ErrorF("tapping detected @ ")); + priv->tapping_millis = hw->millis; + priv->tap = TRUE; + if(priv->finger_count == 0) + { + switch(edge) + { + case RIGHT_TOP_EDGE: + DBG(7, ErrorF("right top edge\n")); + priv->tap_mid = TRUE; + break; + case RIGHT_BOTTOM_EDGE: + DBG(7, ErrorF("right bottom edge\n")); + priv->tap_right = TRUE; + break; + case LEFT_TOP_EDGE: + DBG(7, ErrorF("left top edge\n")); + break; + case LEFT_BOTTOM_EDGE: + DBG(7, ErrorF("left bottom edge\n")); + break; + default: + DBG(7, ErrorF("no edge\n")); + priv->tap_left = TRUE; + } + } + else + { + switch(priv->finger_count) + { + case 2: + DBG(7, ErrorF("two finger tap\n")); + priv->tap_mid = TRUE; + break; + case 3: + DBG(7, ErrorF("three finger tap\n")); + priv->tap_right = TRUE; + break; + default: + DBG(7, ErrorF("one finger\n")); + priv->tap_left = TRUE; + } + } } - } - } /* tap detection */ + } /* tap detection */ priv->drag = FALSE; } /* finger lost */ - /* detecting 2 and 3 fingers */ - if(finger && /* finger is on the surface */ - (DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time)) /* tap time is not succeeded */ + /* detecting 2 and 3 fingers */ + timeleft = TIME_DIFF(priv->touch_on.millis + para->tap_time, hw->millis); + if (timeleft > 0) + delay = MIN(delay, timeleft); + if(finger && /* finger is on the surface */ + (timeleft > 0)) /* tap time is not succeeded */ { /* count fingers when reported */ - if((hw.w == 0) && (priv->finger_count == 0)) + if((hw->w == 0) && (priv->finger_count == 0)) priv->finger_count = 2; - if(hw.w == 1) + if(hw->w == 1) priv->finger_count = 3; } - else + else { /* reset finger counts */ priv->finger_count = 0; } - /* reset tapping button flags */ - if(!priv->tap && !priv->drag && !priv->doubletap) + /* reset tapping button flags */ + if(!priv->tap && !priv->drag && !priv->doubletap) { priv->tap_left = priv->tap_mid = priv->tap_right = FALSE; } - /* tap processing */ - if(priv->tap && - (DIFF_TIME(priv->count_packet, priv->count_packet_tapping) < para->tap_time)) + /* tap processing */ + timeleft = TIME_DIFF(priv->tapping_millis + para->tap_time, hw->millis); + if (timeleft > 0) + delay = MIN(delay, timeleft); + if (priv->tap && (timeleft > 0)) { - hw.left |= priv->tap_left; - mid |= priv->tap_mid; - hw.right |= priv->tap_right; + hw->left |= priv->tap_left; + mid |= priv->tap_mid; + hw->right |= priv->tap_right; } - else + else { priv->tap = FALSE; } - /* drag processing */ - if(priv->drag) + /* drag processing */ + if(priv->drag) { - hw.left |= priv->tap_left; - mid |= priv->tap_mid; - hw.right |= priv->tap_right; + hw->left |= priv->tap_left; + mid |= priv->tap_mid; + hw->right |= priv->tap_right; } - /* double tap processing */ - if(priv->doubletap && !priv->finger_flag) + /* double tap processing */ + if(priv->doubletap && !priv->finger_flag) { - hw.left |= priv->tap_left; - mid |= priv->tap_mid; - hw.right |= priv->tap_right; + hw->left |= priv->tap_left; + mid |= priv->tap_mid; + hw->right |= priv->tap_right; priv->doubletap = FALSE; } - /* scroll detection */ - if(finger && !priv->finger_flag) + /* scroll detection */ + if(finger && !priv->finger_flag) { if(edge & RIGHT_EDGE) - { - priv->vert_scroll_on = TRUE; - priv->scroll_y = hw.y; - DBG(7, ErrorF("vert edge scroll detected on right edge\n")); - } + { + priv->vert_scroll_on = TRUE; + priv->scroll_y = hw->y; + DBG(7, ErrorF("vert edge scroll detected on right edge\n")); + } if(edge & BOTTOM_EDGE) { priv->horiz_scroll_on = TRUE; - priv->scroll_x = hw.x; + priv->scroll_x = hw->x; DBG(7, ErrorF("horiz edge scroll detected on bottom edge\n")); } } - if(priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger || priv->palm)) + if(priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger || priv->palm)) { DBG(7, ErrorF("vert edge scroll off\n")); priv->vert_scroll_on = FALSE; } - if(priv->horiz_scroll_on && (!(edge & BOTTOM_EDGE) || !finger || priv->palm)) + if(priv->horiz_scroll_on && (!(edge & BOTTOM_EDGE) || !finger || priv->palm)) { DBG(7, ErrorF("horiz edge scroll off\n")); priv->horiz_scroll_on = FALSE; } - /* scroll processing */ - scroll_up = 0; - scroll_down = 0; - if(priv->vert_scroll_on) + /* scroll processing */ + scroll_up = 0; + scroll_down = 0; + if(priv->vert_scroll_on) { /* + = up, - = down */ - while(hw.y - priv->scroll_y > para->scroll_dist_vert) { + while(hw->y - priv->scroll_y > para->scroll_dist_vert) { scroll_up++; priv->scroll_y += para->scroll_dist_vert; } - while(hw.y - priv->scroll_y < -para->scroll_dist_vert) { + while(hw->y - priv->scroll_y < -para->scroll_dist_vert) { scroll_down++; priv->scroll_y -= para->scroll_dist_vert; } } - scroll_left = 0; - scroll_right = 0; - if(priv->horiz_scroll_on) { - /* + = right, - = left */ - while(hw.x - priv->scroll_x > para->scroll_dist_horiz) { - scroll_right++; - priv->scroll_x += para->scroll_dist_horiz; - } - while(hw.x - priv->scroll_x < -para->scroll_dist_horiz) { - scroll_left++; - priv->scroll_x -= para->scroll_dist_horiz; - } - } + scroll_left = 0; + scroll_right = 0; + if(priv->horiz_scroll_on) { + /* + = right, - = left */ + while(hw->x - priv->scroll_x > para->scroll_dist_horiz) { + scroll_right++; + priv->scroll_x += para->scroll_dist_horiz; + } + while(hw->x - priv->scroll_x < -para->scroll_dist_horiz) { + scroll_left++; + priv->scroll_x -= para->scroll_dist_horiz; + } + } - /* movement */ - if(finger && !priv->vert_scroll_on && !priv->horiz_scroll_on && - !priv->finger_count && !priv->palm) + /* movement */ + if(finger && !priv->vert_scroll_on && !priv->horiz_scroll_on && + !priv->finger_count && !priv->palm) + { + timeleft = TIME_DIFF(priv->finger_millis + 50, hw->millis); + if (timeleft > 0) + delay = MIN(delay, timeleft); + if (timeleft <= 0) { - if(priv->count_packet_finger > 3) - { /* min. 3 packets */ - dy = (1 * - (((priv->move_hist[MOVE_HIST(1)].y + priv->move_hist[MOVE_HIST(2)].y) / 2) - - ((hw.y + priv->move_hist[MOVE_HIST(1)].y) / 2))); - dx = (-1 * - (((priv->move_hist[MOVE_HIST(1)].x + priv->move_hist[MOVE_HIST(2)].x) / 2) - - ((hw.x + priv->move_hist[MOVE_HIST(1)].x) / 2))); + delay = MIN(delay, 13); - if (priv->drag) { - if (edge & RIGHT_EDGE) { - dx += clamp(para->edge_motion_speed - dx, 0, para->edge_motion_speed); - } else if (edge & LEFT_EDGE) { - dx -= clamp(para->edge_motion_speed + dx, 0, para->edge_motion_speed); - } - if (edge & TOP_EDGE) { - dy -= clamp(para->edge_motion_speed + dy, 0, para->edge_motion_speed); - } else if (edge & BOTTOM_EDGE) { - dy += clamp(para->edge_motion_speed - dy, 0, para->edge_motion_speed); - } - } - - /* speed in depence of distance/packet */ - dist = move_distance( dx, dy ); - speed = dist * para->accl; - if(speed > para->max_speed) - { /* set max speed factor */ - speed = para->max_speed; - } - else if(speed < para->min_speed) - { /* set min speed factor */ - speed = para->min_speed; - } + dy = (1 * + (((MOVE_HIST(1).y + MOVE_HIST(2).y) / 2) - + ((hw->y + MOVE_HIST(1).y) / 2))); + dx = (-1 * + (((MOVE_HIST(1).x + MOVE_HIST(2).x) / 2) - + ((hw->x + MOVE_HIST(1).x) / 2))); - /* save the fraction for adding to the next priv->count_packet */ - priv->frac_x = xf86modf((dx * speed) + priv->frac_x, &integral); - dx = integral; - priv->frac_y = xf86modf((dy * speed) + priv->frac_y, &integral); - dy = integral; + if (priv->drag) { + if (edge & RIGHT_EDGE) { + dx += clamp(para->edge_motion_speed - dx, 0, para->edge_motion_speed); + } else if (edge & LEFT_EDGE) { + dx -= clamp(para->edge_motion_speed + dx, 0, para->edge_motion_speed); + } + if (edge & TOP_EDGE) { + dy -= clamp(para->edge_motion_speed + dy, 0, para->edge_motion_speed); + } else if (edge & BOTTOM_EDGE) { + dy += clamp(para->edge_motion_speed - dy, 0, para->edge_motion_speed); + } } - priv->count_packet_finger++; - } - else - { /* reset packet counter */ - priv->count_packet_finger = 0; - } - - - buttons = ((hw.left ? 0x01 : 0) | - (mid ? 0x02 : 0) | - (hw.right ? 0x04 : 0) | - (hw.up ? 0x08 : 0) | - (hw.down ? 0x10 : 0)); - - priv->count_packet++; - - /* Flags */ - priv->finger_flag = finger; - - /* generate a history of the absolute positions */ - priv->move_hist[MOVE_HIST(0)].y = hw.y; - priv->move_hist[MOVE_HIST(0)].x = hw.x; - - /* repeat timer for up/down buttons */ - /* when you press a button the packets will only send for a second, so - we have to use a timer for repeating */ - if((hw.up || hw.down) && para->updown_button_scrolling) - { - if(!priv->repeat_timer) - { - priv->repeatButtons = buttons & 0x18; - priv->repeat_timer = TimerSet(priv->repeat_timer, - 0, 200, updownTimer, local); + /* speed in depence of distance/packet */ + dist = move_distance( dx, dy ); + speed = dist * para->accl; + if(speed > para->max_speed) + { /* set max speed factor */ + speed = para->max_speed; + } + else if(speed < para->min_speed) + { /* set min speed factor */ + speed = para->min_speed; } - } - else if(priv->repeat_timer) - { - TimerFree(priv->repeat_timer); - priv->repeat_timer = NULL; - priv->repeatButtons = 0; - } - /* Post events */ - if(dx || dy) - xf86PostMotionEvent(local->dev, 0, 0, 2, dx, dy); + /* save the fraction for adding to the next priv->count_packet */ + priv->frac_x = xf86modf((dx * speed) + priv->frac_x, &integral); + dx = integral; + priv->frac_y = xf86modf((dy * speed) + priv->frac_y, &integral); + dy = integral; + } + } + else + { + priv->finger_millis = hw->millis; + } + + + buttons = ((hw->left ? 0x01 : 0) | + (mid ? 0x02 : 0) | + (hw->right ? 0x04 : 0) | + (hw->up ? 0x08 : 0) | + (hw->down ? 0x10 : 0)); + + /* Flags */ + priv->finger_flag = finger; + + /* generate a history of the absolute positions */ + if (1) { + priv->move_hist_idx++; + MOVE_HIST(0).y = hw->y; + MOVE_HIST(0).x = hw->x; + } + + /* Post events */ + if(dx || dy) + xf86PostMotionEvent(local->dev, 0, 0, 2, dx, dy); - change = buttons ^ priv->lastButtons; - while(change) + change = buttons ^ priv->lastButtons; + while(change) { id = ffs(change); change &= ~(1 << (id - 1)); xf86PostButtonEvent(local->dev, FALSE, id, (buttons & (1 << (id - 1))), 0, 0); } - priv->lastButtons = buttons; + priv->lastButtons = buttons; - while(scroll_up-- > 0) { - xf86PostButtonEvent(local->dev, FALSE, 4, !hw.up, 0, 0); - xf86PostButtonEvent(local->dev, FALSE, 4, hw.up, 0, 0); - } - while(scroll_down-- > 0) { - xf86PostButtonEvent(local->dev, FALSE, 5, !hw.down, 0, 0); - xf86PostButtonEvent(local->dev, FALSE, 5, hw.down, 0, 0); - } - while(scroll_left-- > 0) { - xf86PostButtonEvent(local->dev, FALSE, 6, TRUE, 0, 0); - xf86PostButtonEvent(local->dev, FALSE, 6, FALSE, 0, 0); - } - while(scroll_right-- > 0) { - xf86PostButtonEvent(local->dev, FALSE, 7, TRUE, 0, 0); - xf86PostButtonEvent(local->dev, FALSE, 7, FALSE, 0, 0); - } - if (double_click) { - int i; - for (i = 0; i < 2; i++) { - xf86PostButtonEvent(local->dev, FALSE, 1, !hw.left, 0, 0); - xf86PostButtonEvent(local->dev, FALSE, 1, hw.left, 0, 0); - } + while(scroll_up-- > 0) { + xf86PostButtonEvent(local->dev, FALSE, 4, !hw->up, 0, 0); + xf86PostButtonEvent(local->dev, FALSE, 4, hw->up, 0, 0); + } + while(scroll_down-- > 0) { + xf86PostButtonEvent(local->dev, FALSE, 5, !hw->down, 0, 0); + xf86PostButtonEvent(local->dev, FALSE, 5, hw->down, 0, 0); + } + while(scroll_left-- > 0) { + xf86PostButtonEvent(local->dev, FALSE, 6, TRUE, 0, 0); + xf86PostButtonEvent(local->dev, FALSE, 6, FALSE, 0, 0); + } + while(scroll_right-- > 0) { + xf86PostButtonEvent(local->dev, FALSE, 7, TRUE, 0, 0); + xf86PostButtonEvent(local->dev, FALSE, 7, FALSE, 0, 0); + } + if (double_click) { + int i; + for (i = 0; i < 2; i++) { + xf86PostButtonEvent(local->dev, FALSE, 1, !hw->left, 0, 0); + xf86PostButtonEvent(local->dev, FALSE, 1, hw->left, 0, 0); } } + + + /* + * Handle auto repeat buttons + */ + if ((hw->up || hw->down) && para->updown_button_scrolling) { + priv->repeatButtons = buttons & 0x18; + if (!priv->nextRepeat) { + priv->nextRepeat = hw->millis + 200; + } + } else { + priv->repeatButtons = 0; + priv->nextRepeat = 0; + } + + if (priv->repeatButtons) + { + timeleft = TIME_DIFF(priv->nextRepeat, hw->millis); + if (timeleft > 0) + delay = MIN(delay, timeleft); + if (timeleft <= 0) + { + int change, id; + change = priv->repeatButtons; + while(change) { + id = ffs(change); + change &= ~(1 << (id - 1)); + xf86PostButtonEvent(local->dev, FALSE, id, FALSE, 0, 0); + xf86PostButtonEvent(local->dev, FALSE, id, TRUE, 0, 0); + } + + priv->nextRepeat = hw->millis + 100; + delay = MIN(delay, 100); + } + } + + return delay; } static int @@ -1270,6 +1328,8 @@ SynapticsParseRawPacket(LocalDevicePtr local, SynapticsPrivatePtr priv, hw->w = 5; } + priv->hwState = *hw; + return Success; } diff --git a/synaptics.h b/synaptics.h index 3ae06e3..2d669b1 100644 --- a/synaptics.h +++ b/synaptics.h @@ -24,7 +24,8 @@ typedef struct _SynapticsSHM int left_edge, right_edge, top_edge, bottom_edge; /* edge coordinates absolute */ int finger_low, finger_high; /* finger detection values in Z-values */ - int tap_time, tap_move; /* max. tapping-time and movement in packets and coord. */ + unsigned long tap_time; + int tap_move; /* max. tapping-time and movement in packets and coord. */ int emulate_mid_button_time; /* Max time between left and right button presses to emulate a middle button press. */ int scroll_dist_vert; /* Scrolling distance in absolute coordinates */ @@ -46,10 +47,11 @@ typedef struct _SynapticsSHM * A structure to describe the state of the touchpad hardware (buttons and pad) */ struct SynapticsHwState { - int x; - int y; - int z; - int w; + int millis; /* Timestamp in milliseconds */ + int x; /* X position of finger */ + int y; /* Y position of finger */ + int z; /* Finger pressure */ + int w; /* Finger width/finger count */ Bool left; Bool right; Bool up; @@ -73,7 +75,7 @@ struct input_event { typedef struct _SynapticsTapRec { int x, y; - unsigned int packet; + unsigned int millis; } SynapticsTapRec; typedef struct _SynapticsMoveHist @@ -85,8 +87,9 @@ enum MidButtonEmulation { MBE_OFF, /* No button pressed */ MBE_LEFT, /* Left button pressed, waiting for right button or timeout */ MBE_RIGHT, /* Right button pressed, waiting for left button or timeout */ - MBE_MID /* Left and right buttons pressed, waiting for both buttons + MBE_MID, /* Left and right buttons pressed, waiting for both buttons to be released */ + MBE_TIMEOUT /* Waiting for both buttons to be released. */ }; enum SynapticsProtocol { @@ -112,6 +115,8 @@ typedef struct _SynapticsPrivateRec Bool shm_config; /* True when shared memory area allocated */ + OsTimerPtr timer; /* for up/down-button repeat, tap processing, etc */ + /* Data for normal processing */ XISBuffer *buffer; unsigned char protoBuf[6]; /* Buffer for Packet */ @@ -120,14 +125,14 @@ typedef struct _SynapticsPrivateRec int protoBufTail; int fifofd; /* fd for fifo */ SynapticsTapRec touch_on; /* data when the touchpad is touched */ - SynapticsMoveHistRec move_hist[SYNAPTICS_MOVE_HISTORY]; - /* movement history */ + SynapticsMoveHistRec move_hist[SYNAPTICS_MOVE_HISTORY]; /* movement history */ + int move_hist_idx; /* Most recent entry in move_hist[] */ + int scroll_y; /* last y-scroll position */ int scroll_x; /* last x-scroll position */ - unsigned int count_packet_finger; /* packet counter with finger on the touchpad */ - unsigned int count_packet; /* packet counter */ - unsigned int count_packet_tapping; /* packet counter for tapping */ - unsigned int count_button_delay; /* button delay for 3rd button emulation */ + unsigned long finger_millis; /* Time when finger entered touchpad */ + unsigned int tapping_millis; /* packet counter for tapping */ + unsigned int button_delay_millis; /* button delay for 3rd button emulation */ unsigned int prev_up; /* Previous up button value, for double click emulation */ Bool finger_flag; /* previous finger */ Bool tap, drag, doubletap; /* feature flags */ @@ -136,8 +141,8 @@ typedef struct _SynapticsPrivateRec Bool horiz_scroll_on; /* scrolling flag */ double frac_x, frac_y; /* absoulte -> relative fraction */ enum MidButtonEmulation mid_emu_state; /* emulated 3rd button */ - OsTimerPtr repeat_timer; /* for up/down-button repeat */ int repeatButtons; /* buttons for repeat */ + unsigned long nextRepeat; /* Time when to trigger next auto repeat event */ int lastButtons; /* last State of the buttons */ int finger_count; /* tap counter for fingers */ int palm; /* Set to true when palm detected, reset to false when @@ -150,6 +155,7 @@ SynapticsPrivateRec, *SynapticsPrivatePtr; static Bool DeviceControl(DeviceIntPtr, int); static void ReadInput(LocalDevicePtr); +static int HandleState(LocalDevicePtr, struct SynapticsHwState*); static int ControlProc(LocalDevicePtr, xDeviceCtl*); static void CloseProc(LocalDevicePtr); static int SwitchMode(ClientPtr, DeviceIntPtr, int); @@ -159,13 +165,12 @@ static Bool DeviceInit(DeviceIntPtr); static Bool DeviceOn(DeviceIntPtr); static Bool DeviceOff(DeviceIntPtr); static Bool DeviceInit(DeviceIntPtr); -static Bool SynapticsGetHwState(LocalDevicePtr local, SynapticsPrivatePtr priv, - struct SynapticsHwState *hw); -static Bool SynapticsParseEventData(LocalDevicePtr local, SynapticsPrivatePtr priv, - struct SynapticsHwState *hw); -static Bool SynapticsReadEvent(SynapticsPrivatePtr priv, struct input_event *ev); -static Bool SynapticsParseRawPacket(LocalDevicePtr local, SynapticsPrivatePtr priv, - struct SynapticsHwState *hw); +static Bool SynapticsGetHwState(LocalDevicePtr, SynapticsPrivatePtr, struct SynapticsHwState*); +static Bool SynapticsParseEventData(LocalDevicePtr, SynapticsPrivatePtr, + struct SynapticsHwState*); +static Bool SynapticsReadEvent(SynapticsPrivatePtr, struct input_event*); +static Bool SynapticsParseRawPacket(LocalDevicePtr, SynapticsPrivatePtr, + struct SynapticsHwState*); static Bool SynapticsGetPacket(LocalDevicePtr, SynapticsPrivatePtr); static void PrintIdent(SynapticsPrivatePtr); diff --git a/synclient.c b/synclient.c index 98c15a0..8e7edf9 100644 --- a/synclient.c +++ b/synclient.c @@ -49,9 +49,9 @@ static struct Parameter params[] = { DEFINE_PAR("BottomEdge", bottom_edge, PT_INT, 0, 10000), DEFINE_PAR("FingerLow", finger_low, PT_INT, 0, 255), DEFINE_PAR("FingerHigh", finger_high, PT_INT, 0, 255), - DEFINE_PAR("MaxTapTime", tap_time, PT_INT, 0, 75), + DEFINE_PAR("MaxTapTime", tap_time, PT_INT, 0, 1000), DEFINE_PAR("MaxTapMove", tap_move, PT_INT, 0, 2000), - DEFINE_PAR("EmulateMidButtonTime", emulate_mid_button_time, PT_INT, 0, 75), + DEFINE_PAR("EmulateMidButtonTime", emulate_mid_button_time, PT_INT, 0, 1000), DEFINE_PAR("VertScrollDelta", scroll_dist_vert, PT_INT, 5, 1000), DEFINE_PAR("HorizScrollDelta", scroll_dist_horiz, PT_INT, 5, 1000), DEFINE_PAR("MinSpeed", min_speed, PT_DOUBLE, 0, 1.0),