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