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