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