1 /* $NetBSD: moused.c,v 1.17 2008/07/21 12:44:25 gmcgarry Exp $ */
3 ** Copyright (c) 1995 Michael Smith, All rights reserved.
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions
8 ** 1. Redistributions of source code must retain the above copyright
9 ** notice, this list of conditions and the following disclaimer as
10 ** the first lines of this file unmodified.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 ** notice, this list of conditions and the following disclaimer in the
13 ** documentation and/or other materials provided with the distribution.
14 ** 3. All advertising materials mentioning features or use of this software
15 ** must display the following acknowledgment:
16 ** This product includes software developed by Michael Smith.
17 ** 4. The name of the author may not be used to endorse or promote products
18 ** derived from this software without specific prior written permission.
21 ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY
22 ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR
25 ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ** Mouse daemon : listens to a serial port, the bus mouse interface, or
39 ** the PS/2 mouse port for mouse data stream, interprets data and passes
40 ** ioctls off to the console driver.
42 ** The mouse interface functions are derived closely from the mouse
43 ** handler in the XFree86 X server. Many thanks to the XFree86 people
44 ** for their great work!
48 #include <sys/cdefs.h>
51 __RCSID("$NetBSD: moused.c,v 1.17 2008/07/21 12:44:25 gmcgarry Exp $");
68 #include <sys/ioctl.h>
69 #include <dev/wscons/wsconsio.h>
70 #include <sys/types.h>
72 #include <sys/socket.h>
77 #define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */
78 #define MAX_BUTTON2TIMEOUT 2000 /* 2 seconds */
79 #define DFLT_CLICKTHRESHOLD 500 /* 0.5 second */
80 #define DFLT_BUTTON2TIMEOUT 100 /* 0.1 second */
82 /* Abort 3-button emulation delay after this many movement events. */
83 #define BUTTON2_MAXMOVE 3
88 #define MOUSE_XAXIS (-1)
89 #define MOUSE_YAXIS (-2)
91 /* Logitech PS2++ protocol */
92 #define MOUSE_PS2PLUS_CHECKBITS(b) \
93 ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
94 #define MOUSE_PS2PLUS_PACKET_TYPE(b) \
95 (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
97 #define ChordMiddle 0x0001
98 #define Emulate3Button 0x0002
99 #define ClearDTR 0x0004
100 #define ClearRTS 0x0008
108 #define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
112 /* symbol table entry */
119 /* serial PnP ID string */
121 int revision
; /* PnP revision, 100 for 1.00 */
122 const char *eisaid
; /* EISA ID including mfr ID and product ID */
123 const char *serial
; /* serial No, optional */
124 const char *class; /* device class, optional */
125 const char *compat
; /* list of compatible drivers, optional */
126 const char *description
; /* product description, optional */
127 int neisaid
; /* length of the above fields... */
134 /* global variables */
137 int nodaemon
= FALSE
;
138 int background
= FALSE
;
139 int identify
= ID_NONE
;
140 const char *pidfile
= "/var/run/moused.pid";
142 /* local variables */
144 /* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
145 static symtab_t rifs
[] = {
146 { "serial", MOUSE_IF_SERIAL
, 0 },
147 { "bus", MOUSE_IF_BUS
, 0 },
148 { "inport", MOUSE_IF_INPORT
, 0 },
149 { "ps/2", MOUSE_IF_PS2
, 0 },
150 { "sysmouse", MOUSE_IF_SYSMOUSE
, 0 },
151 { "usb", MOUSE_IF_USB
, 0 },
152 { NULL
, MOUSE_IF_UNKNOWN
, 0 },
155 /* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */
156 static const char *rnames
[] = {
179 static symtab_t rmodels
[] = {
180 { "NetScroll", MOUSE_MODEL_NETSCROLL
, 0 },
181 { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET
, 0 },
182 { "GlidePoint", MOUSE_MODEL_GLIDEPOINT
, 0 },
183 { "ThinkingMouse", MOUSE_MODEL_THINK
, 0 },
184 { "IntelliMouse", MOUSE_MODEL_INTELLI
, 0 },
185 { "EasyScroll/SmartScroll", MOUSE_MODEL_EASYSCROLL
, 0 },
186 { "MouseMan+", MOUSE_MODEL_MOUSEMANPLUS
, 0 },
187 { "Kidspad", MOUSE_MODEL_KIDSPAD
, 0 },
188 { "VersaPad", MOUSE_MODEL_VERSAPAD
, 0 },
189 { "IntelliMouse Explorer", MOUSE_MODEL_EXPLORER
, 0 },
190 { "4D Mouse", MOUSE_MODEL_4D
, 0 },
191 { "4D+ Mouse", MOUSE_MODEL_4DPLUS
, 0 },
192 { "generic", MOUSE_MODEL_GENERIC
, 0 },
193 { NULL
, MOUSE_MODEL_UNKNOWN
, 0 },
196 /* PnP EISA/product IDs */
197 static symtab_t pnpprod
[] = {
198 /* Kensignton ThinkingMouse */
199 { "KML0001", MOUSE_PROTO_THINK
, MOUSE_MODEL_THINK
},
200 /* MS IntelliMouse */
201 { "MSH0001", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_INTELLI
},
202 /* MS IntelliMouse TrackBall */
203 { "MSH0004", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_INTELLI
},
204 /* Tremon Wheel Mouse MUSD */
205 { "HTK0001", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_INTELLI
},
206 /* Genius PnP Mouse */
207 { "KYE0001", MOUSE_PROTO_MS
, MOUSE_MODEL_GENERIC
},
208 /* MouseSystems SmartScroll Mouse (OEM from Genius?) */
209 { "KYE0002", MOUSE_PROTO_MS
, MOUSE_MODEL_EASYSCROLL
},
210 /* Genius NetMouse */
211 { "KYE0003", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_NET
},
212 /* Genius Kidspad, Easypad and other tablets */
213 { "KYE0005", MOUSE_PROTO_KIDSPAD
, MOUSE_MODEL_KIDSPAD
},
214 /* Genius EZScroll */
215 { "KYEEZ00", MOUSE_PROTO_MS
, MOUSE_MODEL_EASYSCROLL
},
216 /* Logitech Cordless MouseMan Wheel */
217 { "LGI8033", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_MOUSEMANPLUS
},
218 /* Logitech MouseMan (new 4 button model) */
219 { "LGI800C", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_MOUSEMANPLUS
},
220 /* Logitech MouseMan+ */
221 { "LGI8050", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_MOUSEMANPLUS
},
222 /* Logitech FirstMouse+ */
223 { "LGI8051", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_MOUSEMANPLUS
},
224 /* Logitech serial */
225 { "LGI8001", MOUSE_PROTO_LOGIMOUSEMAN
, MOUSE_MODEL_GENERIC
},
226 /* A4 Tech 4D/4D+ Mouse */
227 { "A4W0005", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_4D
},
228 /* 8D Scroll Mouse */
229 { "PEC9802", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_INTELLI
},
230 /* Mitsumi Wireless Scroll Mouse */
231 { "MTM6401", MOUSE_PROTO_INTELLI
, MOUSE_MODEL_INTELLI
},
234 { "PNP0F00", MOUSE_PROTO_BUS
, MOUSE_MODEL_GENERIC
},
236 { "PNP0F01", MOUSE_PROTO_MS
, MOUSE_MODEL_GENERIC
},
238 { "PNP0F02", MOUSE_PROTO_INPORT
, MOUSE_MODEL_GENERIC
},
240 { "PNP0F03", MOUSE_PROTO_PS2
, MOUSE_MODEL_GENERIC
},
242 * EzScroll returns PNP0F04 in the compatible device field; but it
243 * doesn't look compatible... XXX
246 { "PNP0F04", MOUSE_PROTO_MSC
, MOUSE_MODEL_GENERIC
},
248 { "PNP0F05", MOUSE_PROTO_MSC
, MOUSE_MODEL_GENERIC
},
251 { "PNP0F06", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
253 { "PNP0F07", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
255 /* Logitech serial */
256 { "PNP0F08", MOUSE_PROTO_LOGIMOUSEMAN
, MOUSE_MODEL_GENERIC
},
257 /* MS BallPoint serial */
258 { "PNP0F09", MOUSE_PROTO_MS
, MOUSE_MODEL_GENERIC
},
260 { "PNP0F0A", MOUSE_PROTO_MS
, MOUSE_MODEL_GENERIC
},
261 /* MS PnP BallPoint serial */
262 { "PNP0F0B", MOUSE_PROTO_MS
, MOUSE_MODEL_GENERIC
},
263 /* MS serial comatible */
264 { "PNP0F0C", MOUSE_PROTO_MS
, MOUSE_MODEL_GENERIC
},
265 /* MS InPort comatible */
266 { "PNP0F0D", MOUSE_PROTO_INPORT
, MOUSE_MODEL_GENERIC
},
267 /* MS PS/2 comatible */
268 { "PNP0F0E", MOUSE_PROTO_PS2
, MOUSE_MODEL_GENERIC
},
269 /* MS BallPoint comatible */
270 { "PNP0F0F", MOUSE_PROTO_MS
, MOUSE_MODEL_GENERIC
},
273 { "PNP0F10", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
275 /* MS bus comatible */
276 { "PNP0F11", MOUSE_PROTO_BUS
, MOUSE_MODEL_GENERIC
},
278 { "PNP0F12", MOUSE_PROTO_PS2
, MOUSE_MODEL_GENERIC
},
280 { "PNP0F13", MOUSE_PROTO_PS2
, MOUSE_MODEL_GENERIC
},
283 { "PNP0F14", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
286 { "PNP0F15", MOUSE_PROTO_BUS
, MOUSE_MODEL_GENERIC
},
289 { "PNP0F16", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
291 /* Logitech serial compat */
292 { "PNP0F17", MOUSE_PROTO_LOGIMOUSEMAN
, MOUSE_MODEL_GENERIC
},
293 /* Logitech bus compatible */
294 { "PNP0F18", MOUSE_PROTO_BUS
, MOUSE_MODEL_GENERIC
},
295 /* Logitech PS/2 compatible */
296 { "PNP0F19", MOUSE_PROTO_PS2
, MOUSE_MODEL_GENERIC
},
298 /* Logitech SWIFT compatible */
299 { "PNP0F1A", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
301 { "PNP0F1B", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
302 /* Compaq LTE TrackBall PS/2 */
303 { "PNP0F1C", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
304 /* Compaq LTE TrackBall serial */
305 { "PNP0F1D", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
306 /* MS Kidts Trackball */
307 { "PNP0F1E", MOUSE_PROTO_
???, MOUSE_MODEL_GENERIC
},
309 /* Interlink VersaPad */
310 { "LNK0001", MOUSE_PROTO_VERSAPAD
, MOUSE_MODEL_VERSAPAD
},
312 { NULL
, MOUSE_PROTO_UNKNOWN
, MOUSE_MODEL_GENERIC
},
315 /* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */
316 static unsigned short rodentcflags
[] =
318 (CS7
| CREAD
| CLOCAL
| HUPCL
), /* MicroSoft */
319 (CS8
| CSTOPB
| CREAD
| CLOCAL
| HUPCL
), /* MouseSystems */
320 (CS8
| CSTOPB
| CREAD
| CLOCAL
| HUPCL
), /* Logitech */
321 (CS8
| PARENB
| PARODD
| CREAD
| CLOCAL
| HUPCL
), /* MMSeries */
322 (CS7
| CREAD
| CLOCAL
| HUPCL
), /* MouseMan */
326 (CS8
| CREAD
| CLOCAL
| HUPCL
), /* MM HitTablet */
327 (CS7
| CREAD
| CLOCAL
| HUPCL
), /* GlidePoint */
328 (CS7
| CREAD
| CLOCAL
| HUPCL
), /* IntelliMouse */
329 (CS7
| CREAD
| CLOCAL
| HUPCL
), /* Thinking Mouse */
330 (CS8
| CSTOPB
| CREAD
| CLOCAL
| HUPCL
), /* sysmouse */
331 (CS7
| CREAD
| CLOCAL
| HUPCL
), /* X10 MouseRemote */
332 (CS8
| PARENB
| PARODD
| CREAD
| CLOCAL
| HUPCL
), /* kidspad etc. */
333 (CS8
| CREAD
| CLOCAL
| HUPCL
), /* VersaPad */
335 (CS8
| CSTOPB
| CREAD
| CLOCAL
| HUPCL
), /* Mariqua */
339 static struct rodentparam
{
341 char *portname
; /* /dev/XXX */
342 int rtype
; /* MOUSE_PROTO_XXX */
343 int level
; /* operation level: 0 or greater */
345 int rate
; /* report rate */
346 int resolution
; /* MOUSE_RES_XXX or a positive number */
347 int zmap
[4]; /* MOUSE_{X|Y}AXIS or a button number */
348 int wmode
; /* wheel mode button number */
349 int mfd
; /* mouse file descriptor */
350 int cfd
; /* /dev/wsmousectl file descriptor */
351 int mremsfd
; /* mouse remote server file descriptor */
352 int mremcfd
; /* mouse remote client file descriptor */
353 long clickthreshold
; /* double click speed in msec */
354 long button2timeout
; /* 3 button emulation timeout */
355 mousehw_t hw
; /* mouse device hardware information */
356 mousemode_t mode
; /* protocol information */
357 float accelx
; /* Acceleration in the X axis */
358 float accely
; /* Acceleration in the Y axis */
362 .rtype
= MOUSE_PROTO_UNKNOWN
,
366 .resolution
= MOUSE_RES_UNKNOWN
,
367 .zmap
= { 0, 0, 0, 0 },
373 .clickthreshold
= DFLT_CLICKTHRESHOLD
,
374 .button2timeout
= DFLT_BUTTON2TIMEOUT
,
380 struct button_state
{
381 int count
; /* 0: up, 1: single click, 2: double click,... */
382 struct timeval tv
; /* timestamp on the last button event */
384 static struct button_state bstate
[MOUSE_MAXBUTTON
]; /* button state */
385 static struct button_state
*mstate
[MOUSE_MAXBUTTON
];/* mapped button st.*/
386 static struct button_state zstate
[4]; /* Z/W axis state */
388 /* state machine for 3 button emulation */
390 #define S0 0 /* start */
391 #define S1 1 /* button 1 delayed down */
392 #define S2 2 /* button 3 delayed down */
393 #define S3 3 /* both buttons down -> button 2 down */
394 #define S4 4 /* button 1 delayed up */
395 #define S5 5 /* button 1 down */
396 #define S6 6 /* button 3 down */
397 #define S7 7 /* both buttons down */
398 #define S8 8 /* button 3 delayed up */
399 #define S9 9 /* button 1 or 3 up after S3 */
401 #define A(b1, b3) (((b1) ? 2 : 0) | ((b3) ? 1 : 0))
403 #define S_DELAYED(st) (states[st].s[A_TIMEOUT] != (st))
406 int s
[A_TIMEOUT
+ 1];
412 { { S0
, S2
, S1
, S3
, S0
}, 0, ~(MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
), FALSE
},
414 { { S4
, S2
, S1
, S3
, S5
}, 0, ~MOUSE_BUTTON1DOWN
, FALSE
},
416 { { S8
, S2
, S1
, S3
, S6
}, 0, ~MOUSE_BUTTON3DOWN
, FALSE
},
418 { { S0
, S9
, S9
, S3
, S3
}, MOUSE_BUTTON2DOWN
, ~0, FALSE
},
420 { { S0
, S2
, S1
, S3
, S0
}, MOUSE_BUTTON1DOWN
, ~0, TRUE
},
422 { { S0
, S2
, S5
, S7
, S5
}, MOUSE_BUTTON1DOWN
, ~0, FALSE
},
424 { { S0
, S6
, S1
, S7
, S6
}, MOUSE_BUTTON3DOWN
, ~0, FALSE
},
426 { { S0
, S6
, S5
, S7
, S7
}, MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
, ~0, FALSE
},
428 { { S0
, S2
, S1
, S3
, S0
}, MOUSE_BUTTON3DOWN
, ~0, TRUE
},
430 { { S0
, S9
, S9
, S3
, S9
}, 0, ~(MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
), FALSE
},
432 static int mouse_button_state
;
433 static struct timeval mouse_button_state_tv
;
434 static int mouse_move_delayed
;
438 /* function prototypes */
440 static void moused(const char *);
441 static void hup(int sig
);
442 static void cleanup(int sig
);
443 static void usage(void);
445 static int r_identify(void);
446 static const char *r_if(int type
);
447 static const char *r_name(int type
);
448 static const char *r_model(int model
);
449 static void r_init(void);
450 static int r_protocol(u_char b
, mousestatus_t
*act
);
451 static int r_statetrans(mousestatus_t
*a1
, mousestatus_t
*a2
, int trans
);
452 static int r_installmap(char *arg
);
453 static void r_map(mousestatus_t
*act1
, mousestatus_t
*act2
);
454 static void r_timestamp(mousestatus_t
*act
);
455 static int r_timeout(void);
456 static void setmousespeed(int old
, int new, unsigned cflag
);
458 static int pnpwakeup1(void);
459 static int pnpwakeup2(void);
460 static int pnpgets(char *buf
);
461 static int pnpparse(pnpid_t
*id
, char *buf
, int len
);
462 static symtab_t
*pnpproto(pnpid_t
*id
);
464 static symtab_t
*gettoken(symtab_t
*tab
, const char *s
, int len
);
465 static const char *gettokenname(symtab_t
*tab
, int val
);
467 static void wsev(int ty
, int val
);
469 static int kidspad(u_char rxc
, mousestatus_t
*act
);
472 debug(const char *fmt
, ...)
483 logerr(int e
, const char *fmt
, ...)
489 int saveerrno
= errno
;
490 vsyslog(LOG_DAEMON
| LOG_ERR
, fmt
, ap
);
492 syslog(LOG_DAEMON
| LOG_ERR
, "%m");
500 logwarn(const char *fmt
, ...)
506 int saveerrno
= errno
;
507 vsyslog(LOG_DAEMON
| LOG_WARNING
, fmt
, ap
);
509 syslog(LOG_DAEMON
| LOG_WARNING
, "%m");
516 logwarnx(const char *fmt
, ...)
522 vsyslog(LOG_DAEMON
| LOG_WARNING
, fmt
, ap
);
529 main(int argc
, char *argv
[])
534 const char * volatile ctldev
= "/dev/wsmuxctl0";
536 for (i
= 0; i
< MOUSE_MAXBUTTON
; ++i
)
537 mstate
[i
] = &bstate
[i
];
539 while((c
= getopt(argc
,argv
,"3DE:F:I:PRS:W:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
547 rodent
.flags
|= Emulate3Button
;
551 rodent
.button2timeout
= atoi(optarg
);
552 if ((rodent
.button2timeout
< 0) ||
553 (rodent
.button2timeout
> MAX_BUTTON2TIMEOUT
)) {
554 warnx("invalid argument `%s'", optarg
);
560 i
= sscanf(optarg
, "%f,%f", &rodent
.accelx
, &rodent
.accely
);
562 warnx("invalid acceleration argument '%s'", optarg
);
567 rodent
.accely
= rodent
.accelx
;
572 rodent
.flags
|= ChordMiddle
;
584 if (strcmp(optarg
, "all") == 0)
586 else if (strcmp(optarg
, "port") == 0)
588 else if (strcmp(optarg
, "if") == 0)
590 else if (strcmp(optarg
, "type") == 0)
592 else if (strcmp(optarg
, "model") == 0)
595 warnx("invalid argument `%s'", optarg
);
602 rodent
.level
= atoi(optarg
);
603 if ((rodent
.level
< 0) || (rodent
.level
> 4)) {
604 warnx("invalid argument `%s'", optarg
);
610 if (!r_installmap(optarg
)) {
611 warnx("invalid argument `%s'", optarg
);
617 rodent
.portname
= optarg
;
621 if (strcmp(optarg
, "high") == 0)
622 rodent
.resolution
= MOUSE_RES_HIGH
;
623 else if (strcmp(optarg
, "medium-high") == 0)
624 rodent
.resolution
= MOUSE_RES_HIGH
;
625 else if (strcmp(optarg
, "medium-low") == 0)
626 rodent
.resolution
= MOUSE_RES_MEDIUMLOW
;
627 else if (strcmp(optarg
, "low") == 0)
628 rodent
.resolution
= MOUSE_RES_LOW
;
629 else if (strcmp(optarg
, "default") == 0)
630 rodent
.resolution
= MOUSE_RES_DEFAULT
;
632 rodent
.resolution
= atoi(optarg
);
633 if (rodent
.resolution
<= 0) {
634 warnx("invalid argument `%s'", optarg
);
641 rodent
.baudrate
= 9600;
646 if ((i
<= 0) || (i
> MOUSE_MAXBUTTON
)) {
647 warnx("invalid argument `%s'", optarg
);
650 rodent
.wmode
= 1 << (i
- 1);
654 if (strcmp(optarg
, "x") == 0)
655 rodent
.zmap
[0] = MOUSE_XAXIS
;
656 else if (strcmp(optarg
, "y") == 0)
657 rodent
.zmap
[0] = MOUSE_YAXIS
;
661 * Use button i for negative Z axis movement and
662 * button (i + 1) for positive Z axis movement.
664 if ((i
<= 0) || (i
> MOUSE_MAXBUTTON
- 1)) {
665 warnx("invalid argument `%s'", optarg
);
669 rodent
.zmap
[1] = i
+ 1;
670 debug("optind: %d, optarg: '%s'", optind
, optarg
);
671 for (j
= 1; j
< 4; ++j
) {
672 if ((optind
>= argc
) || !isdigit((unsigned char)*argv
[optind
]))
674 i
= atoi(argv
[optind
]);
675 if ((i
<= 0) || (i
> MOUSE_MAXBUTTON
- 1)) {
676 warnx("invalid argument `%s'", argv
[optind
]);
682 if ((rodent
.zmap
[2] != 0) && (rodent
.zmap
[3] == 0))
683 rodent
.zmap
[3] = rodent
.zmap
[2] + 1;
688 rodent
.clickthreshold
= atoi(optarg
);
689 if ((rodent
.clickthreshold
< 0) ||
690 (rodent
.clickthreshold
> MAX_CLICKTHRESHOLD
)) {
691 warnx("invalid argument `%s'", optarg
);
697 rodent
.flags
|= ClearDTR
;
701 rodent
.rate
= atoi(optarg
);
702 if (rodent
.rate
<= 0) {
703 warnx("invalid argument `%s'", optarg
);
713 rodent
.flags
|= NoPnP
;
717 rodent
.flags
|= ClearRTS
;
721 rodent
.baudrate
= atoi(optarg
);
722 if (rodent
.baudrate
<= 0) {
723 warnx("invalid argument `%s'", optarg
);
726 debug("rodent baudrate %d", rodent
.baudrate
);
730 if (strcmp(optarg
, "auto") == 0) {
731 rodent
.rtype
= MOUSE_PROTO_UNKNOWN
;
732 rodent
.flags
&= ~NoPnP
;
736 for (i
= 0; rnames
[i
]; i
++)
737 if (strcmp(optarg
, rnames
[i
]) == 0) {
739 rodent
.flags
|= NoPnP
;
740 rodent
.level
= (i
== MOUSE_PROTO_SYSMOUSE
) ? 1 : 0;
745 warnx("no such mouse type `%s'", optarg
);
754 /* fix Z axis mapping */
755 for (i
= 0; i
< 4; ++i
) {
756 if (rodent
.zmap
[i
] > 0) {
757 for (j
= 0; j
< MOUSE_MAXBUTTON
; ++j
) {
758 if (mstate
[j
] == &bstate
[rodent
.zmap
[i
] - 1])
759 mstate
[j
] = &zstate
[i
];
761 rodent
.zmap
[i
] = 1 << (rodent
.zmap
[i
] - 1);
765 /* the default port name */
766 switch(rodent
.rtype
) {
767 case MOUSE_PROTO_INPORT
:
768 /* INPORT and BUS are the same... */
769 rodent
.rtype
= MOUSE_PROTO_BUS
;
774 warnx("no port name specified");
779 if (setjmp(env
) == 0) {
781 signal(SIGINT
, cleanup
);
782 signal(SIGQUIT
, cleanup
);
783 signal(SIGTERM
, cleanup
);
784 if ((rodent
.mfd
= open(rodent
.portname
, O_RDWR
| O_NONBLOCK
, 0))
786 logerr(1, "unable to open %s", rodent
.portname
);
787 if (r_identify() == MOUSE_PROTO_UNKNOWN
) {
788 logwarnx("cannot determine mouse type on %s", rodent
.portname
);
793 /* print some information */
794 if (identify
!= ID_NONE
) {
795 if (identify
== ID_ALL
)
796 printf("%s %s %s %s\n",
797 rodent
.portname
, r_if(rodent
.hw
.iftype
),
798 r_name(rodent
.rtype
), r_model(rodent
.hw
.model
));
799 else if (identify
& ID_PORT
)
800 printf("%s\n", rodent
.portname
);
801 else if (identify
& ID_IF
)
802 printf("%s\n", r_if(rodent
.hw
.iftype
));
803 else if (identify
& ID_TYPE
)
804 printf("%s\n", r_name(rodent
.rtype
));
805 else if (identify
& ID_MODEL
)
806 printf("%s\n", r_model(rodent
.hw
.model
));
809 debug("port: %s interface: %s type: %s model: %s",
810 rodent
.portname
, r_if(rodent
.hw
.iftype
),
811 r_name(rodent
.rtype
), r_model(rodent
.hw
.model
));
814 if (rodent
.mfd
== -1) {
816 * We cannot continue because of error. Exit if the
817 * program has not become a daemon. Otherwise, block
818 * until the user corrects the problem and issues SIGHUP.
825 r_init(); /* call init function */
829 if (rodent
.mfd
!= -1)
831 if (rodent
.cfd
!= -1)
833 rodent
.mfd
= rodent
.cfd
= -1;
841 wsev(int ty
, int val
)
843 struct wscons_event ev
;
848 printf("wsev: type=%d value=%d\n", ty
, val
);
849 if (ioctl(rodent
.cfd
, WSMUXIO_INJECTEVENT
, &ev
) < 0)
850 logwarn("muxio inject event");
854 moused(const char *wsm
)
856 mousestatus_t action0
; /* original mouse action */
857 mousestatus_t action
; /* interrim buffer */
858 mousestatus_t action2
; /* mapped action */
861 struct pollfd set
[3];
868 if ((rodent
.cfd
= open(wsm
, O_WRONLY
, 0)) == -1)
869 logerr(1, "cannot open %s", wsm
);
871 if (!nodaemon
&& !background
) {
873 logerr(1, "failed to become a daemon");
876 fp
= fopen(pidfile
, "w");
878 fprintf(fp
, "%d\n", getpid());
884 /* clear mouse data */
885 bzero(&action0
, sizeof(action0
));
886 bzero(&action
, sizeof(action
));
887 bzero(&action2
, sizeof(action2
));
888 mouse_button_state
= S0
;
889 gettimeofday(&mouse_button_state_tv
, NULL
);
890 mouse_move_delayed
= 0;
891 for (i
= 0; i
< MOUSE_MAXBUTTON
; ++i
) {
893 bstate
[i
].tv
= mouse_button_state_tv
;
895 for (i
= 0; i
< (int)(sizeof(zstate
)/sizeof(zstate
[0])); ++i
) {
897 zstate
[i
].tv
= mouse_button_state_tv
;
901 /* process mouse data */
904 set
[0].fd
= rodent
.mfd
;
905 set
[0].events
= POLLIN
;
906 set
[1].fd
= rodent
.mremsfd
;
907 set
[1].events
= POLLIN
;
908 set
[2].fd
= rodent
.mremcfd
;
909 set
[2].events
= POLLIN
;
911 c
= poll(set
, 3, (rodent
.flags
& Emulate3Button
) ? 20 : INFTIM
);
912 if (c
< 0) { /* error */
913 logwarn("failed to read from mouse");
915 } else if (c
== 0) { /* timeout */
916 /* assert(rodent.flags & Emulate3Button) */
917 action0
.button
= action0
.obutton
;
918 action0
.dx
= action0
.dy
= action0
.dz
= 0;
919 action0
.flags
= flags
= 0;
920 if (r_timeout() && r_statetrans(&action0
, &action
, A_TIMEOUT
)) {
922 debug("flags:%08x buttons:%08x obuttons:%08x",
923 action
.flags
, action
.button
, action
.obutton
);
925 action0
.obutton
= action0
.button
;
930 /* MouseRemote client connect/disconnect */
931 if (set
[1].revents
& POLLIN
) {
932 mremote_clientchg(TRUE
);
935 if (set
[2].revents
& POLLIN
) {
936 mremote_clientchg(FALSE
);
941 if (set
[0].revents
& POLLIN
) {
942 if (read(rodent
.mfd
, &b
, 1) == -1)
944 if ((flags
= r_protocol(b
, &action0
)) == 0)
946 r_timestamp(&action0
);
947 r_statetrans(&action0
, &action
,
948 A(action0
.button
& MOUSE_BUTTON1DOWN
,
949 action0
.button
& MOUSE_BUTTON3DOWN
));
950 debug("flags:%08x buttons:%08x obuttons:%08x", action
.flags
,
951 action
.button
, action
.obutton
);
954 action0
.obutton
= action0
.button
;
955 flags
&= MOUSE_POSCHANGED
;
956 flags
|= action
.obutton
^ action
.button
;
957 action
.flags
= flags
;
959 if (flags
) { /* handler detected action */
960 r_map(&action
, &action2
);
961 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
962 action2
.button
, action2
.dx
, action2
.dy
, action2
.dz
);
965 printf("buttons=%x x=%d y=%d z=%d\n", action2
.button
,
966 (int)(action2
.dx
* rodent
.accelx
),
967 (int)(action2
.dy
* rodent
.accely
),
969 if (action2
.dx
!= 0 && dbg
< 2)
970 wsev(WSCONS_EVENT_MOUSE_DELTA_X
, action2
.dx
* rodent
.accelx
);
971 if (action2
.dy
!= 0 && dbg
< 2)
972 wsev(WSCONS_EVENT_MOUSE_DELTA_Y
, -action2
.dy
* rodent
.accely
);
973 if (action2
.dz
!= 0 && dbg
< 2)
974 wsev(WSCONS_EVENT_MOUSE_DELTA_Z
, action2
.dz
);
975 button
= lastbutton
^ action2
.button
;
976 lastbutton
= action2
.button
;
977 printf("diff=%x buts=%x\n", button
, lastbutton
);
978 for (i
= 0; i
< 3; i
++) {
979 if ((button
& (1<<i
)) && dbg
< 2) {
980 wsev(lastbutton
& (1<<i
) ? WSCONS_EVENT_MOUSE_DOWN
:
981 WSCONS_EVENT_MOUSE_UP
, i
);
986 * If the Z axis movement is mapped to a imaginary physical
987 * button, we need to cook up a corresponding button `up' event
988 * after sending a button `down' event.
990 if ((rodent
.zmap
[0] > 0) && (action
.dz
!= 0)) {
991 action
.obutton
= action
.button
;
992 action
.dx
= action
.dy
= action
.dz
= 0;
993 r_map(&action
, &action2
);
994 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
995 action2
.button
, action2
.dx
, action2
.dy
, action2
.dz
);
997 /* XXX emplement this */
1002 mouse
.operation
= MOUSE_ACTION
;
1003 mouse
.u
.data
.buttons
= action2
.button
;
1004 mouse
.u
.data
.x
= mouse
.u
.data
.y
= mouse
.u
.data
.z
= 0;
1006 ioctl(rodent
.cfd
, CONS_MOUSECTL
, &mouse
);
1024 if (rodent
.rtype
== MOUSE_PROTO_X10MOUSEREM
)
1025 unlink(_PATH_MOUSEREMOTE
);
1032 ** Complain, and free the CPU for more worthy tasks
1037 fprintf(stderr
, "%s\n%s\n%s\n%s\n",
1038 "usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
1039 " [-a X[,Y]] [-m N=M] [-w N] [-z N]",
1040 " [-t <mousetype>] [-3 [-E timeout]] -p <port>",
1041 " moused [-d] -i <port|if|type|model|all> -p <port>");
1046 ** Mouse interface code, courtesy of XFree86 3.1.2.
1048 ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
1049 ** to clean, reformat and rationalise naming, it's quite possible that
1050 ** some things in here have been broken.
1054 ** The following code is derived from a module marked :
1057 /* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
1058 /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
1059 17:03:40 dawes Exp $ */
1062 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
1063 * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
1065 * Permission to use, copy, modify, distribute, and sell this software and its
1066 * documentation for any purpose is hereby granted without fee, provided that
1067 * the above copyright notice appear in all copies and that both that
1068 * copyright notice and this permission notice appear in supporting
1069 * documentation, and that the names of Thomas Roell and David Dawes not be
1070 * used in advertising or publicity pertaining to distribution of the
1071 * software without specific, written prior permission. Thomas Roell
1072 * and David Dawes makes no representations about the suitability of this
1073 * software for any purpose. It is provided "as is" without express or
1076 * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
1077 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1078 * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
1079 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
1080 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
1081 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1082 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1087 ** GlidePoint support from XFree86 3.2.
1088 ** Derived from the module:
1091 /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
1092 /* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
1094 /* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
1095 static unsigned char proto
[][7] = {
1096 /* hd_mask hd_id dp_mask dp_id bytes b4_mask b4_id */
1097 { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MicroSoft */
1098 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* MouseSystems */
1099 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* Logitech */
1100 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MMSeries */
1101 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* MouseMan */
1102 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* Bus */
1103 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* InPort */
1104 { 0xc0, 0x00, 0x00, 0x00, 3, 0x00, 0xff }, /* PS/2 mouse */
1105 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MM HitTablet */
1106 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* GlidePoint */
1107 { 0x40, 0x40, 0x40, 0x00, 3, ~0x3f, 0x00 }, /* IntelliMouse */
1108 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* ThinkingMouse */
1109 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* sysmouse */
1110 { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* X10 MouseRem */
1111 { 0x80, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* KIDSPAD */
1112 { 0xc3, 0xc0, 0x00, 0x00, 6, 0x00, 0xff }, /* VersaPad */
1114 { 0xf8, 0x80, 0x00, 0x00, 5, ~0x2f, 0x10 }, /* Mariqua */
1117 static unsigned char cur_proto
[7];
1122 char pnpbuf
[256]; /* PnP identifier string may be up to 256 bytes long */
1129 if (rodent
.rtype
!= MOUSE_PROTO_UNKNOWN
)
1130 bcopy(proto
[rodent
.rtype
], cur_proto
, sizeof(cur_proto
));
1131 rodent
.mode
.protocol
= MOUSE_PROTO_UNKNOWN
;
1132 rodent
.mode
.rate
= -1;
1133 rodent
.mode
.resolution
= MOUSE_RES_UNKNOWN
;
1134 rodent
.mode
.accelfactor
= 0;
1135 rodent
.mode
.level
= 0;
1137 /* maybe this is an PnP mouse... */
1138 if (rodent
.mode
.protocol
== MOUSE_PROTO_UNKNOWN
) {
1140 if (rodent
.flags
& NoPnP
)
1141 return rodent
.rtype
;
1142 if (((len
= pnpgets(pnpbuf
)) <= 0) || !pnpparse(&pnpid
, pnpbuf
, len
))
1143 return rodent
.rtype
;
1145 debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
1146 pnpid
.neisaid
, pnpid
.neisaid
, pnpid
.eisaid
,
1147 pnpid
.ncompat
, pnpid
.ncompat
, pnpid
.compat
,
1148 pnpid
.ndescription
, pnpid
.ndescription
, pnpid
.description
);
1150 /* we have a valid PnP serial device ID */
1151 rodent
.hw
.iftype
= MOUSE_IF_SERIAL
;
1152 t
= pnpproto(&pnpid
);
1154 rodent
.mode
.protocol
= t
->val
;
1155 rodent
.hw
.model
= t
->val2
;
1157 rodent
.mode
.protocol
= MOUSE_PROTO_UNKNOWN
;
1159 if (rodent
.mode
.protocol
== MOUSE_PROTO_INPORT
)
1160 rodent
.mode
.protocol
= MOUSE_PROTO_BUS
;
1162 /* make final adjustment */
1163 if (rodent
.mode
.protocol
!= MOUSE_PROTO_UNKNOWN
) {
1164 if (rodent
.mode
.protocol
!= rodent
.rtype
) {
1165 /* Hmm, the device doesn't agree with the user... */
1166 if (rodent
.rtype
!= MOUSE_PROTO_UNKNOWN
)
1167 logwarnx("mouse type mismatch (%s != %s), %s is assumed",
1168 r_name(rodent
.mode
.protocol
), r_name(rodent
.rtype
),
1169 r_name(rodent
.mode
.protocol
));
1170 rodent
.rtype
= rodent
.mode
.protocol
;
1171 bcopy(proto
[rodent
.rtype
], cur_proto
, sizeof(cur_proto
));
1176 debug("proto params: %02x %02x %02x %02x %d %02x %02x",
1177 cur_proto
[0], cur_proto
[1], cur_proto
[2], cur_proto
[3],
1178 cur_proto
[4], cur_proto
[5], cur_proto
[6]);
1180 return rodent
.rtype
;
1188 s
= gettokenname(rifs
, iftype
);
1189 return (s
== NULL
) ? "unknown" : s
;
1195 return ((type
== MOUSE_PROTO_UNKNOWN
)
1196 || (type
> (int)(sizeof(rnames
)/sizeof(rnames
[0]) - 1)))
1197 ? "unknown" : rnames
[type
];
1205 s
= gettokenname(rmodels
, model
);
1206 return (s
== NULL
) ? "unknown" : s
;
1212 unsigned char buf
[16]; /* scrach buffer */
1213 struct pollfd set
[1];
1219 ** This comment is a little out of context here, but it contains
1220 ** some useful information...
1221 ********************************************************************
1223 ** The following lines take care of the Logitech MouseMan protocols.
1225 ** NOTE: There are different versions of both MouseMan and TrackMan!
1226 ** Hence I add another protocol P_LOGIMAN, which the user can
1227 ** specify as MouseMan in his XF86Config file. This entry was
1228 ** formerly handled as a special case of P_MS. However, people
1229 ** who don't have the middle button problem, can still specify
1230 ** Microsoft and use P_MS.
1232 ** By default, these mice should use a 3 byte Microsoft protocol
1233 ** plus a 4th byte for the middle button. However, the mouse might
1234 ** have switched to a different protocol before we use it, so I send
1235 ** the proper sequence just in case.
1237 ** NOTE: - all commands to (at least the European) MouseMan have to
1238 ** be sent at 1200 Baud.
1239 ** - each command starts with a '*'.
1240 ** - whenever the MouseMan receives a '*', it will switch back
1241 ** to 1200 Baud. Hence I have to select the desired protocol
1242 ** first, then select the baud rate.
1244 ** The protocols supported by the (European) MouseMan are:
1245 ** - 5 byte packed binary protocol, as with the Mouse Systems
1246 ** mouse. Selected by sequence "*U".
1247 ** - 2 button 3 byte MicroSoft compatible protocol. Selected
1248 ** by sequence "*V".
1249 ** - 3 button 3+1 byte MicroSoft compatible protocol (default).
1250 ** Selected by sequence "*X".
1252 ** The following baud rates are supported:
1253 ** - 1200 Baud (default). Selected by sequence "*n".
1254 ** - 9600 Baud. Selected by sequence "*q".
1256 ** Selecting a sample rate is no longer supported with the MouseMan!
1257 ** Some additional lines in xf86Config.c take care of ill configured
1258 ** baud rates and sample rates. (The user will get an error.)
1261 switch (rodent
.rtype
) {
1263 case MOUSE_PROTO_LOGI
:
1265 * The baud rate selection command must be sent at the current
1266 * baud rate; try all likely settings
1268 setmousespeed(9600, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1269 setmousespeed(4800, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1270 setmousespeed(2400, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1271 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1272 /* select MM series data format */
1273 write(rodent
.mfd
, "S", 1);
1274 setmousespeed(rodent
.baudrate
, rodent
.baudrate
,
1275 rodentcflags
[MOUSE_PROTO_MM
]);
1276 /* select report rate/frequency */
1277 if (rodent
.rate
<= 0) write(rodent
.mfd
, "O", 1);
1278 else if (rodent
.rate
<= 15) write(rodent
.mfd
, "J", 1);
1279 else if (rodent
.rate
<= 27) write(rodent
.mfd
, "K", 1);
1280 else if (rodent
.rate
<= 42) write(rodent
.mfd
, "L", 1);
1281 else if (rodent
.rate
<= 60) write(rodent
.mfd
, "R", 1);
1282 else if (rodent
.rate
<= 85) write(rodent
.mfd
, "M", 1);
1283 else if (rodent
.rate
<= 125) write(rodent
.mfd
, "Q", 1);
1284 else write(rodent
.mfd
, "N", 1);
1287 case MOUSE_PROTO_LOGIMOUSEMAN
:
1288 /* The command must always be sent at 1200 baud */
1289 setmousespeed(1200, 1200, rodentcflags
[rodent
.rtype
]);
1290 write(rodent
.mfd
, "*X", 2);
1291 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1294 case MOUSE_PROTO_HITTAB
:
1295 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1298 * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
1299 * The tablet must be configured to be in MM mode, NO parity,
1300 * Binary Format. xf86Info.sampleRate controls the sensativity
1301 * of the tablet. We only use this tablet for it's 4-button puck
1302 * so we don't run in "Absolute Mode"
1304 write(rodent
.mfd
, "z8", 2); /* Set Parity = "NONE" */
1306 write(rodent
.mfd
, "zb", 2); /* Set Format = "Binary" */
1308 write(rodent
.mfd
, "@", 1); /* Set Report Mode = "Stream" */
1310 write(rodent
.mfd
, "R", 1); /* Set Output Rate = "45 rps" */
1312 write(rodent
.mfd
, "I\x20", 2); /* Set Incrememtal Mode "20" */
1314 write(rodent
.mfd
, "E", 1); /* Set Data Type = "Relative */
1317 /* Resolution is in 'lines per inch' on the Hitachi tablet */
1318 if (rodent
.resolution
== MOUSE_RES_LOW
) c
= 'g';
1319 else if (rodent
.resolution
== MOUSE_RES_MEDIUMLOW
) c
= 'e';
1320 else if (rodent
.resolution
== MOUSE_RES_MEDIUMHIGH
) c
= 'h';
1321 else if (rodent
.resolution
== MOUSE_RES_HIGH
) c
= 'd';
1322 else if (rodent
.resolution
<= 40) c
= 'g';
1323 else if (rodent
.resolution
<= 100) c
= 'd';
1324 else if (rodent
.resolution
<= 200) c
= 'e';
1325 else if (rodent
.resolution
<= 500) c
= 'h';
1326 else if (rodent
.resolution
<= 1000) c
= 'j';
1328 write(rodent
.mfd
, &c
, 1);
1331 write(rodent
.mfd
, "\021", 1); /* Resume DATA output */
1334 case MOUSE_PROTO_THINK
:
1335 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1336 /* the PnP ID string may be sent again, discard it */
1339 ioctl(rodent
.mfd
, TIOCFLUSH
, &i
);
1340 /* send the command to initialize the beast */
1341 set
[0].fd
= rodent
.mfd
;
1342 set
[0].events
= POLLIN
;
1343 for (s
= "E5E5"; *s
; ++s
) {
1344 write(rodent
.mfd
, s
, 1);
1345 if (poll(set
, 1, INFTIM
) <= 0)
1347 read(rodent
.mfd
, &c
, 1);
1354 case MOUSE_PROTO_MSC
:
1355 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1356 if (rodent
.flags
& ClearDTR
) {
1358 ioctl(rodent
.mfd
, TIOCMBIC
, &i
);
1360 if (rodent
.flags
& ClearRTS
) {
1362 ioctl(rodent
.mfd
, TIOCMBIC
, &i
);
1366 case MOUSE_PROTO_SYSMOUSE
:
1367 if (rodent
.hw
.iftype
== MOUSE_IF_SYSMOUSE
)
1368 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1371 case MOUSE_PROTO_BUS
:
1372 case MOUSE_PROTO_INPORT
:
1373 case MOUSE_PROTO_PS2
:
1374 if (rodent
.rate
>= 0)
1375 rodent
.mode
.rate
= rodent
.rate
;
1376 if (rodent
.resolution
!= MOUSE_RES_UNKNOWN
)
1377 rodent
.mode
.resolution
= rodent
.resolution
;
1379 ioctl(rodent
.mfd
, MOUSE_SETMODE
, &rodent
.mode
);
1383 case MOUSE_PROTO_X10MOUSEREM
:
1385 mremote_serversetup();
1387 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1391 case MOUSE_PROTO_VERSAPAD
:
1392 tcsendbreak(rodent
.mfd
, 0); /* send break for 400 msec */
1394 ioctl(rodent
.mfd
, TIOCFLUSH
, &i
);
1395 set
[0].fd
= rodent
.mfd
;
1396 set
[0].events
= POLLIN
;
1397 for (i
= 0; i
< 7; ++i
) {
1398 if (poll(set
, 1, INFTIM
) <= 0)
1400 read(rodent
.mfd
, &c
, 1);
1404 if ((buf
[0] != 'V') || (buf
[1] != 'P')|| (buf
[7] != '\r'))
1406 setmousespeed(9600, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1407 tcsendbreak(rodent
.mfd
, 0); /* send break for 400 msec again */
1408 for (i
= 0; i
< 7; ++i
) {
1409 if (poll(set
, 1, INFTIM
) <= 0)
1411 read(rodent
.mfd
, &c
, 1);
1417 ioctl(rodent
.mfd
, TIOCFLUSH
, &i
);
1421 setmousespeed(1200, rodent
.baudrate
, rodentcflags
[rodent
.rtype
]);
1427 r_protocol(u_char rBuf
, mousestatus_t
*act
)
1429 /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1430 static int butmapmss
[4] = { /* Microsoft, MouseMan, GlidePoint,
1431 IntelliMouse, Thinking Mouse */
1435 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
,
1437 static int butmapmss2
[4] = { /* Microsoft, MouseMan, GlidePoint,
1442 MOUSE_BUTTON2DOWN
| MOUSE_BUTTON4DOWN
,
1444 /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1445 static int butmapintelli
[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
1450 MOUSE_BUTTON2DOWN
| MOUSE_BUTTON4DOWN
,
1452 /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
1453 static int butmapmsc
[8] = { /* MouseSystems, MMSeries, Logitech,
1458 MOUSE_BUTTON2DOWN
| MOUSE_BUTTON3DOWN
,
1460 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
,
1461 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON2DOWN
,
1462 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON2DOWN
| MOUSE_BUTTON3DOWN
1464 /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1465 static int butmapps2
[8] = { /* PS/2 */
1469 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
,
1471 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON2DOWN
,
1472 MOUSE_BUTTON2DOWN
| MOUSE_BUTTON3DOWN
,
1473 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON2DOWN
| MOUSE_BUTTON3DOWN
1475 /* for Hitachi tablet */
1476 static int butmaphit
[8] = { /* MM HitTablet */
1486 /* for serial VersaPad */
1487 static int butmapversa
[8] = { /* VersaPad */
1494 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
,
1495 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
,
1497 /* for PS/2 VersaPad */
1498 static int butmapversaps2
[8] = { /* VersaPad */
1504 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
,
1506 MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
,
1508 static int pBufP
= 0;
1509 static unsigned char pBuf
[8];
1510 static int prev_x
, prev_y
;
1511 static int on
= FALSE
;
1514 debug("received char 0x%x",(int)rBuf
);
1515 if (rodent
.rtype
== MOUSE_PROTO_KIDSPAD
)
1516 return kidspad(rBuf
, act
) ;
1519 * Hack for resyncing: We check here for a package that is:
1520 * a) illegal (detected by wrong data-package header)
1521 * b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
1522 * c) bad header-package
1524 * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
1525 * -128 are allowed, but since they are very seldom we can easily
1526 * use them as package-header with no button pressed.
1527 * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
1528 * 0x80 is not valid as a header byte. For a PS/2 mouse we skip
1529 * checking data bytes.
1530 * For resyncing a PS/2 mouse we require the two most significant
1531 * bits in the header byte to be 0. These are the overflow bits,
1532 * and in case of an overflow we actually lose sync. Overflows
1533 * are very rare, however, and we quickly gain sync again after
1534 * an overflow condition. This is the best we can do. (Actually,
1535 * we could use bit 0x08 in the header byte for resyncing, since
1536 * that bit is supposed to be always on, but nobody told
1540 if (pBufP
!= 0 && rodent
.rtype
!= MOUSE_PROTO_PS2
&&
1541 ((rBuf
& cur_proto
[2]) != cur_proto
[3] || rBuf
== 0x80))
1543 pBufP
= 0; /* skip package */
1546 if (pBufP
== 0 && (rBuf
& cur_proto
[0]) != cur_proto
[1])
1549 /* is there an extra data byte? */
1550 if (pBufP
>= cur_proto
[4] && (rBuf
& cur_proto
[0]) != cur_proto
[1])
1553 * Hack for Logitech MouseMan Mouse - Middle button
1555 * Unfortunately this mouse has variable length packets: the standard
1556 * Microsoft 3 byte packet plus an optional 4th byte whenever the
1557 * middle button status changes.
1559 * We have already processed the standard packet with the movement
1560 * and button info. Now post an event message with the old status
1561 * of the left and right buttons and the updated middle button.
1565 * Even worse, different MouseMen and TrackMen differ in the 4th
1566 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
1567 * 0x02/0x22, so I have to strip off the lower bits.
1570 * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
1571 * and it is activated by tapping the glidepad with the finger! 8^)
1572 * We map it to bit bit3, and the reverse map in xf86Events just has
1573 * to be extended so that it is identified as Button 4. The lower
1574 * half of the reverse-map may remain unchanged.
1579 * Receive the fourth byte only when preceding three bytes have
1580 * been detected (pBufP >= cur_proto[4]). In the previous
1581 * versions, the test was pBufP == 0; thus, we may have mistakingly
1582 * received a byte even if we didn't see anything preceding
1586 if ((rBuf
& cur_proto
[5]) != cur_proto
[6]) {
1591 switch (rodent
.rtype
) {
1593 case MOUSE_PROTO_MARIQUA
:
1595 * This mouse has 16! buttons in addition to the standard
1596 * three of them. They return 0x10 though 0x1f in the
1597 * so-called `ten key' mode and 0x30 though 0x3f in the
1598 * `function key' mode. As there are only 31 bits for
1599 * button state (including the standard three), we ignore
1600 * the bit 0x20 and don't distinguish the two modes.
1602 act
->dx
= act
->dy
= act
->dz
= 0;
1603 act
->obutton
= act
->button
;
1605 act
->button
= (1 << (rBuf
- 13))
1606 | (act
->obutton
& (MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
));
1608 * FIXME: this is a button "down" event. There needs to be
1609 * a corresponding button "up" event... XXX
1615 * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
1616 * always send the fourth byte, whereas the fourth byte is
1617 * optional for GlidePoint and ThinkingMouse. The fourth byte
1618 * is also optional for MouseMan+ and FirstMouse+ in their
1619 * native mode. It is always sent if they are in the IntelliMouse
1622 case MOUSE_PROTO_INTELLI
: /* IntelliMouse, NetMouse, Mie Mouse,
1624 act
->dx
= act
->dy
= 0;
1625 act
->dz
= (rBuf
& 0x08) ? (rBuf
& 0x0f) - 16 : (rBuf
& 0x0f);
1626 if ((act
->dz
>= 7) || (act
->dz
<= -7))
1628 act
->obutton
= act
->button
;
1629 act
->button
= butmapintelli
[(rBuf
& MOUSE_MSS_BUTTONS
) >> 4]
1630 | (act
->obutton
& (MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
));
1634 act
->dx
= act
->dy
= act
->dz
= 0;
1635 act
->obutton
= act
->button
;
1636 act
->button
= butmapmss2
[(rBuf
& MOUSE_MSS_BUTTONS
) >> 4]
1637 | (act
->obutton
& (MOUSE_BUTTON1DOWN
| MOUSE_BUTTON3DOWN
));
1641 act
->flags
= ((act
->dx
|| act
->dy
|| act
->dz
) ? MOUSE_POSCHANGED
: 0)
1642 | (act
->obutton
^ act
->button
);
1647 if (pBufP
>= cur_proto
[4])
1649 pBuf
[pBufP
++] = rBuf
;
1650 if (pBufP
!= cur_proto
[4])
1654 * assembly full package
1657 debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
1659 pBuf
[0], pBuf
[1], pBuf
[2], pBuf
[3],
1660 pBuf
[4], pBuf
[5], pBuf
[6], pBuf
[7]);
1663 act
->obutton
= act
->button
;
1664 switch (rodent
.rtype
)
1666 case MOUSE_PROTO_MS
: /* Microsoft */
1667 case MOUSE_PROTO_LOGIMOUSEMAN
: /* MouseMan/TrackMan */
1668 case MOUSE_PROTO_X10MOUSEREM
: /* X10 MouseRemote */
1669 act
->button
= act
->obutton
& MOUSE_BUTTON4DOWN
;
1670 if (rodent
.flags
& ChordMiddle
)
1671 act
->button
|= ((pBuf
[0] & MOUSE_MSS_BUTTONS
) == MOUSE_MSS_BUTTONS
)
1673 : butmapmss
[(pBuf
[0] & MOUSE_MSS_BUTTONS
) >> 4];
1675 act
->button
|= (act
->obutton
& MOUSE_BUTTON2DOWN
)
1676 | butmapmss
[(pBuf
[0] & MOUSE_MSS_BUTTONS
) >> 4];
1679 /* Send X10 btn events to remote client (ensure -128-+127 range) */
1680 if ((rodent
.rtype
== MOUSE_PROTO_X10MOUSEREM
) &&
1681 ((pBuf
[0] & 0xFC) == 0x44) && (pBuf
[2] == 0x3F)) {
1682 if (rodent
.mremcfd
>= 0) {
1683 unsigned char key
= (signed char)(((pBuf
[0] & 0x03) << 6) |
1685 write( rodent
.mremcfd
, &key
, 1 );
1691 act
->dx
= (char)(((pBuf
[0] & 0x03) << 6) | (pBuf
[1] & 0x3F));
1692 act
->dy
= (char)(((pBuf
[0] & 0x0C) << 4) | (pBuf
[2] & 0x3F));
1695 case MOUSE_PROTO_GLIDEPOINT
: /* GlidePoint */
1696 case MOUSE_PROTO_THINK
: /* ThinkingMouse */
1697 case MOUSE_PROTO_INTELLI
: /* IntelliMouse, NetMouse, Mie Mouse,
1699 act
->button
= (act
->obutton
& (MOUSE_BUTTON2DOWN
| MOUSE_BUTTON4DOWN
))
1700 | butmapmss
[(pBuf
[0] & MOUSE_MSS_BUTTONS
) >> 4];
1701 act
->dx
= (char)(((pBuf
[0] & 0x03) << 6) | (pBuf
[1] & 0x3F));
1702 act
->dy
= (char)(((pBuf
[0] & 0x0C) << 4) | (pBuf
[2] & 0x3F));
1705 case MOUSE_PROTO_MSC
: /* MouseSystems Corp */
1707 case MOUSE_PROTO_MARIQUA
: /* Mariqua */
1709 act
->button
= butmapmsc
[(~pBuf
[0]) & MOUSE_MSC_BUTTONS
];
1710 act
->dx
= (char)(pBuf
[1]) + (char)(pBuf
[3]);
1711 act
->dy
= - ((char)(pBuf
[2]) + (char)(pBuf
[4]));
1714 case MOUSE_PROTO_HITTAB
: /* MM HitTablet */
1715 act
->button
= butmaphit
[pBuf
[0] & 0x07];
1716 act
->dx
= (pBuf
[0] & MOUSE_MM_XPOSITIVE
) ? pBuf
[1] : - pBuf
[1];
1717 act
->dy
= (pBuf
[0] & MOUSE_MM_YPOSITIVE
) ? - pBuf
[2] : pBuf
[2];
1720 case MOUSE_PROTO_MM
: /* MM Series */
1721 case MOUSE_PROTO_LOGI
: /* Logitech Mice */
1722 act
->button
= butmapmsc
[pBuf
[0] & MOUSE_MSC_BUTTONS
];
1723 act
->dx
= (pBuf
[0] & MOUSE_MM_XPOSITIVE
) ? pBuf
[1] : - pBuf
[1];
1724 act
->dy
= (pBuf
[0] & MOUSE_MM_YPOSITIVE
) ? - pBuf
[2] : pBuf
[2];
1727 case MOUSE_PROTO_VERSAPAD
: /* VersaPad */
1728 act
->button
= butmapversa
[(pBuf
[0] & MOUSE_VERSA_BUTTONS
) >> 3];
1729 act
->button
|= (pBuf
[0] & MOUSE_VERSA_TAP
) ? MOUSE_BUTTON4DOWN
: 0;
1730 act
->dx
= act
->dy
= 0;
1731 if (!(pBuf
[0] & MOUSE_VERSA_IN_USE
)) {
1735 x
= (pBuf
[2] << 6) | pBuf
[1];
1738 y
= (pBuf
[4] << 6) | pBuf
[3];
1742 act
->dx
= prev_x
- x
;
1743 act
->dy
= prev_y
- y
;
1751 case MOUSE_PROTO_BUS
: /* Bus */
1752 case MOUSE_PROTO_INPORT
: /* InPort */
1753 act
->button
= butmapmsc
[(~pBuf
[0]) & MOUSE_MSC_BUTTONS
];
1754 act
->dx
= (char)pBuf
[1];
1755 act
->dy
= - (char)pBuf
[2];
1758 case MOUSE_PROTO_PS2
: /* PS/2 */
1759 act
->button
= butmapps2
[pBuf
[0] & MOUSE_PS2_BUTTONS
];
1760 act
->dx
= (pBuf
[0] & MOUSE_PS2_XNEG
) ? pBuf
[1] - 256 : pBuf
[1];
1761 act
->dy
= (pBuf
[0] & MOUSE_PS2_YNEG
) ? -(pBuf
[2] - 256) : -pBuf
[2];
1763 * Moused usually operates the psm driver at the operation level 1
1764 * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
1765 * The following code takes effect only when the user explicitly
1766 * requets the level 2 at which wheel movement and additional button
1767 * actions are encoded in model-dependent formats. At the level 0
1768 * the following code is no-op because the psm driver says the model
1769 * is MOUSE_MODEL_GENERIC.
1771 switch (rodent
.hw
.model
) {
1772 case MOUSE_MODEL_EXPLORER
:
1773 /* wheel and additional button data is in the fourth byte */
1774 act
->dz
= (pBuf
[3] & MOUSE_EXPLORER_ZNEG
)
1775 ? (pBuf
[3] & 0x0f) - 16 : (pBuf
[3] & 0x0f);
1776 act
->button
|= (pBuf
[3] & MOUSE_EXPLORER_BUTTON4DOWN
)
1777 ? MOUSE_BUTTON4DOWN
: 0;
1778 act
->button
|= (pBuf
[3] & MOUSE_EXPLORER_BUTTON5DOWN
)
1779 ? MOUSE_BUTTON5DOWN
: 0;
1781 case MOUSE_MODEL_INTELLI
:
1782 case MOUSE_MODEL_NET
:
1783 /* wheel data is in the fourth byte */
1784 act
->dz
= (char)pBuf
[3];
1785 if ((act
->dz
>= 7) || (act
->dz
<= -7))
1787 /* some compatible mice may have additional buttons */
1788 act
->button
|= (pBuf
[0] & MOUSE_PS2INTELLI_BUTTON4DOWN
)
1789 ? MOUSE_BUTTON4DOWN
: 0;
1790 act
->button
|= (pBuf
[0] & MOUSE_PS2INTELLI_BUTTON5DOWN
)
1791 ? MOUSE_BUTTON5DOWN
: 0;
1793 case MOUSE_MODEL_MOUSEMANPLUS
:
1794 if (((pBuf
[0] & MOUSE_PS2PLUS_SYNCMASK
) == MOUSE_PS2PLUS_SYNC
)
1795 && (abs(act
->dx
) > 191)
1796 && MOUSE_PS2PLUS_CHECKBITS(pBuf
)) {
1797 /* the extended data packet encodes button and wheel events */
1798 switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf
)) {
1800 /* wheel data packet */
1801 act
->dx
= act
->dy
= 0;
1802 if (pBuf
[2] & 0x80) {
1803 /* horizontal roller count - ignore it XXX*/
1805 /* vertical roller count */
1806 act
->dz
= (pBuf
[2] & MOUSE_PS2PLUS_ZNEG
)
1807 ? (pBuf
[2] & 0x0f) - 16 : (pBuf
[2] & 0x0f);
1809 act
->button
|= (pBuf
[2] & MOUSE_PS2PLUS_BUTTON4DOWN
)
1810 ? MOUSE_BUTTON4DOWN
: 0;
1811 act
->button
|= (pBuf
[2] & MOUSE_PS2PLUS_BUTTON5DOWN
)
1812 ? MOUSE_BUTTON5DOWN
: 0;
1815 /* this packet type is reserved by Logitech */
1817 * IBM ScrollPoint Mouse uses this packet type to
1818 * encode both vertical and horizontal scroll movement.
1820 act
->dx
= act
->dy
= 0;
1821 /* horizontal roller count */
1823 act
->dz
= (pBuf
[2] & MOUSE_SPOINT_WNEG
) ? -2 : 2;
1824 /* vertical roller count */
1826 act
->dz
= (pBuf
[2] & MOUSE_SPOINT_ZNEG
) ? -1 : 1;
1828 /* vertical roller count */
1829 act
->dz
= (pBuf
[2] & MOUSE_SPOINT_ZNEG
)
1830 ? ((pBuf
[2] >> 4) & 0x0f) - 16
1831 : ((pBuf
[2] >> 4) & 0x0f);
1832 /* horizontal roller count */
1833 act
->dw
= (pBuf
[2] & MOUSE_SPOINT_WNEG
)
1834 ? (pBuf
[2] & 0x0f) - 16 : (pBuf
[2] & 0x0f);
1838 /* device type packet - shouldn't happen */
1841 act
->dx
= act
->dy
= 0;
1842 act
->button
= act
->obutton
;
1843 debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n",
1844 MOUSE_PS2PLUS_PACKET_TYPE(pBuf
),
1845 pBuf
[0], pBuf
[1], pBuf
[2]);
1849 /* preserve button states */
1850 act
->button
|= act
->obutton
& MOUSE_EXTBUTTONS
;
1853 case MOUSE_MODEL_GLIDEPOINT
:
1854 /* `tapping' action */
1855 act
->button
|= ((pBuf
[0] & MOUSE_PS2_TAP
)) ? 0 : MOUSE_BUTTON4DOWN
;
1857 case MOUSE_MODEL_NETSCROLL
:
1858 /* three addtional bytes encode buttons and wheel events */
1859 act
->button
|= (pBuf
[3] & MOUSE_PS2_BUTTON3DOWN
)
1860 ? MOUSE_BUTTON4DOWN
: 0;
1861 act
->button
|= (pBuf
[3] & MOUSE_PS2_BUTTON1DOWN
)
1862 ? MOUSE_BUTTON5DOWN
: 0;
1863 act
->dz
= (pBuf
[3] & MOUSE_PS2_XNEG
) ? pBuf
[4] - 256 : pBuf
[4];
1865 case MOUSE_MODEL_THINK
:
1866 /* the fourth button state in the first byte */
1867 act
->button
|= (pBuf
[0] & MOUSE_PS2_TAP
) ? MOUSE_BUTTON4DOWN
: 0;
1869 case MOUSE_MODEL_VERSAPAD
:
1870 act
->button
= butmapversaps2
[pBuf
[0] & MOUSE_PS2VERSA_BUTTONS
];
1872 (pBuf
[0] & MOUSE_PS2VERSA_TAP
) ? MOUSE_BUTTON4DOWN
: 0;
1873 act
->dx
= act
->dy
= 0;
1874 if (!(pBuf
[0] & MOUSE_PS2VERSA_IN_USE
)) {
1878 x
= ((pBuf
[4] << 8) & 0xf00) | pBuf
[1];
1881 y
= ((pBuf
[4] << 4) & 0xf00) | pBuf
[2];
1885 act
->dx
= prev_x
- x
;
1886 act
->dy
= prev_y
- y
;
1893 case MOUSE_MODEL_4D
:
1894 act
->dx
= (pBuf
[1] & 0x80) ? pBuf
[1] - 256 : pBuf
[1];
1895 act
->dy
= (pBuf
[2] & 0x80) ? -(pBuf
[2] - 256) : -pBuf
[2];
1896 switch (pBuf
[0] & MOUSE_4D_WHEELBITS
) {
1903 case 0x40: /* 2nd wheel rolling right XXX */
1906 case 0xc0: /* 2nd wheel rolling left XXX */
1911 case MOUSE_MODEL_4DPLUS
:
1912 if ((act
->dx
< 16 - 256) && (act
->dy
> 256 - 16)) {
1913 act
->dx
= act
->dy
= 0;
1914 if (pBuf
[2] & MOUSE_4DPLUS_BUTTON4DOWN
)
1915 act
->button
|= MOUSE_BUTTON4DOWN
;
1916 act
->dz
= (pBuf
[2] & MOUSE_4DPLUS_ZNEG
)
1917 ? ((pBuf
[2] & 0x07) - 8) : (pBuf
[2] & 0x07);
1919 /* preserve previous button states */
1920 act
->button
|= act
->obutton
& MOUSE_EXTBUTTONS
;
1923 case MOUSE_MODEL_GENERIC
:
1929 case MOUSE_PROTO_SYSMOUSE
: /* sysmouse */
1930 act
->button
= butmapmsc
[(~pBuf
[0]) & MOUSE_SYS_STDBUTTONS
];
1931 act
->dx
= (char)(pBuf
[1]) + (char)(pBuf
[3]);
1932 act
->dy
= - ((char)(pBuf
[2]) + (char)(pBuf
[4]));
1933 if (rodent
.level
== 1) {
1934 act
->dz
= ((char)(pBuf
[5] << 1) + (char)(pBuf
[6] << 1))/2;
1935 act
->button
|= ((~pBuf
[7] & MOUSE_SYS_EXTBUTTONS
) << 3);
1943 * We don't reset pBufP here yet, as there may be an additional data
1944 * byte in some protocols. See above.
1947 /* has something changed? */
1948 act
->flags
= ((act
->dx
|| act
->dy
|| act
->dz
) ? MOUSE_POSCHANGED
: 0)
1949 | (act
->obutton
^ act
->button
);
1955 r_statetrans(mousestatus_t
*a1
, mousestatus_t
*a2
, int trans
)
1963 a2
->obutton
= a2
->button
;
1964 a2
->button
= a1
->button
;
1965 a2
->flags
= a1
->flags
;
1968 if (rodent
.flags
& Emulate3Button
) {
1970 debug("state:%d, trans:%d -> state:%d",
1971 mouse_button_state
, trans
,
1972 states
[mouse_button_state
].s
[trans
]);
1974 * Avoid re-ordering button and movement events. While a button
1975 * event is deferred, throw away up to BUTTON2_MAXMOVE movement
1976 * events to allow for mouse jitter. If more movement events
1977 * occur, then complete the deferred button events immediately.
1979 if ((a2
->dx
!= 0 || a2
->dy
!= 0) &&
1980 S_DELAYED(states
[mouse_button_state
].s
[trans
])) {
1981 if (++mouse_move_delayed
> BUTTON2_MAXMOVE
) {
1982 mouse_move_delayed
= 0;
1983 mouse_button_state
=
1984 states
[mouse_button_state
].s
[A_TIMEOUT
];
1987 a2
->dx
= a2
->dy
= 0;
1989 mouse_move_delayed
= 0;
1990 if (mouse_button_state
!= states
[mouse_button_state
].s
[trans
])
1993 gettimeofday(&mouse_button_state_tv
, NULL
);
1994 mouse_button_state
= states
[mouse_button_state
].s
[trans
];
1996 ~(MOUSE_BUTTON1DOWN
| MOUSE_BUTTON2DOWN
| MOUSE_BUTTON3DOWN
);
1997 a2
->button
&= states
[mouse_button_state
].mask
;
1998 a2
->button
|= states
[mouse_button_state
].buttons
;
1999 flags
= a2
->flags
& MOUSE_POSCHANGED
;
2000 flags
|= a2
->obutton
^ a2
->button
;
2001 if (flags
& MOUSE_BUTTON2DOWN
) {
2002 a2
->flags
= flags
& MOUSE_BUTTON2DOWN
;
2010 /* phisical to logical button mapping */
2011 static int p2l
[MOUSE_MAXBUTTON
] = {
2012 MOUSE_BUTTON1DOWN
, MOUSE_BUTTON2DOWN
, MOUSE_BUTTON3DOWN
, MOUSE_BUTTON4DOWN
,
2013 MOUSE_BUTTON5DOWN
, MOUSE_BUTTON6DOWN
, MOUSE_BUTTON7DOWN
, MOUSE_BUTTON8DOWN
,
2014 0x00000100, 0x00000200, 0x00000400, 0x00000800,
2015 0x00001000, 0x00002000, 0x00004000, 0x00008000,
2016 0x00010000, 0x00020000, 0x00040000, 0x00080000,
2017 0x00100000, 0x00200000, 0x00400000, 0x00800000,
2018 0x01000000, 0x02000000, 0x04000000, 0x08000000,
2019 0x10000000, 0x20000000, 0x40000000,
2025 while(isspace((unsigned char)*s
))
2031 r_installmap(char *arg
)
2038 arg
= skipspace(arg
);
2040 while (isdigit((unsigned char)*arg
))
2042 arg
= skipspace(arg
);
2043 if ((arg
<= s
) || (*arg
!= '='))
2047 arg
= skipspace(++arg
);
2049 while (isdigit((unsigned char)*arg
))
2051 if ((arg
<= s
) || (!isspace((unsigned char)*arg
) && (*arg
!= '\0')))
2055 if ((lbutton
<= 0) || (lbutton
> MOUSE_MAXBUTTON
))
2057 if ((pbutton
<= 0) || (pbutton
> MOUSE_MAXBUTTON
))
2059 p2l
[pbutton
- 1] = 1 << (lbutton
- 1);
2060 mstate
[lbutton
- 1] = &bstate
[pbutton
- 1];
2067 r_map(mousestatus_t
*act1
, mousestatus_t
*act2
)
2070 register int pbuttons
;
2073 pbuttons
= act1
->button
;
2076 act2
->obutton
= act2
->button
;
2077 if (pbuttons
& rodent
.wmode
) {
2078 pbuttons
&= ~rodent
.wmode
;
2079 act1
->dz
= act1
->dy
;
2083 act2
->dx
= act1
->dx
;
2084 act2
->dy
= act1
->dy
;
2085 act2
->dz
= act1
->dz
;
2087 switch (rodent
.zmap
[0]) {
2088 case 0: /* do nothing */
2091 if (act1
->dz
!= 0) {
2092 act2
->dx
= act1
->dz
;
2097 if (act1
->dz
!= 0) {
2098 act2
->dy
= act1
->dz
;
2102 default: /* buttons */
2103 pbuttons
&= ~(rodent
.zmap
[0] | rodent
.zmap
[1]
2104 | rodent
.zmap
[2] | rodent
.zmap
[3]);
2105 if ((act1
->dz
< -1) && rodent
.zmap
[2]) {
2106 pbuttons
|= rodent
.zmap
[2];
2107 zstate
[2].count
= 1;
2108 } else if (act1
->dz
< 0) {
2109 pbuttons
|= rodent
.zmap
[0];
2110 zstate
[0].count
= 1;
2111 } else if ((act1
->dz
> 1) && rodent
.zmap
[3]) {
2112 pbuttons
|= rodent
.zmap
[3];
2113 zstate
[3].count
= 1;
2114 } else if (act1
->dz
> 0) {
2115 pbuttons
|= rodent
.zmap
[1];
2116 zstate
[1].count
= 1;
2122 for (pb
= 0; (pb
< MOUSE_MAXBUTTON
) && (pbuttons
!= 0); ++pb
) {
2123 lbuttons
|= (pbuttons
& 1) ? p2l
[pb
] : 0;
2126 act2
->button
= lbuttons
;
2128 act2
->flags
= ((act2
->dx
|| act2
->dy
|| act2
->dz
) ? MOUSE_POSCHANGED
: 0)
2129 | (act2
->obutton
^ act2
->button
);
2133 r_timestamp(mousestatus_t
*act
)
2143 mask
= act
->flags
& MOUSE_BUTTONS
;
2149 gettimeofday(&tv1
, NULL
);
2151 /* double click threshold */
2152 tv2
.tv_sec
= rodent
.clickthreshold
/1000;
2153 tv2
.tv_usec
= (rodent
.clickthreshold
%1000)*1000;
2154 timersub(&tv1
, &tv2
, &tv
);
2155 debug("tv: %ld %ld", tv
.tv_sec
, tv
.tv_usec
);
2157 /* 3 button emulation timeout */
2158 tv2
.tv_sec
= rodent
.button2timeout
/1000;
2159 tv2
.tv_usec
= (rodent
.button2timeout
%1000)*1000;
2160 timersub(&tv1
, &tv2
, &tv3
);
2162 button
= MOUSE_BUTTON1DOWN
;
2163 for (i
= 0; (i
< MOUSE_MAXBUTTON
) && (mask
!= 0); ++i
) {
2165 if (act
->button
& button
) {
2166 /* the button is down */
2168 bstate
[i
].tv
.tv_sec
, bstate
[i
].tv
.tv_usec
);
2169 if (timercmp(&tv
, &bstate
[i
].tv
, >)) {
2170 bstate
[i
].count
= 1;
2176 /* the button is up */
2180 if (act
->button
& button
) {
2181 /* the button has been down */
2182 if (timercmp(&tv3
, &bstate
[i
].tv
, >)) {
2183 bstate
[i
].count
= 1;
2185 act
->flags
|= button
;
2186 debug("button %d timeout", i
+ 1);
2189 /* the button has been up */
2204 if (states
[mouse_button_state
].timeout
)
2206 gettimeofday(&tv1
, NULL
);
2207 tv2
.tv_sec
= rodent
.button2timeout
/1000;
2208 tv2
.tv_usec
= (rodent
.button2timeout
%1000)*1000;
2209 timersub(&tv1
, &tv2
, &tv
);
2210 return timercmp(&tv
, &mouse_button_state_tv
, >);
2213 /* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
2214 /* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
2216 * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
2218 * Permission to use, copy, modify, distribute, and sell this software and its
2219 * documentation for any purpose is hereby granted without fee, provided that
2220 * the above copyright notice appear in all copies and that both that
2221 * copyright notice and this permission notice appear in supporting
2222 * documentation, and that the name of David Dawes
2223 * not be used in advertising or publicity pertaining to distribution of
2224 * the software without specific, written prior permission.
2225 * David Dawes makes no representations about the suitability of this
2226 * software for any purpose. It is provided "as is" without express or
2229 * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
2230 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
2231 * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
2232 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
2233 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
2234 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
2235 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2241 setmousespeed(int old
, int new, unsigned cflag
)
2246 if (tcgetattr(rodent
.mfd
, &tty
) < 0)
2248 logwarn("unable to get status of mouse fd");
2252 tty
.c_iflag
= IGNBRK
| IGNPAR
;
2255 tty
.c_cflag
= (tcflag_t
)cflag
;
2256 tty
.c_cc
[VTIME
] = 0;
2262 cfsetispeed(&tty
, B9600
);
2263 cfsetospeed(&tty
, B9600
);
2266 cfsetispeed(&tty
, B4800
);
2267 cfsetospeed(&tty
, B4800
);
2270 cfsetispeed(&tty
, B2400
);
2271 cfsetospeed(&tty
, B2400
);
2275 cfsetispeed(&tty
, B1200
);
2276 cfsetospeed(&tty
, B1200
);
2279 if (tcsetattr(rodent
.mfd
, TCSADRAIN
, &tty
) < 0)
2281 logwarn("unable to set status of mouse fd");
2289 cfsetispeed(&tty
, B9600
);
2290 cfsetospeed(&tty
, B9600
);
2294 cfsetispeed(&tty
, B4800
);
2295 cfsetospeed(&tty
, B4800
);
2299 cfsetispeed(&tty
, B2400
);
2300 cfsetospeed(&tty
, B2400
);
2305 cfsetispeed(&tty
, B1200
);
2306 cfsetospeed(&tty
, B1200
);
2309 if (rodent
.rtype
== MOUSE_PROTO_LOGIMOUSEMAN
2310 || rodent
.rtype
== MOUSE_PROTO_LOGI
)
2312 if (write(rodent
.mfd
, c
, 2) != 2)
2314 logwarn("unable to write to mouse fd");
2320 if (tcsetattr(rodent
.mfd
, TCSADRAIN
, &tty
) < 0)
2321 logwarn("unable to set status of mouse fd");
2325 * PnP COM device support
2327 * It's a simplistic implementation, but it works :-)
2332 * Try to elicit a PnP ID as described in
2333 * Microsoft, Hayes: "Plug and Play External COM Device Specification,
2336 * The routine does not fully implement the COM Enumerator as par Section
2337 * 2.1 of the document. In particular, we don't have idle state in which
2338 * the driver software monitors the com port for dynamic connection or
2339 * removal of a device at the port, because `moused' simply quits if no
2342 * In addition, as PnP COM device enumeration procedure slightly has
2343 * changed since its first publication, devices which follow earlier
2344 * revisions of the above spec. may fail to respond if the rev 1.0
2345 * procedure is used. XXX
2350 struct pollfd set
[1];
2354 * This is the procedure described in rev 1.0 of PnP COM device spec.
2355 * Unfortunately, some devices which comform to earlier revisions of
2356 * the spec gets confused and do not return the ID string...
2358 debug("PnP COM device rev 1.0 probe...");
2360 /* port initialization (2.1.2) */
2361 ioctl(rodent
.mfd
, TIOCMGET
, &i
);
2362 i
|= TIOCM_DTR
; /* DTR = 1 */
2363 i
&= ~TIOCM_RTS
; /* RTS = 0 */
2364 ioctl(rodent
.mfd
, TIOCMSET
, &i
);
2368 * The PnP COM device spec. dictates that the mouse must set DSR
2369 * in response to DTR (by hardware or by software) and that if DSR is
2370 * not asserted, the host computer should think that there is no device
2371 * at this serial port. But some mice just don't do that...
2373 ioctl(rodent
.mfd
, TIOCMGET
, &i
);
2374 debug("modem status 0%o", i
);
2375 if ((i
& TIOCM_DSR
) == 0)
2378 /* port setup, 1st phase (2.1.3) */
2379 setmousespeed(1200, 1200, (CS7
| CREAD
| CLOCAL
| HUPCL
));
2380 i
= TIOCM_DTR
| TIOCM_RTS
; /* DTR = 0, RTS = 0 */
2381 ioctl(rodent
.mfd
, TIOCMBIC
, &i
);
2383 i
= TIOCM_DTR
; /* DTR = 1, RTS = 0 */
2384 ioctl(rodent
.mfd
, TIOCMBIS
, &i
);
2387 /* wait for response, 1st phase (2.1.4) */
2389 ioctl(rodent
.mfd
, TIOCFLUSH
, &i
);
2390 i
= TIOCM_RTS
; /* DTR = 1, RTS = 1 */
2391 ioctl(rodent
.mfd
, TIOCMBIS
, &i
);
2393 /* try to read something */
2394 set
[0].fd
= rodent
.mfd
;
2395 set
[0].events
= POLLIN
;
2396 if (poll(set
, 1, 240) > 0) {
2397 debug("pnpwakeup1(): valid response in first phase.");
2401 /* port setup, 2nd phase (2.1.5) */
2402 i
= TIOCM_DTR
| TIOCM_RTS
; /* DTR = 0, RTS = 0 */
2403 ioctl(rodent
.mfd
, TIOCMBIC
, &i
);
2406 /* wait for respose, 2nd phase (2.1.6) */
2408 ioctl(rodent
.mfd
, TIOCFLUSH
, &i
);
2409 i
= TIOCM_DTR
| TIOCM_RTS
; /* DTR = 1, RTS = 1 */
2410 ioctl(rodent
.mfd
, TIOCMBIS
, &i
);
2412 /* try to read something */
2413 if (poll(set
, 1, 240) > 0) {
2414 debug("pnpwakeup1(): valid response in second phase.");
2424 struct pollfd set
[1];
2428 * This is a simplified procedure; it simply toggles RTS.
2430 debug("alternate probe...");
2432 ioctl(rodent
.mfd
, TIOCMGET
, &i
);
2433 i
|= TIOCM_DTR
; /* DTR = 1 */
2434 i
&= ~TIOCM_RTS
; /* RTS = 0 */
2435 ioctl(rodent
.mfd
, TIOCMSET
, &i
);
2438 setmousespeed(1200, 1200, (CS7
| CREAD
| CLOCAL
| HUPCL
));
2440 /* wait for respose */
2442 ioctl(rodent
.mfd
, TIOCFLUSH
, &i
);
2443 i
= TIOCM_DTR
| TIOCM_RTS
; /* DTR = 1, RTS = 1 */
2444 ioctl(rodent
.mfd
, TIOCMBIS
, &i
);
2446 /* try to read something */
2447 set
[0].fd
= rodent
.mfd
;
2448 set
[0].events
= POLLIN
;
2449 if (poll(set
, 1, 240) > 0) {
2450 debug("pnpwakeup2(): valid response.");
2460 struct pollfd set
[1];
2465 if (!pnpwakeup1() && !pnpwakeup2()) {
2467 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2468 * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
2469 * assuming there is something at the port even if it didn't
2470 * respond to the PnP enumeration procedure.
2472 i
= TIOCM_DTR
| TIOCM_RTS
; /* DTR = 1, RTS = 1 */
2473 ioctl(rodent
.mfd
, TIOCMBIS
, &i
);
2477 /* collect PnP COM device ID (2.1.7) */
2480 usleep(240000); /* the mouse must send `Begin ID' within 200msec */
2481 while (read(rodent
.mfd
, &c
, 1) == 1) {
2482 /* we may see "M", or "M3..." before `Begin ID' */
2484 if ((c
== 0x08) || (c
== 0x28)) { /* Begin ID */
2485 debug("begin-id %02x", c
);
2489 debug("%c %02x", c
, c
);
2494 /* we haven't seen `Begin ID' in time... */
2498 ++c
; /* make it `End ID' */
2499 set
[0].fd
= rodent
.mfd
;
2500 set
[0].events
= POLLIN
;
2502 if (poll(set
, 1, 240) <= 0)
2505 read(rodent
.mfd
, &buf
[i
], 1);
2506 if (buf
[i
++] == c
) /* End ID */
2513 bcopy(&buf
[begin
], &buf
[0], i
);
2515 /* string may not be human readable... */
2516 debug("len:%d, '%-*.*s'", i
, i
, i
, buf
);
2518 if (buf
[i
- 1] == c
)
2519 return i
; /* a valid PnP string */
2522 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2523 * in idle state. But, `moused' shall leave the modem control lines
2524 * as they are. See above.
2528 /* we may still have something in the buffer */
2529 return ((i
> 0) ? i
: 0);
2533 pnpparse(pnpid_t
*id
, char *buf
, int len
)
2545 id
->description
= NULL
;
2550 id
->ndescription
= 0;
2552 if ((buf
[0] != 0x28) && (buf
[0] != 0x08)) {
2557 case 'M': /* Microsoft */
2558 id
->eisaid
= "PNP0F01";
2560 case 'H': /* MouseSystems */
2561 id
->eisaid
= "PNP0F04";
2564 id
->neisaid
= strlen(id
->eisaid
);
2565 id
->class = "MOUSE";
2566 id
->nclass
= strlen(id
->class);
2567 debug("non-PnP mouse '%c'", buf
[0]);
2572 offset
= 0x28 - buf
[0];
2574 /* calculate checksum */
2575 for (i
= 0; i
< len
- 3; ++i
) {
2579 sum
+= buf
[len
- 1];
2580 for (; i
< len
; ++i
)
2582 debug("PnP ID string: '%*.*s'", len
, len
, buf
);
2587 id
->revision
= ((buf
[1] & 0x3f) << 6) | (buf
[2] & 0x3f);
2588 debug("PnP rev %d.%02d", id
->revision
/ 100, id
->revision
% 100);
2590 /* EISA vender and product ID */
2591 id
->eisaid
= &buf
[3];
2594 /* option strings */
2596 if (buf
[i
] == '\\') {
2597 /* device serial # */
2598 for (j
= ++i
; i
< len
; ++i
) {
2605 id
->serial
= &buf
[j
];
2609 if (buf
[i
] == '\\') {
2611 for (j
= ++i
; i
< len
; ++i
) {
2618 id
->class = &buf
[j
];
2622 if (buf
[i
] == '\\') {
2623 /* compatible driver */
2624 for (j
= ++i
; i
< len
; ++i
) {
2629 * PnP COM spec prior to v0.96 allowed '*' in this field,
2630 * it's not allowed now; just igore it.
2637 id
->compat
= &buf
[j
];
2638 id
->ncompat
= i
- j
;
2641 if (buf
[i
] == '\\') {
2642 /* product description */
2643 for (j
= ++i
; i
< len
; ++i
) {
2650 id
->description
= &buf
[j
];
2651 id
->ndescription
= i
- j
;
2655 /* checksum exists if there are any optional fields */
2656 if ((id
->nserial
> 0) || (id
->nclass
> 0)
2657 || (id
->ncompat
> 0) || (id
->ndescription
> 0)) {
2658 debug("PnP checksum: 0x%X", sum
);
2659 snprintf(s
, sizeof(s
), "%02X", sum
& 0x0ff);
2660 if (strncmp(s
, &buf
[len
- 3], 2) != 0) {
2663 * I found some mice do not comply with the PnP COM device
2664 * spec regarding checksum... XXX
2666 logwarnx("PnP checksum error", 0);
2676 pnpproto(pnpid_t
*id
)
2682 if ( strncmp(id
->class, "MOUSE", id
->nclass
) != 0 &&
2683 strncmp(id
->class, "TABLET", id
->nclass
) != 0)
2684 /* this is not a mouse! */
2687 if (id
->neisaid
> 0) {
2688 t
= gettoken(pnpprod
, id
->eisaid
, id
->neisaid
);
2689 if (t
->val
!= MOUSE_PROTO_UNKNOWN
)
2694 * The 'Compatible drivers' field may contain more than one
2695 * ID separated by ','.
2697 if (id
->ncompat
<= 0)
2699 for (i
= 0; i
< id
->ncompat
; ++i
) {
2700 for (j
= i
; id
->compat
[i
] != ','; ++i
)
2701 if (i
>= id
->ncompat
)
2704 t
= gettoken(pnpprod
, id
->compat
+ j
, i
- j
);
2705 if (t
->val
!= MOUSE_PROTO_UNKNOWN
)
2713 /* name/val mapping */
2716 gettoken(symtab_t
*tab
, const char *s
, int len
)
2720 for (i
= 0; tab
[i
].name
!= NULL
; ++i
) {
2721 if (strncmp(tab
[i
].name
, s
, len
) == 0)
2728 gettokenname(symtab_t
*tab
, int val
)
2732 for (i
= 0; tab
[i
].name
!= NULL
; ++i
) {
2733 if (tab
[i
].val
== val
)
2741 * code to read from the Genius Kidspad tablet.
2743 The tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005,
2744 and to pre-pnp probes (RTS toggle) with 'T' (tablet ?)
2745 9600, 8 bit, parity odd.
2747 The tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains
2748 the proximity, tip and button info:
2749 (byte0 & 0x1) true = tip pressed
2750 (byte0 & 0x2) true = button pressed
2751 (byte0 & 0x40) false = pen in proximity of tablet.
2753 The next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid).
2755 Only absolute coordinates are returned, so we use the following approach:
2756 we store the last coordinates sent when the pen went out of the tablet,
2763 S_IDLE
, S_PROXY
, S_FIRST
, S_DOWN
, S_UP
2767 kidspad(u_char rxc
, mousestatus_t
*act
)
2770 static int buflen
= 0, b_prev
= 0 , x_prev
= -1, y_prev
= -1 ;
2771 static k_status status
= S_IDLE
;
2772 static struct timeval old
, now
;
2776 if (buflen
> 0 && (rxc
& 0x80) ) {
2777 fprintf(stderr
, "invalid code %d 0x%x\n", buflen
, rxc
);
2780 if (buflen
== 0 && (rxc
& 0xb8) != 0xb8 ) {
2781 fprintf(stderr
, "invalid code 0 0x%x\n", rxc
);
2782 return 0 ; /* invalid code, no action */
2784 buf
[buflen
++] = rxc
;
2788 buflen
= 0 ; /* for next time... */
2790 x
= buf
[1]+128*(buf
[2] - 7) ;
2792 y
= 28*128 - (buf
[3] + 128* (buf
[4] - 7)) ;
2799 act
->obutton
= act
->button
;
2800 act
->dx
= act
->dy
= act
->dz
= 0 ;
2801 gettimeofday(&now
, NULL
);
2802 if ( buf
[0] & 0x40 ) /* pen went out of reach */
2804 else if (status
== S_IDLE
) { /* pen is newly near the tablet */
2805 act
->flags
|= MOUSE_POSCHANGED
; /* force update */
2811 act
->dx
= x
- x_prev
;
2812 act
->dy
= y
- y_prev
;
2813 if (act
->dx
|| act
->dy
)
2814 act
->flags
|= MOUSE_POSCHANGED
;
2817 if (b_prev
!= 0 && b_prev
!= buf
[0]) { /* possibly record button change */
2819 if ( buf
[0] & 0x01 ) /* tip pressed */
2820 act
->button
|= MOUSE_BUTTON1DOWN
;
2821 if ( buf
[0] & 0x02 ) /* button pressed */
2822 act
->button
|= MOUSE_BUTTON2DOWN
;
2823 act
->flags
|= MOUSE_BUTTONSCHANGED
;