summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README1
-rw-r--r--synaptics.c202
-rw-r--r--synaptics.h22
-rw-r--r--synclient.c3
4 files changed, 149 insertions, 79 deletions
diff --git a/README b/README
index b17ce51..d45133a 100644
--- a/README
+++ b/README
@@ -28,6 +28,7 @@ advanced features of the touchpad becomes available, such as:
for right button events. (Needs hardware support. Not all models
implement this feature.)
- Pressure dependent motion speed.
+- Trackstick emulation.
- Run-time configuration using shared memory. This means you can
change parameter settings without restarting the X server.
diff --git a/synaptics.c b/synaptics.c
index e85908e..114b022 100644
--- a/synaptics.c
+++ b/synaptics.c
@@ -1,4 +1,7 @@
/*
+ * Copyright 2006 Christian Thaeter <chth@gmx.net>
+ * patch for Trackstick mode
+ *
* Copyright 2006 Stefan Bethge <stefan.bethge@web.de>
* patch for two-fingered scrolling
*
@@ -373,6 +376,7 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
pars->bottom_edge = xf86SetIntOption(opts, "BottomEdge", 4000);
pars->finger_low = xf86SetIntOption(opts, "FingerLow", 25);
pars->finger_high = xf86SetIntOption(opts, "FingerHigh", 30);
+ pars->finger_press = xf86SetIntOption(opts, "FingerPress", 256);
pars->tap_time = xf86SetIntOption(opts, "MaxTapTime", 180);
pars->tap_move = xf86SetIntOption(opts, "MaxTapMove", 220);
pars->tap_time_2 = xf86SetIntOption(opts, "MaxDoubleTapTime", 180);
@@ -421,6 +425,8 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
pars->min_speed = synSetFloatOption(opts, "MinSpeed", 0.09);
pars->max_speed = synSetFloatOption(opts, "MaxSpeed", 0.18);
pars->accl = synSetFloatOption(opts, "AccelFactor", 0.0015);
+ pars->trackstick_accl = synSetFloatOption(opts, "TrackstickAccelFactor", 0.5);
+ pars->trackstick_exp_accl = synSetFloatOption(opts, "TrackstickAccelExp", 1.1);
pars->scroll_dist_circ = synSetFloatOption(opts, "CircScrollDelta", 0.1);
pars->coasting_speed = synSetFloatOption(opts, "CoastingSpeed", 0.0);
pars->press_motion_min_factor = synSetFloatOption(opts, "PressureMotionMinFactor", 1.0);
@@ -910,8 +916,10 @@ SynapticsDetectFinger(SynapticsPrivate *priv, struct SynapticsHwState *hw)
int finger;
/* finger detection thru pressure and threshold */
- finger = (((hw->z > para->finger_high) && !priv->finger_flag) ||
- ((hw->z > para->finger_low) && priv->finger_flag));
+ finger = ((hw->z > para->finger_press) && priv->finger_state < FS_PRESSED) ? FS_PRESSED
+ : ((hw->z > para->finger_high) && priv->finger_state < FS_TOUCHED) ? FS_TOUCHED
+ : ((hw->z < para->finger_low) && priv->finger_state > FS_UNTOUCHED) ? FS_UNTOUCHED
+ : priv->finger_state;
if (!para->palm_detect)
return finger;
@@ -927,7 +935,7 @@ SynapticsDetectFinger(SynapticsPrivate *priv, struct SynapticsHwState *hw)
priv->avg_width = 0;
else
priv->avg_width += (hw->fingerWidth - priv->avg_width + 1) / 2;
- if (finger && !priv->finger_flag) {
+ if (finger && !priv->finger_state) {
int safe_width = MAX(hw->fingerWidth, priv->avg_width);
if (hw->numFingers > 1)
finger = TRUE; /* more than one finger -> not a palm */
@@ -1040,6 +1048,20 @@ SetTapState(SynapticsPrivate *priv, enum TapState tap_state, int millis)
priv->tap_state = tap_state;
}
+static void
+SetMovingState(SynapticsPrivate *priv, enum MovingState moving_state, int millis)
+{
+ /* SynapticsSHM *para = priv->synpara; */
+ DBG(7, ErrorF("SetMovingState - %d -> %d center at %d/%d (millis:%d)\n", priv->moving_state,
+ moving_state,priv->hwState.x, priv->hwState.y, millis));
+
+ if (moving_state == MS_TRACKSTICK) {
+ priv->trackstick_neutral_x = priv->hwState.x;
+ priv->trackstick_neutral_y = priv->hwState.y;
+ }
+ priv->moving_state = moving_state;
+}
+
static int
GetTimeOut(SynapticsPrivate *priv)
{
@@ -1063,7 +1085,7 @@ GetTimeOut(SynapticsPrivate *priv)
static int
HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
- edge_type edge, Bool finger)
+ edge_type edge, enum FingerState finger)
{
SynapticsSHM *para = priv->synpara;
Bool touch, release, is_timeout, move;
@@ -1073,9 +1095,12 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
if (priv->palm)
return delay;
- touch = finger && !priv->finger_flag;
- release = !finger && priv->finger_flag;
- move = FALSE;
+ touch = finger && !priv->finger_state;
+ release = !finger && priv->finger_state;
+ move = ((priv->tap_max_fingers <= 1) &&
+ ((abs(hw->x - priv->touch_on.x) >= para->tap_move) ||
+ (abs(hw->y - priv->touch_on.y) >= para->tap_move)));
+
if (touch) {
priv->touch_on.x = hw->x;
priv->touch_on.y = hw->y;
@@ -1100,17 +1125,31 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
SetTapState(priv, TS_1, hw->millis);
break;
case TS_1:
- if (is_timeout || move) {
- SetTapState(priv, TS_MOVE, hw->millis);
- goto restart;
- } else if (release) {
- SelectTapButton(priv, edge);
- SetTapState(priv, TS_2A, hw->millis);
- }
- break;
+ if (move) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ SetTapState(priv, TS_MOVE, hw->millis);
+ goto restart;
+ } else if (is_timeout) {
+ if (finger == FS_TOUCHED) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ } else if (finger == FS_PRESSED) {
+ SetMovingState(priv, MS_TRACKSTICK, hw->millis);
+ }
+ SetTapState(priv, TS_MOVE, hw->millis);
+ goto restart;
+ } else if (release) {
+ SelectTapButton(priv, edge);
+ SetTapState(priv, TS_2A, hw->millis);
+ }
+ break;
case TS_MOVE:
- if (release)
+ if (move && priv->moving_state == MS_TRACKSTICK) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ }
+ if (release) {
+ SetMovingState(priv, MS_FALSE, hw->millis);
SetTapState(priv, TS_START, hw->millis);
+ }
break;
case TS_2A:
if (touch)
@@ -1133,18 +1172,32 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
SetTapState(priv, TS_START, hw->millis);
break;
case TS_3:
- if (is_timeout || move) {
- SetTapState(priv, TS_DRAG, hw->millis);
- goto restart;
- } else if (release)
+ if (move) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ SetTapState(priv, TS_DRAG, hw->millis);
+ goto restart;
+ } else if (is_timeout) {
+ if (finger == FS_TOUCHED) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ } else if (finger == FS_PRESSED) {
+ SetMovingState(priv, MS_TRACKSTICK, hw->millis);
+ }
+ SetTapState(priv, TS_DRAG, hw->millis);
+ goto restart;
+ } else if (release) {
SetTapState(priv, TS_2B, hw->millis);
+ }
break;
case TS_DRAG:
+ if (move)
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
if (release) {
- if (para->locked_drags)
+ SetMovingState(priv, MS_FALSE, hw->millis);
+ if (para->locked_drags) {
SetTapState(priv, TS_4, hw->millis);
- else
+ } else {
SetTapState(priv, TS_START, hw->millis);
+ }
}
break;
case TS_4:
@@ -1155,8 +1208,10 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
if (is_timeout || move) {
SetTapState(priv, TS_DRAG, hw->millis);
goto restart;
- } else if (release)
+ } else if (release) {
+ SetMovingState(priv, MS_FALSE, hw->millis);
SetTapState(priv, TS_START, hw->millis);
+ }
break;
}
@@ -1196,7 +1251,7 @@ ComputeDeltas(SynapticsPrivate *priv, struct SynapticsHwState *hw,
edge_type edge, int *dxP, int *dyP)
{
SynapticsSHM *para = priv->synpara;
- Bool moving_state;
+ enum MovingState moving_state;
int dist;
double dx, dy;
double speed, integral;
@@ -1204,21 +1259,8 @@ ComputeDeltas(SynapticsPrivate *priv, struct SynapticsHwState *hw,
dx = dy = 0;
- moving_state = FALSE;
- switch (priv->tap_state) {
- case TS_MOVE:
- case TS_DRAG:
- moving_state = TRUE;
- break;
- case TS_1:
- case TS_3:
- case TS_5:
- if (hw->numFingers == 1)
- moving_state = TRUE;
- break;
- default:
- break;
- }
+ moving_state = priv->moving_state;
+
if (moving_state && !priv->palm &&
!priv->vert_scroll_edge_on && !priv->horiz_scroll_edge_on &&
!priv->vert_scroll_twofinger_on && !priv->horiz_scroll_twofinger_on &&
@@ -1229,44 +1271,52 @@ ComputeDeltas(SynapticsPrivate *priv, struct SynapticsHwState *hw,
int x_edge_speed = 0;
int y_edge_speed = 0;
double dtime = (hw->millis - HIST(0).millis) / 1000.0;
- dx = estimate_delta(hw->x, HIST(0).x, HIST(1).x, HIST(2).x);
- dy = estimate_delta(hw->y, HIST(0).y, HIST(1).y, HIST(2).y);
-
- if ((priv->tap_state == TS_DRAG) || para->edge_motion_use_always) {
- int minZ = para->edge_motion_min_z;
- int maxZ = para->edge_motion_max_z;
- int minSpd = para->edge_motion_min_speed;
- int maxSpd = para->edge_motion_max_speed;
- int edge_speed;
-
- if (hw->z <= minZ) {
- edge_speed = minSpd;
- } else if (hw->z >= maxZ) {
+
+ if (priv->moving_state == MS_TOUCHPAD_RELATIVE) {
+ dx = estimate_delta(hw->x, HIST(0).x, HIST(1).x, HIST(2).x);
+ dy = estimate_delta(hw->y, HIST(0).y, HIST(1).y, HIST(2).y);
+ if ((priv->tap_state == TS_DRAG) || para->edge_motion_use_always) {
+ int minZ = para->edge_motion_min_z;
+ int maxZ = para->edge_motion_max_z;
+ int minSpd = para->edge_motion_min_speed;
+ int maxSpd = para->edge_motion_max_speed;
+ int edge_speed;
+
+ if (hw->z <= minZ) {
+ edge_speed = minSpd;
+ } else if (hw->z >= maxZ) {
edge_speed = maxSpd;
- } else {
+ } else {
edge_speed = minSpd + (hw->z - minZ) * (maxSpd - minSpd) / (maxZ - minZ);
- }
- if (!priv->synpara->circular_pad) {
- /* on rectangular pad */
- if (edge & RIGHT_EDGE) {
- x_edge_speed = edge_speed;
- } else if (edge & LEFT_EDGE) {
- x_edge_speed = -edge_speed;
}
- if (edge & TOP_EDGE) {
- y_edge_speed = -edge_speed;
- } else if (edge & BOTTOM_EDGE) {
- y_edge_speed = edge_speed;
+ if (!priv->synpara->circular_pad) {
+ /* on rectangular pad */
+ if (edge & RIGHT_EDGE) {
+ x_edge_speed = edge_speed;
+ } else if (edge & LEFT_EDGE) {
+ x_edge_speed = -edge_speed;
+ }
+ if (edge & TOP_EDGE) {
+ y_edge_speed = -edge_speed;
+ } else if (edge & BOTTOM_EDGE) {
+ y_edge_speed = edge_speed;
+ }
+ } else if (edge) {
+ /* at edge of circular pad */
+ double relX, relY;
+
+ relative_coords(priv, hw->x, hw->y, &relX, &relY);
+ x_edge_speed = (int)(edge_speed * relX);
+ y_edge_speed = (int)(edge_speed * relY);
}
- } else if (edge) {
- /* at edge of circular pad */
- double relX, relY;
-
- relative_coords(priv, hw->x, hw->y, &relX, &relY);
- x_edge_speed = (int)(edge_speed * relX);
- y_edge_speed = (int)(edge_speed * relY);
- }
- }
+ }
+ } else if (priv->moving_state == MS_TRACKSTICK) {
+ dx = (hw->x - priv->trackstick_neutral_x);
+ dy = (hw->y - priv->trackstick_neutral_y);
+
+ dx = xf86pow(xf86fabs(dx), para->trackstick_exp_accl) * (dx < 0 ? -1.0 : 1.0) * para->trackstick_accl;
+ dy = xf86pow(xf86fabs(dy), para->trackstick_exp_accl) * (dy < 0 ? -1.0 : 1.0) * para->trackstick_accl;
+ }
/* speed depending on distance/packet */
dist = move_distance(dx, dy);
@@ -1278,7 +1328,7 @@ ComputeDeltas(SynapticsPrivate *priv, struct SynapticsHwState *hw,
}
/* modify speed according to pressure */
- {
+ if (priv->moving_state == MS_TOUCHPAD_RELATIVE) {
int minZ = para->press_motion_min_z;
int maxZ = para->press_motion_max_z;
double minFctr = para->press_motion_min_factor;
@@ -1383,7 +1433,7 @@ HandleScrolling(SynapticsPrivate *priv, struct SynapticsHwState *hw,
}
/* scroll detection */
- if (finger && !priv->finger_flag) {
+ if (finger && !priv->finger_state) {
priv->autoscroll_xspd = 0;
priv->autoscroll_yspd = 0;
priv->scroll_packet_count = 0;
@@ -1790,7 +1840,7 @@ HandleState(LocalDevicePtr local, struct SynapticsHwState *hw)
}
/* Save old values of some state variables */
- priv->finger_flag = finger;
+ priv->finger_state = finger;
priv->lastButtons = buttons;
return delay;
diff --git a/synaptics.h b/synaptics.h
index 0f4cb14..09abf76 100644
--- a/synaptics.h
+++ b/synaptics.h
@@ -50,7 +50,7 @@ typedef struct _SynapticsSHM
/* Parameter data */
int left_edge, right_edge, top_edge, bottom_edge; /* edge coordinates absolute */
- int finger_low, finger_high; /* finger detection values in Z-values */
+ int finger_low, finger_high, finger_press; /* finger detection values in Z-values */
int tap_time;
int tap_move; /* max. tapping time and movement in packets and coord. */
int single_tap_timeout; /* timeout to recognize a single tap */
@@ -67,6 +67,7 @@ typedef struct _SynapticsSHM
Bool scroll_twofinger_vert; /* Enable/disable vertical two-finger scrolling */
Bool scroll_twofinger_horiz; /* Enable/disable horizontal two-finger scrolling */
double min_speed, max_speed, accl; /* movement parameters */
+ double trackstick_accl, trackstick_exp_accl; /* trackstick mode acceleration parameters */
int edge_motion_min_z; /* finger pressure at which minimum edge motion speed is set */
int edge_motion_max_z; /* finger pressure at which maximum edge motion speed is set */
int edge_motion_min_speed; /* slowest setting for edge motion speed */
@@ -136,6 +137,19 @@ typedef struct _SynapticsMoveHist
int millis;
} SynapticsMoveHistRec;
+enum FingerState {
+ FS_UNTOUCHED,
+ FS_TOUCHED,
+ FS_PRESSED
+};
+
+enum MovingState {
+ MS_FALSE,
+ MS_TOUCHPAD_RELATIVE,
+ MS_TOUCHPAD_ABSOLUTE, /* lets reserve this for future extension, in no way supported for now */
+ MS_TRACKSTICK /* trackstick is always relative */
+};
+
enum MidButtonEmulation {
MBE_OFF, /* No button pressed */
MBE_LEFT, /* Left button pressed, waiting for right button or timeout */
@@ -192,14 +206,14 @@ typedef struct _SynapticsPrivateRec
int count_packet_finger; /* packet counter with finger on the touchpad */
int button_delay_millis; /* button delay for 3rd button emulation */
Bool prev_up; /* Previous up button value, for double click emulation */
- Bool finger_flag; /* previous finger */
+ enum FingerState finger_state; /* previous finger state */
enum TapState tap_state; /* State of tap processing */
int tap_max_fingers; /* Max number of fingers seen since entering start state */
int tap_button; /* Which button started the tap processing */
enum TapButtonState tap_button_state; /* Current tap action */
SynapticsMoveHistRec touch_on; /* data when the touchpad is touched/released */
-
+ enum MovingState moving_state; /* previous moving state */
Bool vert_scroll_edge_on; /* Keeps track of currently active scroll modes */
Bool horiz_scroll_edge_on; /* Keeps track of currently active scroll modes */
Bool vert_scroll_twofinger_on; /* Keeps track of currently active scroll modes */
@@ -207,6 +221,8 @@ typedef struct _SynapticsPrivateRec
Bool circ_scroll_on; /* Keeps track of currently active scroll modes */
Bool circ_scroll_vert; /* True: Generate vertical scroll events
False: Generate horizontal events */
+ int trackstick_neutral_x; /* neutral x position for trackstick mode */
+ int trackstick_neutral_y; /* neutral y position for trackstick mode */
double autoscroll_xspd; /* Horizontal coasting speed */
double autoscroll_yspd; /* Vertical coasting speed */
double autoscroll_x; /* Accumulated horizontal coasting scroll */
diff --git a/synclient.c b/synclient.c
index 7222d94..4a06977 100644
--- a/synclient.c
+++ b/synclient.c
@@ -55,6 +55,7 @@ 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("FingerPress", finger_press, PT_INT, 0, 256),
DEFINE_PAR("MaxTapTime", tap_time, PT_INT, 0, 1000),
DEFINE_PAR("MaxTapMove", tap_move, PT_INT, 0, 2000),
DEFINE_PAR("MaxDoubleTapTime", tap_time_2, PT_INT, 0, 1000),
@@ -72,6 +73,8 @@ static struct Parameter params[] = {
DEFINE_PAR("MinSpeed", min_speed, PT_DOUBLE, 0, 1.0),
DEFINE_PAR("MaxSpeed", max_speed, PT_DOUBLE, 0, 1.0),
DEFINE_PAR("AccelFactor", accl, PT_DOUBLE, 0, 0.2),
+ DEFINE_PAR("TrackstickAccelFactor", trackstick_accl, PT_DOUBLE, 0, 2.0),
+ DEFINE_PAR("TrackstickAccelExp", trackstick_exp_accl, PT_DOUBLE, 0, 2.0),
DEFINE_PAR("EdgeMotionMinZ", edge_motion_min_z, PT_INT, 1, 255),
DEFINE_PAR("EdgeMotionMaxZ", edge_motion_max_z, PT_INT, 1, 255),
DEFINE_PAR("EdgeMotionMinSpeed", edge_motion_min_speed, PT_INT, 0, 1000),