1 /************************************************************
2 Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3 
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15 
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE 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 
46 int XkbDfltRepeatDelay = 660;
47 int XkbDfltRepeatInterval = 40;
48 
49 #define	DFLT_TIMEOUT_CTRLS (XkbAX_KRGMask|XkbStickyKeysMask|XkbMouseKeysMask)
50 #define	DFLT_TIMEOUT_OPTS  (XkbAX_IndicatorFBMask)
51 
52 unsigned short XkbDfltAccessXTimeout = 120;
53 unsigned int XkbDfltAccessXTimeoutMask = DFLT_TIMEOUT_CTRLS;
54 static unsigned int XkbDfltAccessXTimeoutValues = 0;
55 static unsigned int XkbDfltAccessXTimeoutOptionsMask = DFLT_TIMEOUT_OPTS;
56 static unsigned int XkbDfltAccessXTimeoutOptionsValues = 0;
57 unsigned int XkbDfltAccessXFeedback = XkbAccessXFeedbackMask;
58 unsigned short XkbDfltAccessXOptions =
59     XkbAX_AllOptionsMask & ~(XkbAX_IndicatorFBMask | XkbAX_SKReleaseFBMask |
60                              XkbAX_SKRejectFBMask);
61 
62 void
AccessXComputeCurveFactor(XkbSrvInfoPtr xkbi,XkbControlsPtr ctrls)63 AccessXComputeCurveFactor(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 
72 void
AccessXInit(DeviceIntPtr keybd)73 AccessXInit(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 /************************************************************************/
125 static void
AccessXKeyboardEvent(DeviceIntPtr keybd,int type,BYTE keyCode,Bool isRepeat)126 AccessXKeyboardEvent(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 /************************************************************************/
151 static void
AccessXKRGTurnOn(DeviceIntPtr dev,CARD16 KRGControl,xkbControlsNotify * pCN)152 AccessXKRGTurnOn(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 /************************************************************************/
183 static void
AccessXKRGTurnOff(DeviceIntPtr dev,xkbControlsNotify * pCN)184 AccessXKRGTurnOff(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 /************************************************************************/
218 static void
AccessXStickyKeysTurnOn(DeviceIntPtr dev,xkbControlsNotify * pCN)219 AccessXStickyKeysTurnOn(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 /************************************************************************/
252 static void
AccessXStickyKeysTurnOff(DeviceIntPtr dev,xkbControlsNotify * pCN)253 AccessXStickyKeysTurnOff(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 
282 static CARD32
AccessXKRGExpire(OsTimerPtr timer,CARD32 now,void * arg)283 AccessXKRGExpire(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 
312 static CARD32
AccessXRepeatKeyExpire(OsTimerPtr timer,CARD32 now,void * arg)313 AccessXRepeatKeyExpire(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 
327 void
AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi,KeyCode key)328 AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi, KeyCode key)
329 {
330     if (xkbi->repeatKey == key)
331         xkbi->repeatKey = 0;
332     return;
333 }
334 
335 static CARD32
AccessXSlowKeyExpire(OsTimerPtr timer,CARD32 now,void * arg)336 AccessXSlowKeyExpire(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 
382 static CARD32
AccessXBounceKeyExpire(OsTimerPtr timer,CARD32 now,void * arg)383 AccessXBounceKeyExpire(OsTimerPtr timer, CARD32 now, void *arg)
384 {
385     XkbSrvInfoPtr xkbi = ((DeviceIntPtr) arg)->key->xkbInfo;
386 
387     xkbi->inactiveKey = 0;
388     return 0;
389 }
390 
391 static CARD32
AccessXTimeoutExpire(OsTimerPtr timer,CARD32 now,void * arg)392 AccessXTimeoutExpire(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 /************************************************************************/
456 Bool
AccessXFilterPressEvent(DeviceEvent * event,DeviceIntPtr keybd)457 AccessXFilterPressEvent(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 /************************************************************************/
594 Bool
AccessXFilterReleaseEvent(DeviceEvent * event,DeviceIntPtr keybd)595 AccessXFilterReleaseEvent(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 /************************************************************************/
708 extern int xkbDevicePrivateIndex;
709 void
ProcessPointerEvent(InternalEvent * ev,DeviceIntPtr mouse)710 ProcessPointerEvent(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