Added support for circular scrolling. From Alexei Gilchrist

<alexei@physics.uq.edu.au>, with some cosmetic changes by me.
This commit is contained in:
Peter Osterlund
2004-01-25 00:10:28 +01:00
parent 2fa26a2574
commit 995df72ef0
4 changed files with 111 additions and 10 deletions

14
README
View File

@@ -107,6 +107,12 @@ TapButton2 Int Which mouse button is reported on a non-corner two-finger tap
0=No action, 1=Left Button, 2=Middle Button, 3=Right Button
TapButton3 Int Which mouse button is reported on a non-corner three-finger tap
0=No action, 1=Left Button, 2=Middle Button, 3=Right Button
CircularScrolling Bool If on, circular scrolling is used (see below)
CircScrollDelta Float Move angle (radians) of finger to generate a scroll event
CircScrollTrigger Int Trigger region on the touchpad to start circular scrolling
0=All Edges, 1=Top Edge, 2=Top Right Corner, 3=Right Edge,
4=Bottom Right Corner, 5=Bottom Edge, 6=Bottom Left Corner,
7=Left Edge, 8=Top Left Corner
A tap event happens when the finger is touched and released in a time
interval shorter than MaxTapTime, and the touch and release
@@ -133,6 +139,14 @@ events. If you press both the left and right mouse buttons at almost
the same time (no more than EmulateMidButtonTime milliseconds apart)
the driver generates a middle mouse button event.
Circular scrolling acts like a scrolling wheel on the trackpad.
Scrolling is engaged when a drag starts in the given CircScrollTrigger
region, which can be all edges, a particular side, or a particular
corner. Once scrolling is engaged, moving your finger in clockwise
circles around the trackpad will generate scroll down events and
counter clockwise scroll up events. Lifting your finger will disengage
circular scrolling. Use tight circles near the center of the pad for
fast scrolling and large circles for better control.
FAQ
---

View File

@@ -1,4 +1,7 @@
/*
* Copyright 2004 Alexei Gilchrist <alexei@physics.uq.edu.au>
* patch for circular scrolling
*
* Copyright 2003 Jörg Bösner <ich@joerg-boesner.de>
* patch for switching the touchpad off (for example, when a
* USB mouse is connected)
@@ -110,6 +113,10 @@ typedef enum {
#define TIME_DIFF(a, b) ((long)((a)-(b)))
#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* for auto-dev: */
#define DEV_INPUT_EVENT "/dev/input"
#define EVENT_DEV_NAME "event"
@@ -336,6 +343,8 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
priv->synpara->tap_action[F1_TAP] = xf86SetIntOption(local->options, "TapButton1", 1);
priv->synpara->tap_action[F2_TAP] = xf86SetIntOption(local->options, "TapButton2", 2);
priv->synpara->tap_action[F3_TAP] = xf86SetIntOption(local->options, "TapButton3", 3);
priv->synpara->circular_scrolling = xf86SetBoolOption(local->options, "CircularScrolling", FALSE);
priv->synpara->circular_trigger = xf86SetIntOption(local->options, "CircScrollTrigger", 0);
str_par = xf86FindOptionValue(local->options, "MinSpeed");
if ((!str_par) || (xf86sscanf(str_par, "%lf", &priv->synpara->min_speed) != 1))
@@ -346,6 +355,14 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
str_par = xf86FindOptionValue(local->options, "AccelFactor");
if ((!str_par) || (xf86sscanf(str_par, "%lf", &priv->synpara->accl) != 1))
priv->synpara->accl=0.0015;
str_par = xf86FindOptionValue(local->options, "CircScrollDelta");
if ((!str_par) || (xf86sscanf(str_par, "%lf", &priv->synpara->scroll_dist_circ) != 1))
priv->synpara->scroll_dist_circ = 0.1;
if (priv->synpara->circular_trigger < 0 || priv->synpara->circular_trigger > 8) {
xf86Msg(X_WARNING, "Unknown circular scrolling trigger, using 0 (edges)");
priv->synpara->circular_trigger = 0;
}
/* Warn about (and fix) incorrectly configured TopEdge/BottomEdge parameters */
if (priv->synpara->top_edge > priv->synpara->bottom_edge) {
@@ -573,6 +590,28 @@ move_distance(int dx, int dy)
return xf86sqrt((dx * dx) + (dy * dy));
}
/* return angle of point relative to center */
static double
angle(SynapticsPrivate *priv, int x, int y)
{
double xCenter = (priv->synpara->left_edge + priv->synpara->right_edge) / 2.0;
double yCenter = (priv->synpara->top_edge + priv->synpara->bottom_edge) / 2.0;
return xf86atan2(-(y - yCenter), x - xCenter);
}
/* return angle difference */
static double
diffa(double a1, double a2)
{
double da = xf86fmod(a2 - a1, 2 * M_PI);
if (da < 0)
da += 2 * M_PI;
if (da > M_PI)
da -= 2 * M_PI;
return da;
}
static edge_type
edge_detection(SynapticsPrivate *priv, int x, int y)
{
@@ -1004,17 +1043,38 @@ HandleState(LocalDevicePtr local, struct SynapticsHwState* hw)
/* 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"));
}
if (edge & BOTTOM_EDGE) {
priv->horiz_scroll_on = TRUE;
priv->scroll_x = hw->x;
DBG(7, ErrorF("horiz edge scroll detected on bottom edge\n"));
if (para->circular_scrolling) {
if ((para->circular_trigger == 0 && edge) ||
(para->circular_trigger == 1 && edge & TOP_EDGE) ||
(para->circular_trigger == 2 && edge & TOP_EDGE && edge & RIGHT_EDGE) ||
(para->circular_trigger == 3 && edge & RIGHT_EDGE) ||
(para->circular_trigger == 4 && edge & RIGHT_EDGE && edge & BOTTOM_EDGE) ||
(para->circular_trigger == 5 && edge & BOTTOM_EDGE) ||
(para->circular_trigger == 6 && edge & BOTTOM_EDGE && edge & LEFT_EDGE) ||
(para->circular_trigger == 7 && edge & LEFT_EDGE) ||
(para->circular_trigger == 8 && edge & LEFT_EDGE && edge & TOP_EDGE)) {
priv->circ_scroll_on = TRUE;
priv->scroll_a = angle(priv, hw->x, hw->y);
DBG(7, ErrorF("circular scroll detected on edge\n"));
}
} else {
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"));
}
if (edge & BOTTOM_EDGE) {
priv->horiz_scroll_on = TRUE;
priv->scroll_x = hw->x;
DBG(7, ErrorF("horiz edge scroll detected on bottom edge\n"));
}
}
}
if (priv->circ_scroll_on && (!finger || priv->palm)) {
/* circular scroll locks in until finger is raised */
DBG(7, ErrorF("cicular scroll off\n"));
priv->circ_scroll_on = FALSE;
}
if (priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger || priv->palm)) {
DBG(7, ErrorF("vert edge scroll off\n"));
priv->vert_scroll_on = FALSE;
@@ -1038,6 +1098,25 @@ HandleState(LocalDevicePtr local, struct SynapticsHwState* hw)
priv->scroll_y -= para->scroll_dist_vert;
}
}
if (priv->circ_scroll_on) {
/* + = counter clockwise, - = clockwise */
while (diffa(priv->scroll_a, angle(priv, hw->x, hw->y)) > para->scroll_dist_circ) {
scroll_up++;
if (scroll_up > 1000)
break; /* safety */
priv->scroll_a += para->scroll_dist_circ;
if (priv->scroll_a > M_PI)
priv->scroll_a -= 2 * M_PI;
}
while (diffa(priv->scroll_a, angle(priv, hw->x, hw->y)) < -para->scroll_dist_circ) {
scroll_down++;
if (scroll_down > 1000)
break; /* safety */
priv->scroll_a -= para->scroll_dist_circ;
if (priv->scroll_a < -M_PI)
priv->scroll_a += 2 * M_PI;
}
}
scroll_left = 0;
scroll_right = 0;
if (priv->horiz_scroll_on) {
@@ -1053,7 +1132,7 @@ HandleState(LocalDevicePtr local, struct SynapticsHwState* hw)
}
/* movement */
if (finger && !priv->vert_scroll_on && !priv->horiz_scroll_on &&
if (finger && !priv->vert_scroll_on && !priv->horiz_scroll_on && !priv->circ_scroll_on &&
!priv->finger_count && !priv->palm) {
delay = MIN(delay, 13);
if (priv->count_packet_finger > 3) { /* min. 3 packets */

View File

@@ -54,6 +54,9 @@ typedef struct _SynapticsSHM
Bool touchpad_off; /* Switches the Touchpad off*/
Bool locked_drags; /* Enable locked drags */
int tap_action[MAX_TAP]; /* Button to report on tap events */
Bool circular_scrolling; /* Enable circular scrolling */
double scroll_dist_circ; /* Scrolling angle radians */
int circular_trigger; /* Trigger area for circular scrolling */
} SynapticsSHM;
#ifdef SYNAPTICS_PRIVATE
@@ -147,6 +150,7 @@ typedef struct _SynapticsPrivateRec
int largest_valid_x; /* Largest valid X coordinate seen so far */
int scroll_y; /* last y-scroll position */
int scroll_x; /* last x-scroll position */
double scroll_a; /* last angle-scroll position */
unsigned long count_packet_finger; /* packet counter with finger on the touchpad */
unsigned int tapping_millis; /* packet counter for tapping */
unsigned int button_delay_millis; /* button delay for 3rd button emulation */
@@ -157,6 +161,7 @@ typedef struct _SynapticsPrivateRec
Bool tap_left, tap_mid, tap_right; /* tapping buttons */
Bool vert_scroll_on; /* scrolling flag */
Bool horiz_scroll_on; /* scrolling flag */
Bool circ_scroll_on; /* scrolling flag */
double frac_x, frac_y; /* absoulte -> relative fraction */
enum MidButtonEmulation mid_emu_state; /* emulated 3rd button */
int repeatButtons; /* buttons for repeat */

View File

@@ -71,6 +71,9 @@ static struct Parameter params[] = {
DEFINE_PAR("TapButton1", tap_action[F1_TAP], PT_INT, 0, 3),
DEFINE_PAR("TapButton2", tap_action[F2_TAP], PT_INT, 0, 3),
DEFINE_PAR("TapButton3", tap_action[F3_TAP], PT_INT, 0, 3),
DEFINE_PAR("CircularScrolling", circular_scrolling, PT_BOOL, 0, 1),
DEFINE_PAR("CircScrollDelta", scroll_dist_circ, PT_DOUBLE, .01, 3),
DEFINE_PAR("CircScrollTrigger", circular_trigger, PT_INT, 0, 8),
{ 0, 0, 0, 0, 0 }
};