1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32#include <math.h>
33#include <X11/X.h>
34#include <X11/Xproto.h>
35#include <X11/keysym.h>
36#include "exglobals.h"
37#include <X11/extensions/XIproto.h>
38#include "inputstr.h"
39#include "eventstr.h"
40#include <xkbsrv.h>
41#if !defined(WIN32)
42#include <sys/time.h>
43#endif
44
45int	XkbDfltRepeatDelay=	660;
46int	XkbDfltRepeatInterval=	40;
47
48#define	DFLT_TIMEOUT_CTRLS (XkbAX_KRGMask|XkbStickyKeysMask|XkbMouseKeysMask)
49#define	DFLT_TIMEOUT_OPTS  (XkbAX_IndicatorFBMask)
50
51unsigned short	XkbDfltAccessXTimeout= 	120;
52unsigned int	XkbDfltAccessXTimeoutMask= DFLT_TIMEOUT_CTRLS;
53static unsigned int XkbDfltAccessXTimeoutValues= 0;
54static unsigned int XkbDfltAccessXTimeoutOptionsMask= DFLT_TIMEOUT_OPTS;
55static unsigned int XkbDfltAccessXTimeoutOptionsValues= 0;
56unsigned int	XkbDfltAccessXFeedback= XkbAccessXFeedbackMask;
57unsigned short	XkbDfltAccessXOptions=  XkbAX_AllOptionsMask & ~(XkbAX_IndicatorFBMask|XkbAX_SKReleaseFBMask|XkbAX_SKRejectFBMask);
58
59void
60AccessXComputeCurveFactor(XkbSrvInfoPtr xkbi,XkbControlsPtr ctrls)
61{
62    xkbi->mouseKeysCurve= 1.0+(((double)ctrls->mk_curve)*0.001);
63    xkbi->mouseKeysCurveFactor= ( ((double)ctrls->mk_max_speed)/
64	pow((double)ctrls->mk_time_to_max,xkbi->mouseKeysCurve));
65    return;
66}
67
68void
69AccessXInit(DeviceIntPtr keybd)
70{
71XkbSrvInfoPtr	xkbi = keybd->key->xkbInfo;
72XkbControlsPtr	ctrls = xkbi->desc->ctrls;
73
74    xkbi->shiftKeyCount= 0;
75    xkbi->mouseKeysCounter= 0;
76    xkbi->inactiveKey= 0;
77    xkbi->slowKey= 0;
78    xkbi->repeatKey= 0;
79    xkbi->krgTimerActive= _OFF_TIMER;
80    xkbi->beepType= _BEEP_NONE;
81    xkbi->beepCount= 0;
82    xkbi->mouseKeyTimer= NULL;
83    xkbi->slowKeysTimer= NULL;
84    xkbi->bounceKeysTimer= NULL;
85    xkbi->repeatKeyTimer= NULL;
86    xkbi->krgTimer= NULL;
87    xkbi->beepTimer= NULL;
88    ctrls->repeat_delay = XkbDfltRepeatDelay;
89    ctrls->repeat_interval = XkbDfltRepeatInterval;
90    ctrls->debounce_delay = 300;
91    ctrls->slow_keys_delay = 300;
92    ctrls->mk_delay = 160;
93    ctrls->mk_interval = 40;
94    ctrls->mk_time_to_max = 30;
95    ctrls->mk_max_speed = 30;
96    ctrls->mk_curve = 500;
97    ctrls->mk_dflt_btn = 1;
98    ctrls->ax_timeout = XkbDfltAccessXTimeout;
99    ctrls->axt_ctrls_mask = XkbDfltAccessXTimeoutMask;
100    ctrls->axt_ctrls_values = XkbDfltAccessXTimeoutValues;
101    ctrls->axt_opts_mask = XkbDfltAccessXTimeoutOptionsMask;
102    ctrls->axt_opts_values = XkbDfltAccessXTimeoutOptionsValues;
103    if (XkbDfltAccessXTimeout)
104	ctrls->enabled_ctrls |= XkbAccessXTimeoutMask;
105    else
106	ctrls->enabled_ctrls &= ~XkbAccessXTimeoutMask;
107    ctrls->enabled_ctrls |= XkbDfltAccessXFeedback;
108    ctrls->ax_options = XkbDfltAccessXOptions;
109    AccessXComputeCurveFactor(xkbi,ctrls);
110    return;
111}
112
113/************************************************************************/
114/*									*/
115/* AccessXKeyboardEvent							*/
116/*									*/
117/*	Generate a synthetic keyboard event.				*/
118/*									*/
119/************************************************************************/
120static void
121AccessXKeyboardEvent(DeviceIntPtr	keybd,
122				 int		type,
123				 BYTE		keyCode,
124				 Bool		isRepeat)
125{
126    DeviceEvent event;
127    memset(&event, 0, sizeof(DeviceEvent));
128    event.header = ET_Internal;
129    event.type = type;
130    event.detail.key = keyCode;
131    event.time = GetTimeInMillis();
132    event.length = sizeof(DeviceEvent);
133    event.key_repeat = isRepeat;
134    event.sourceid = keybd->id;
135    event.deviceid = keybd->id;
136
137    if (xkbDebugFlags&0x8) {
138	DebugF("[xkb] AXKE: Key %d %s\n", keyCode,
139               (event.type == ET_KeyPress ? "down" : "up"));
140    }
141
142    XkbProcessKeyboardEvent(&event, keybd);
143    return;
144} /* AccessXKeyboardEvent */
145
146/************************************************************************/
147/*									*/
148/* AccessXKRGTurnOn							*/
149/*									*/
150/*	Turn the keyboard response group on.				*/
151/*									*/
152/************************************************************************/
153static void
154AccessXKRGTurnOn(DeviceIntPtr dev,CARD16 KRGControl,xkbControlsNotify	*pCN)
155{
156XkbSrvInfoPtr		xkbi = dev->key->xkbInfo;
157XkbControlsPtr		ctrls = xkbi->desc->ctrls;
158XkbControlsRec		old;
159XkbEventCauseRec	cause;
160XkbSrvLedInfoPtr	sli;
161
162    old= *ctrls;
163    ctrls->enabled_ctrls |= (KRGControl&XkbAX_KRGMask);
164    if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
165	XkbSendControlsNotify(dev,pCN);
166    cause.kc=		pCN->keycode;
167    cause.event=	pCN->eventType;
168    cause.mjr=		pCN->requestMajor;
169    cause.mnr=		pCN->requestMinor;
170    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
171    XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
172    if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
173	XkbDDXAccessXBeep(dev,_BEEP_FEATURE_ON,KRGControl);
174    return;
175
176} /* AccessXKRGTurnOn */
177
178/************************************************************************/
179/*									*/
180/* AccessXKRGTurnOff							*/
181/*									*/
182/*	Turn the keyboard response group off.				*/
183/*									*/
184/************************************************************************/
185static void
186AccessXKRGTurnOff(DeviceIntPtr dev,xkbControlsNotify *pCN)
187{
188XkbSrvInfoPtr		xkbi = dev->key->xkbInfo;
189XkbControlsPtr		ctrls = xkbi->desc->ctrls;
190XkbControlsRec		old;
191XkbEventCauseRec	cause;
192XkbSrvLedInfoPtr	sli;
193
194    old = *ctrls;
195    ctrls->enabled_ctrls &= ~XkbAX_KRGMask;
196    if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
197	XkbSendControlsNotify(dev,pCN);
198    cause.kc=		pCN->keycode;
199    cause.event=	pCN->eventType;
200    cause.mjr=		pCN->requestMajor;
201    cause.mnr=		pCN->requestMinor;
202    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
203    XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
204    if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) {
205	unsigned changes= old.enabled_ctrls^ctrls->enabled_ctrls;
206	XkbDDXAccessXBeep(dev,_BEEP_FEATURE_OFF,changes);
207    }
208    return;
209
210} /* AccessXKRGTurnOff */
211
212/************************************************************************/
213/*									*/
214/* AccessXStickyKeysTurnOn						*/
215/*									*/
216/*	Turn StickyKeys on.						*/
217/*									*/
218/************************************************************************/
219static void
220AccessXStickyKeysTurnOn(DeviceIntPtr dev,xkbControlsNotify *pCN)
221{
222XkbSrvInfoPtr		xkbi = dev->key->xkbInfo;
223XkbControlsPtr		ctrls = xkbi->desc->ctrls;
224XkbControlsRec		old;
225XkbEventCauseRec	cause;
226XkbSrvLedInfoPtr	sli;
227
228    old = *ctrls;
229    ctrls->enabled_ctrls |= XkbStickyKeysMask;
230    xkbi->shiftKeyCount = 0;
231    if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
232	XkbSendControlsNotify(dev,pCN);
233    cause.kc=		pCN->keycode;
234    cause.event=	pCN->eventType;
235    cause.mjr=		pCN->requestMajor;
236    cause.mnr=		pCN->requestMinor;
237    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
238    XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
239    if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) {
240	XkbDDXAccessXBeep(dev,_BEEP_FEATURE_ON,XkbStickyKeysMask);
241    }
242    return;
243
244} /* AccessXStickyKeysTurnOn */
245
246/************************************************************************/
247/*									*/
248/* AccessXStickyKeysTurnOff						*/
249/*									*/
250/*	Turn StickyKeys off.						*/
251/*									*/
252/************************************************************************/
253static void
254AccessXStickyKeysTurnOff(DeviceIntPtr dev,xkbControlsNotify *pCN)
255{
256XkbSrvInfoPtr		xkbi = dev->key->xkbInfo;
257XkbControlsPtr		ctrls = xkbi->desc->ctrls;
258XkbControlsRec		old;
259XkbEventCauseRec	cause;
260XkbSrvLedInfoPtr	sli;
261
262    old = *ctrls;
263    ctrls->enabled_ctrls &= ~XkbStickyKeysMask;
264    xkbi->shiftKeyCount = 0;
265    if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
266	XkbSendControlsNotify(dev,pCN);
267
268    cause.kc=		pCN->keycode;
269    cause.event=	pCN->eventType;
270    cause.mjr=		pCN->requestMajor;
271    cause.mnr=		pCN->requestMinor;
272    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
273    XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
274    if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) {
275	XkbDDXAccessXBeep(dev,_BEEP_FEATURE_OFF,XkbStickyKeysMask);
276    }
277#ifndef NO_CLEAR_LATCHES_FOR_STICKY_KEYS_OFF
278    XkbClearAllLatchesAndLocks(dev,xkbi,FALSE,&cause);
279#endif
280    return;
281} /* AccessXStickyKeysTurnOff */
282
283static CARD32
284AccessXKRGExpire(OsTimerPtr timer,CARD32 now,pointer arg)
285{
286XkbSrvInfoPtr		xkbi= ((DeviceIntPtr)arg)->key->xkbInfo;
287xkbControlsNotify	cn;
288
289    if (xkbi->krgTimerActive==_KRG_WARN_TIMER) {
290	XkbDDXAccessXBeep((DeviceIntPtr)arg,_BEEP_SLOW_WARN,XkbStickyKeysMask);
291	xkbi->krgTimerActive= _KRG_TIMER;
292	return 4000;
293    }
294    xkbi->krgTimerActive= _OFF_TIMER;
295    cn.keycode = 0;
296    cn.eventType = 0;
297    cn.requestMajor = 0;
298    cn.requestMinor = 0;
299    if (xkbi->desc->ctrls->enabled_ctrls&XkbSlowKeysMask)
300	 AccessXKRGTurnOff((DeviceIntPtr)arg,&cn);
301    else AccessXKRGTurnOn((DeviceIntPtr)arg,XkbSlowKeysMask,&cn);
302    return 0;
303}
304
305static CARD32
306AccessXRepeatKeyExpire(OsTimerPtr timer,CARD32 now,pointer arg)
307{
308DeviceIntPtr    dev = (DeviceIntPtr) arg;
309XkbSrvInfoPtr	xkbi = dev->key->xkbInfo;
310
311    if (xkbi->repeatKey == 0)
312	return 0;
313
314    AccessXKeyboardEvent(dev, ET_KeyPress, xkbi->repeatKey, TRUE);
315
316    return xkbi->desc->ctrls->repeat_interval;
317}
318
319void
320AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi,KeyCode key)
321{
322    if (xkbi->repeatKey==key)
323	xkbi->repeatKey= 0;
324    return;
325}
326
327static CARD32
328AccessXSlowKeyExpire(OsTimerPtr timer,CARD32 now,pointer arg)
329{
330DeviceIntPtr	keybd;
331XkbSrvInfoPtr	xkbi;
332XkbDescPtr	xkb;
333XkbControlsPtr	ctrls;
334
335    keybd= 	(DeviceIntPtr)arg;
336    xkbi= 	keybd->key->xkbInfo;
337    xkb= 	xkbi->desc;
338    ctrls= 	xkb->ctrls;
339    if (xkbi->slowKey!=0) {
340	xkbAccessXNotify ev;
341	KeySym *sym= XkbKeySymsPtr(xkb,xkbi->slowKey);
342	ev.detail= XkbAXN_SKAccept;
343	ev.keycode= xkbi->slowKey;
344	ev.slowKeysDelay= ctrls->slow_keys_delay;
345	ev.debounceDelay= ctrls->debounce_delay;
346	XkbSendAccessXNotify(keybd,&ev);
347	if (XkbAX_NeedFeedback(ctrls,XkbAX_SKAcceptFBMask))
348	    XkbDDXAccessXBeep(keybd,_BEEP_SLOW_ACCEPT,XkbSlowKeysMask);
349	AccessXKeyboardEvent(keybd, ET_KeyPress,xkbi->slowKey,FALSE);
350	/* check for magic sequences */
351	if ((ctrls->enabled_ctrls&XkbAccessXKeysMask) &&
352	    ((sym[0]==XK_Shift_R)||(sym[0]==XK_Shift_L)))
353	    xkbi->shiftKeyCount++;
354
355	/* Start repeating if necessary.  Stop autorepeating if the user
356	 * presses a non-modifier key that doesn't autorepeat.
357	 */
358	if (keybd->kbdfeed->ctrl.autoRepeat &&
359	    ((xkbi->slowKey != xkbi->mouseKey) || (!xkbi->mouseKeysAccel)) &&
360	     (ctrls->enabled_ctrls&XkbRepeatKeysMask)) {
361	    if (BitIsOn(keybd->kbdfeed->ctrl.autoRepeats,xkbi->slowKey)) {
362		xkbi->repeatKey = xkbi->slowKey;
363		xkbi->repeatKeyTimer= TimerSet(xkbi->repeatKeyTimer,
364					0, ctrls->repeat_delay,
365					AccessXRepeatKeyExpire, (pointer)keybd);
366	    }
367	}
368    }
369    return 0;
370}
371
372static CARD32
373AccessXBounceKeyExpire(OsTimerPtr timer,CARD32 now,pointer arg)
374{
375XkbSrvInfoPtr	xkbi= ((DeviceIntPtr)arg)->key->xkbInfo;
376
377    xkbi->inactiveKey= 0;
378    return 0;
379}
380
381static CARD32
382AccessXTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg)
383{
384DeviceIntPtr		dev = (DeviceIntPtr)arg;
385XkbSrvInfoPtr		xkbi= dev->key->xkbInfo;
386XkbControlsPtr		ctrls= xkbi->desc->ctrls;
387XkbControlsRec		old;
388xkbControlsNotify	cn;
389XkbEventCauseRec	cause;
390XkbSrvLedInfoPtr	sli;
391
392    if (xkbi->lastPtrEventTime) {
393	unsigned timeToWait = (ctrls->ax_timeout*1000);
394	unsigned timeElapsed = (now-xkbi->lastPtrEventTime);
395
396	if (timeToWait > timeElapsed)
397	    return timeToWait - timeElapsed;
398    }
399    old= *ctrls;
400    xkbi->shiftKeyCount= 0;
401    ctrls->enabled_ctrls&= ~ctrls->axt_ctrls_mask;
402    ctrls->enabled_ctrls|=
403	(ctrls->axt_ctrls_values&ctrls->axt_ctrls_mask);
404    if (ctrls->axt_opts_mask) {
405	ctrls->ax_options&= ~ctrls->axt_opts_mask;
406	ctrls->ax_options|= (ctrls->axt_opts_values&ctrls->axt_opts_mask);
407    }
408    if (XkbComputeControlsNotify(dev,&old,ctrls,&cn,FALSE)) {
409	cn.keycode = 0;
410	cn.eventType = 0;
411	cn.requestMajor = 0;
412	cn.requestMinor = 0;
413	XkbSendControlsNotify(dev,&cn);
414    }
415    XkbSetCauseUnknown(&cause);
416    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
417    XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
418    if (ctrls->ax_options!=old.ax_options) {
419	unsigned set,cleared,bell;
420	set= ctrls->ax_options&(~old.ax_options);
421	cleared= (~ctrls->ax_options)&old.ax_options;
422	if (set && cleared)	bell= _BEEP_FEATURE_CHANGE;
423	else if (set)		bell= _BEEP_FEATURE_ON;
424	else 			bell= _BEEP_FEATURE_OFF;
425	XkbDDXAccessXBeep(dev,bell,XkbAccessXTimeoutMask);
426    }
427    xkbi->krgTimerActive= _OFF_TIMER;
428    return 0;
429}
430
431
432/************************************************************************/
433/*									*/
434/* AccessXFilterPressEvent						*/
435/*									*/
436/* Filter events before they get any further if SlowKeys is turned on.	*/
437/* In addition, this routine handles the ever so popular magic key	*/
438/* acts for turning various accessibility features on/off.		*/
439/*									*/
440/* Returns TRUE if this routine has discarded the event.		*/
441/* Returns FALSE if the event needs further processing.			*/
442/*									*/
443/************************************************************************/
444Bool
445AccessXFilterPressEvent(	DeviceEvent*	event,
446				DeviceIntPtr	keybd)
447{
448XkbSrvInfoPtr	xkbi = keybd->key->xkbInfo;
449XkbControlsPtr	ctrls = xkbi->desc->ctrls;
450Bool		ignoreKeyEvent = FALSE;
451KeyCode		key = event->detail.key;
452KeySym *	sym = XkbKeySymsPtr(xkbi->desc,key);
453
454    if (ctrls->enabled_ctrls&XkbAccessXKeysMask) {
455	/* check for magic sequences */
456	if ((sym[0]==XK_Shift_R)||(sym[0]==XK_Shift_L)) {
457	    if (XkbAX_NeedFeedback(ctrls,XkbAX_SlowWarnFBMask)) {
458		xkbi->krgTimerActive = _KRG_WARN_TIMER;
459		xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0, 4000,
460					AccessXKRGExpire, (pointer)keybd);
461	    }
462	    else {
463		xkbi->krgTimerActive = _KRG_TIMER;
464		xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0, 8000,
465					AccessXKRGExpire, (pointer)keybd);
466	    }
467	    if (!(ctrls->enabled_ctrls & XkbSlowKeysMask)) {
468		CARD32 now= GetTimeInMillis();
469		if ((now-xkbi->lastShiftEventTime)>15000)
470		     xkbi->shiftKeyCount= 1;
471		else xkbi->shiftKeyCount++;
472		xkbi->lastShiftEventTime= now;
473	    }
474	}
475	else {
476	    if (xkbi->krgTimerActive) {
477		xkbi->krgTimer= TimerSet(xkbi->krgTimer,0, 0, NULL, NULL);
478		xkbi->krgTimerActive= _OFF_TIMER;
479	    }
480	}
481    }
482
483    /* Don't transmit the KeyPress if SlowKeys is turned on;
484     * The wakeup handler will synthesize one for us if the user
485     * has held the key long enough.
486     */
487    if (ctrls->enabled_ctrls & XkbSlowKeysMask) {
488	xkbAccessXNotify	ev;
489	/* If key was already pressed, ignore subsequent press events
490	 * from the server's autorepeat
491	 */
492	if(xkbi->slowKey == key)
493	    return TRUE;
494	ev.detail= XkbAXN_SKPress;
495	ev.keycode= key;
496	ev.slowKeysDelay= ctrls->slow_keys_delay;
497	ev.debounceDelay= ctrls->debounce_delay;
498	XkbSendAccessXNotify(keybd,&ev);
499	if (XkbAX_NeedFeedback(ctrls,XkbAX_SKPressFBMask))
500	    XkbDDXAccessXBeep(keybd,_BEEP_SLOW_PRESS,XkbSlowKeysMask);
501	xkbi->slowKey= key;
502	xkbi->slowKeysTimer = TimerSet(xkbi->slowKeysTimer,
503				 0, ctrls->slow_keys_delay,
504				 AccessXSlowKeyExpire, (pointer)keybd);
505	ignoreKeyEvent = TRUE;
506    }
507
508    /* Don't transmit the KeyPress if BounceKeys is turned on
509     * and the user pressed the same key within a given time period
510     * from the last release.
511     */
512    else if ((ctrls->enabled_ctrls & XkbBounceKeysMask) &&
513					(key == xkbi->inactiveKey)) {
514	if (XkbAX_NeedFeedback(ctrls,XkbAX_BKRejectFBMask))
515	    XkbDDXAccessXBeep(keybd,_BEEP_BOUNCE_REJECT,XkbBounceKeysMask);
516	ignoreKeyEvent = TRUE;
517    }
518
519    /* Start repeating if necessary.  Stop autorepeating if the user
520     * presses a non-modifier key that doesn't autorepeat.
521     */
522    if (XkbDDXUsesSoftRepeat(keybd)) {
523	if ((keybd->kbdfeed->ctrl.autoRepeat) &&
524		((ctrls->enabled_ctrls&(XkbSlowKeysMask|XkbRepeatKeysMask))==
525							XkbRepeatKeysMask)) {
526	    if (BitIsOn(keybd->kbdfeed->ctrl.autoRepeats,key)) {
527		if (xkbDebugFlags&0x10)
528		    DebugF("Starting software autorepeat...\n");
529		if (xkbi->repeatKey == key)
530		    ignoreKeyEvent = TRUE;
531		else {
532		    xkbi->repeatKey = key;
533		    xkbi->repeatKeyTimer= TimerSet(xkbi->repeatKeyTimer,
534			    0, ctrls->repeat_delay,
535			    AccessXRepeatKeyExpire, (pointer)keybd);
536		}
537	    }
538	}
539    }
540
541    /* Check for two keys being pressed at the same time.  This section
542     * essentially says the following:
543     *
544     *	If StickyKeys is on, and a modifier is currently being held down,
545     *  and one of the following is true:  the current key is not a modifier
546     *  or the currentKey is a modifier, but not the only modifier being
547     *  held down, turn StickyKeys off if the TwoKeys off ctrl is set.
548     */
549    if ((ctrls->enabled_ctrls & XkbStickyKeysMask) &&
550				(xkbi->state.base_mods!=0) &&
551				(XkbAX_NeedOption(ctrls,XkbAX_TwoKeysMask))) {
552	xkbControlsNotify cn;
553	cn.keycode = key;
554	cn.eventType = KeyPress;
555	cn.requestMajor = 0;
556	cn.requestMinor = 0;
557	AccessXStickyKeysTurnOff(keybd,&cn);
558    }
559
560    if (!ignoreKeyEvent)
561	XkbProcessKeyboardEvent(event, keybd);
562    return ignoreKeyEvent;
563} /* AccessXFilterPressEvent */
564
565/************************************************************************/
566/*									*/
567/* AccessXFilterReleaseEvent						*/
568/*									*/
569/* Filter events before they get any further if SlowKeys is turned on.	*/
570/* In addition, this routine handles the ever so popular magic key	*/
571/* acts for turning various accessibility features on/off.		*/
572/*									*/
573/* Returns TRUE if this routine has discarded the event.		*/
574/* Returns FALSE if the event needs further processing.			*/
575/*									*/
576/************************************************************************/
577Bool
578AccessXFilterReleaseEvent(	DeviceEvent*	event,
579				DeviceIntPtr	keybd)
580{
581XkbSrvInfoPtr	xkbi = keybd->key->xkbInfo;
582XkbControlsPtr	ctrls = xkbi->desc->ctrls;
583KeyCode		key = event->detail.key;
584Bool		ignoreKeyEvent = FALSE;
585
586    /* Don't transmit the KeyRelease if BounceKeys is on and
587     * this is the release of a key that was ignored due to
588     * BounceKeys.
589     */
590    if (ctrls->enabled_ctrls & XkbBounceKeysMask) {
591	if ((key!=xkbi->mouseKey)&&(!BitIsOn(keybd->key->down,key)))
592	    ignoreKeyEvent = TRUE;
593	xkbi->inactiveKey= key;
594	xkbi->bounceKeysTimer= TimerSet(xkbi->bounceKeysTimer, 0,
595					ctrls->debounce_delay,
596					AccessXBounceKeyExpire, (pointer)keybd);
597    }
598
599    /* Don't transmit the KeyRelease if SlowKeys is turned on and
600     * the user didn't hold the key long enough.  We know we passed
601     * the key if the down bit was set by CoreProcessKeyboadEvent.
602     */
603    if (ctrls->enabled_ctrls & XkbSlowKeysMask) {
604	xkbAccessXNotify	ev;
605	unsigned		beep_type;
606	ev.keycode= key;
607	ev.slowKeysDelay= ctrls->slow_keys_delay;
608	ev.debounceDelay= ctrls->debounce_delay;
609	if (BitIsOn(keybd->key->down,key) || (xkbi->mouseKey == key)) {
610	    ev.detail= XkbAXN_SKRelease;
611	    beep_type= _BEEP_SLOW_RELEASE;
612	}
613	else {
614	    ev.detail= XkbAXN_SKReject;
615	    beep_type= _BEEP_SLOW_REJECT;
616	    ignoreKeyEvent = TRUE;
617	}
618	XkbSendAccessXNotify(keybd,&ev);
619	if (XkbAX_NeedFeedback(ctrls,XkbAX_SKRejectFBMask)) {
620	    XkbDDXAccessXBeep(keybd,beep_type,XkbSlowKeysMask);
621	}
622	if (xkbi->slowKey==key)
623	    xkbi->slowKey= 0;
624    }
625
626    /* Stop Repeating if the user releases the key that is currently
627     * repeating.
628     */
629    if (xkbi->repeatKey==key) {
630	xkbi->repeatKey= 0;
631    }
632
633    if ((ctrls->enabled_ctrls&XkbAccessXTimeoutMask)&&(ctrls->ax_timeout>0)) {
634	xkbi->lastPtrEventTime= 0;
635	xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0,
636					ctrls->ax_timeout*1000,
637					AccessXTimeoutExpire, (pointer)keybd);
638	xkbi->krgTimerActive= _ALL_TIMEOUT_TIMER;
639    }
640    else if (xkbi->krgTimerActive!=_OFF_TIMER) {
641	xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0, 0, NULL, NULL);
642	xkbi->krgTimerActive= _OFF_TIMER;
643    }
644
645    /* Keep track of how many times the Shift key has been pressed.
646     * If it has been pressed and released 5 times in a row, toggle
647     * the state of StickyKeys.
648     */
649    if ((!ignoreKeyEvent)&&(xkbi->shiftKeyCount)) {
650	KeySym *pSym= XkbKeySymsPtr(xkbi->desc,key);
651	if ((pSym[0]!=XK_Shift_L)&&(pSym[0]!=XK_Shift_R)) {
652	    xkbi->shiftKeyCount= 0;
653	}
654	else if (xkbi->shiftKeyCount>=5) {
655	     xkbControlsNotify cn;
656	     cn.keycode = key;
657	     cn.eventType = KeyPress;
658	     cn.requestMajor = 0;
659	     cn.requestMinor = 0;
660	     if (ctrls->enabled_ctrls & XkbStickyKeysMask)
661		AccessXStickyKeysTurnOff(keybd,&cn);
662	     else
663		AccessXStickyKeysTurnOn(keybd,&cn);
664	     xkbi->shiftKeyCount= 0;
665	}
666    }
667
668    if (!ignoreKeyEvent)
669	XkbProcessKeyboardEvent(event, keybd);
670    return ignoreKeyEvent;
671
672} /* AccessXFilterReleaseEvent */
673
674/************************************************************************/
675/*									*/
676/* ProcessPointerEvent							*/
677/*									*/
678/* This routine merely sets the shiftKeyCount and clears the keyboard   */
679/* response group timer (if necessary) on a mouse event.  This is so	*/
680/* multiple shifts with just the mouse and shift-drags with the mouse	*/
681/* don't accidentally turn on StickyKeys or the Keyboard Response Group.*/
682/*									*/
683/************************************************************************/
684extern int xkbDevicePrivateIndex;
685extern void xkbUnwrapProc(DeviceIntPtr, DeviceHandleProc, pointer);
686void
687ProcessPointerEvent(	InternalEvent   *ev,
688			DeviceIntPtr    mouse)
689{
690DeviceIntPtr	dev;
691XkbSrvInfoPtr	xkbi = NULL;
692unsigned 	changed = 0;
693ProcessInputProc backupproc;
694xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(mouse);
695DeviceEvent     *event = &ev->device_event;
696
697    dev = (IsMaster(mouse) || mouse->u.master) ? GetMaster(mouse, MASTER_KEYBOARD) : mouse;
698
699    if (dev && dev->key)
700    {
701	xkbi = dev->key->xkbInfo;
702	xkbi->shiftKeyCount = 0;
703	xkbi->lastPtrEventTime= event->time;
704    }
705
706    if (event->type == ET_ButtonPress) {
707	    changed |= XkbPointerButtonMask;
708    }
709    else if (event->type == ET_ButtonRelease) {
710	if (xkbi) {
711	    xkbi->lockedPtrButtons&= ~(1 << (event->detail.key & 0x7));
712
713            if (IsMaster(dev))
714            {
715                DeviceIntPtr source;
716                int rc;
717                rc = dixLookupDevice(&source, event->sourceid, serverClient, DixWriteAccess);
718                if (rc != Success)
719                    ErrorF("[xkb] bad sourceid '%d' on button release event.\n", event->sourceid);
720                else if (!IsXTestDevice(source, GetMaster(dev, MASTER_POINTER)))
721                    XkbFakeDeviceButton(dev, FALSE, event->detail.key);
722            }
723	}
724
725	changed |= XkbPointerButtonMask;
726    }
727
728    UNWRAP_PROCESS_INPUT_PROC(mouse, xkbPrivPtr, backupproc);
729    mouse->public.processInputProc(ev, mouse);
730    COND_WRAP_PROCESS_INPUT_PROC(mouse, xkbPrivPtr,
731				     backupproc, xkbUnwrapProc);
732
733    if (!xkbi)
734	return;
735
736    xkbi->state.ptr_buttons = (mouse->button) ? mouse->button->state : 0;
737
738    /* clear any latched modifiers */
739    if ( xkbi->state.latched_mods && (event->type == ET_ButtonRelease) ) {
740	unsigned 		changed_leds;
741	XkbStateRec		oldState;
742	XkbSrvLedInfoPtr	sli;
743
744	sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
745	oldState= xkbi->state;
746	XkbLatchModifiers(dev,0xFF,0x00);
747
748	XkbComputeDerivedState(xkbi);
749	changed |= XkbStateChangedFlags(&oldState,&xkbi->state);
750	if (changed&sli->usedComponents) {
751	    changed_leds= XkbIndicatorsToUpdate(dev,changed,FALSE);
752	    if (changed_leds) {
753		XkbEventCauseRec	cause;
754		XkbSetCauseKey(&cause,(event->detail.key & 0x7), event->type);
755		XkbUpdateIndicators(dev,changed_leds,TRUE,NULL,&cause);
756	    }
757	}
758    }
759
760    if (((xkbi->flags&_XkbStateNotifyInProgress)==0)&&(changed!=0)) {
761	xkbStateNotify	sn;
762	sn.keycode= event->detail.key;
763	sn.eventType= event->type;
764	sn.requestMajor = sn.requestMinor = 0;
765	sn.changed= changed;
766	XkbSendStateNotify(dev,&sn);
767    }
768
769} /* ProcessPointerEvent */
770
771
772
773
774