/* INSTALLATION: 1. gcc -o tp-scroll tp-scroll.c -lm 2. mkfifo /dev/imouse 3. In XF86Config, replace the InputDevice section: Section "InputDevice" Identifier "Mouse0" Driver "mouse" Option "Device" "/dev/imouse" Option "Protocol" "ExplorerPS/2" Option "Emulate3Buttons" "off" Option "ZAxisMapping" "4 5" EndSection 4. disable gpm (sorry, doesn't play nice with gpm yet) 5. add "/tp-scroll /dev/mouse /dev/imouse" to rc.local. USAGE: 1. Scrolling tp-scroll allows the use of the middle mouse button on a Trackpoint keyboard for scrolling up and down in applications that support the use of the wheel on an Intellimouse. The scrolling action is essentially the same as is used on the Trackpoint Windows drivers; hold down the middle mouse button and push the stick up and down to scroll. Scrolling side-to-side is currently unsupported. If the middle mouse button is pressed and released, a click event is sent along, so paste still works; however, no click is sent if the trackpoint is used to scroll the screen. Note that with tp-scroll installed and configured, dragging with the middle mouse button is impossible. tp-scroll works by translating the trackpoint's data stream into Intellimouse format. When the middle mouse button is pressed and the stick moved, it is translated into wheel motion by the driver. It should work with any software that supports mouse-wheel scrolling in X; to XFree86, a Trackpoint with tp-scroll is indistinguishable from an Intellimouse. 2. Acceleration The following three compile time options control acceleration. The acceleration is nonlinear. At slow cursor-movement speeds, the acceleration is modest (single-pixel movements are always mapped to single-pixel movements). At higher speeds, the acceleration ramps up rapidly. The tp-scroll acceleration renders X acceleration unnecessary; therefore, mouse acceleration in X should be disabled by setting the acceleration multiplier to 1. XY_ACCEL_EXP: This applies a nonlinear acceleration to the horizontal and vertical movement of the cursor. Setting XY_ACCEL_EXP to 1.0 disables acceleration (each pixel reported by the mouse moves the cursor one pixel on-screen). Setting XY_ACCEL_EXP to 2.0 results in an extremely agressive acceleration and will basically send the cursor flying across the screen if the trackpoint is pushed with any significant pressure. Values lower than 1.0 should not be used. Z_ACCEL_MULT: This variable controls the basic, unaccelerated rate of scrolling when the middle mouse button is depressed. If Z_ACCEL_MULT is set to 1, one pixel of movement with the MMB down is translated to one scroll-wheel 'click.' When Z_ACCEL_MULT is set to 0.02, 50 (1 / 0.02) pixels of movement are required to trigger one scroll-wheel event. While the MMB is down, any movement will be accumulated, and a scroll-wheel event will be sent once the accumulated motion times Z_ACCESS_MULT exceeds +/- 1. Z_ACCEL_EXP: This applies an exponential acceleration to the Z-axis movement. This is done before the the multiplier; the movement reported from the Trackpoint is first accelerated as in the XY case above, and then multiplied by Z_ACCEL_MULT and accumulated. I use the following values for these options: #define XY_ACCEL_EXP 1.6 #define Z_ACCEL_EXP 1.2 #define Z_ACCEL_MULT 0.02 Note that these represent relatively aggressive acceleration; if you don't like your mouse extremely sensitive, it is probably best to reduce these values significantly. Please note that this is not really even "alpha" quality software; it's simply an evil hack that happens to work for me. It does not play nice with gpm (gpm will not work properly with tp-scroll running). It probably will work on most normal PS/2 mice (although the scrolling action would be quite awkward in this case). Running tp-scroll in its current state might allow scrolling, fail miserably, or possibly even make your machine catch fire. :) BUGS: Documentation is inadequate, and the installation procedure needs to be automated. Compile-time options should be eliminated, and replaced with .rc files that can be changed on a per-user basis. This software is currently incompatible with gpm. AUTHOR: Daniel Grobe Sachs LICENSE: The following is a standard BSD-style license. Copyright (c) 2002, Daniel Grobe Sachs All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #define XY_ACCEL_EXP 1.6 #define Z_ACCEL_EXP 1.2 #define Z_ACCEL_MULT 0.02 main(int argc, char *argv[]) { FILE *in, *out; int state; int b, prev_b; signed char x, y; int scroll; double f; double x_scroll_accum; double y_scroll_accum; int c; if (argc < 3) { printf("%s: %s \n", argv[0], argv[0]); exit(3); } signal(SIGPIPE, SIG_IGN); while (1) { out = fopen(argv[2], "w"); in = fopen(argv[1], "r"); if ((in == NULL) || (out == NULL)) { printf("%s: unable to open files\n", argv[0]); exit(1); } state = 0; prev_b = 0; scroll = 0; while (!feof(in) && !feof(out)) { state++; c = getc(in); if ((state == 1) & !(c & 0x08)) state++; if (state == 1) b = c; if (!(b & 0x04)) { if ((prev_b & 0x04) && (!scroll)) { putc(prev_b & 0xF, out); putc(0, out); putc(0, out); putc(0, out); } scroll = 0; x_scroll_accum = 0; y_scroll_accum = 0; prev_b = b; if( (state == 2) || (state == 3) ) { x = (signed char)c; y = abs(x); f = pow( (double)y, (double)XY_ACCEL_EXP); f = (f > 127) ? 127 : f; if( x < 0 ) y = (signed char)(-f); else y = (signed char) f; #ifdef DEBUG printf("%2x %i %f %i %i\n",b,state,f,(int)x,(int)y); #endif putc(y, out); } else putc(c, out); if (state == 3) { putc(0, out); state = 0; fflush(out); } } else { prev_b = b; x = getc(in); y = getc(in); state = 0; if( y != 0 ) { scroll = 1; f = Z_ACCEL_MULT * pow( (double)(abs(y)), (double)Z_ACCEL_EXP); #ifdef DEBUG printf("y scroll %i %f accum %f\n",y,f,y_scroll_accum); #endif for( y_scroll_accum += f; y_scroll_accum > 1.0; y_scroll_accum -= 1.0 ) { putc(b & 0x0B, out); putc(0, out); putc(0, out); y < 0 ? putc(0x01, out) : putc(0x0F, out); } fflush(out); } if( x != 0 ) { scroll = 1; f = Z_ACCEL_MULT * pow( (double)(abs(x)), (double)Z_ACCEL_EXP); #ifdef DEBUG printf("x scroll %i %f accum %f\n",x,f,x_scroll_accum); #endif for( x_scroll_accum += f; x_scroll_accum > 1.0; x_scroll_accum -= 1.0 ) { putc(b & 0x0B, out); putc(0, out); putc(0, out); x < 0 ? putc(0x10, out) : putc(0x20, out); putc(b & 0x0B, out); putc(0, out); putc(0, out); putc(0, out); } fflush(out); } } } fclose(in); fclose(out); } }