1 /************************************************************
2 Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
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.
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.
25 ********************************************************/
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
34 #include <X11/Xproto.h>
35 #include <X11/keysym.h>
36 #include "exglobals.h"
37 #include <X11/extensions/XIproto.h>
40 #include "inpututils.h"
46 int XkbDfltRepeatDelay
= 660;
47 int XkbDfltRepeatInterval
= 40;
49 #define DFLT_TIMEOUT_CTRLS (XkbAX_KRGMask|XkbStickyKeysMask|XkbMouseKeysMask)
50 #define DFLT_TIMEOUT_OPTS (XkbAX_IndicatorFBMask)
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
);
63 AccessXComputeCurveFactor(XkbSrvInfoPtr xkbi
, XkbControlsPtr ctrls
)
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
));
73 AccessXInit(DeviceIntPtr keybd
)
75 XkbSrvInfoPtr xkbi
= keybd
->key
->xkbInfo
;
76 XkbControlsPtr ctrls
= xkbi
->desc
->ctrls
;
78 xkbi
->shiftKeyCount
= 0;
79 xkbi
->mouseKeysCounter
= 0;
80 xkbi
->inactiveKey
= 0;
83 xkbi
->krgTimerActive
= _OFF_TIMER
;
84 xkbi
->beepType
= _BEEP_NONE
;
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
;
110 ctrls
->enabled_ctrls
&= ~XkbAccessXTimeoutMask
;
111 ctrls
->enabled_ctrls
|= XkbDfltAccessXFeedback
;
112 ctrls
->ax_options
= XkbDfltAccessXOptions
;
113 AccessXComputeCurveFactor(xkbi
, ctrls
);
117 /************************************************************************/
119 /* AccessXKeyboardEvent */
121 /* Generate a synthetic keyboard event. */
123 /************************************************************************/
125 AccessXKeyboardEvent(DeviceIntPtr keybd
, int type
, BYTE keyCode
, Bool isRepeat
)
129 init_device_event(&event
, keybd
, GetTimeInMillis());
131 event
.detail
.key
= keyCode
;
132 event
.key_repeat
= isRepeat
;
134 if (xkbDebugFlags
& 0x8) {
135 DebugF("[xkb] AXKE: Key %d %s\n", keyCode
,
136 (event
.type
== ET_KeyPress
? "down" : "up"));
139 XkbProcessKeyboardEvent(&event
, keybd
);
141 } /* AccessXKeyboardEvent */
143 /************************************************************************/
145 /* AccessXKRGTurnOn */
147 /* Turn the keyboard response group on. */
149 /************************************************************************/
151 AccessXKRGTurnOn(DeviceIntPtr dev
, CARD16 KRGControl
, xkbControlsNotify
* pCN
)
153 XkbSrvInfoPtr xkbi
= dev
->key
->xkbInfo
;
154 XkbControlsPtr ctrls
= xkbi
->desc
->ctrls
;
156 XkbEventCauseRec cause
;
157 XkbSrvLedInfoPtr sli
;
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
);
173 } /* AccessXKRGTurnOn */
175 /************************************************************************/
177 /* AccessXKRGTurnOff */
179 /* Turn the keyboard response group off. */
181 /************************************************************************/
183 AccessXKRGTurnOff(DeviceIntPtr dev
, xkbControlsNotify
* pCN
)
185 XkbSrvInfoPtr xkbi
= dev
->key
->xkbInfo
;
186 XkbControlsPtr ctrls
= xkbi
->desc
->ctrls
;
188 XkbEventCauseRec cause
;
189 XkbSrvLedInfoPtr sli
;
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
;
204 XkbDDXAccessXBeep(dev
, _BEEP_FEATURE_OFF
, changes
);
208 } /* AccessXKRGTurnOff */
210 /************************************************************************/
212 /* AccessXStickyKeysTurnOn */
214 /* Turn StickyKeys on. */
216 /************************************************************************/
218 AccessXStickyKeysTurnOn(DeviceIntPtr dev
, xkbControlsNotify
* pCN
)
220 XkbSrvInfoPtr xkbi
= dev
->key
->xkbInfo
;
221 XkbControlsPtr ctrls
= xkbi
->desc
->ctrls
;
223 XkbEventCauseRec cause
;
224 XkbSrvLedInfoPtr sli
;
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
);
242 } /* AccessXStickyKeysTurnOn */
244 /************************************************************************/
246 /* AccessXStickyKeysTurnOff */
248 /* Turn StickyKeys off. */
250 /************************************************************************/
252 AccessXStickyKeysTurnOff(DeviceIntPtr dev
, xkbControlsNotify
* pCN
)
254 XkbSrvInfoPtr xkbi
= dev
->key
->xkbInfo
;
255 XkbControlsPtr ctrls
= xkbi
->desc
->ctrls
;
257 XkbEventCauseRec cause
;
258 XkbSrvLedInfoPtr sli
;
261 ctrls
->enabled_ctrls
&= ~XkbStickyKeysMask
;
262 xkbi
->shiftKeyCount
= 0;
263 if (XkbComputeControlsNotify(dev
, &old
, ctrls
, pCN
, FALSE
))
264 XkbSendControlsNotify(dev
, pCN
);
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
);
275 #ifndef NO_CLEAR_LATCHES_FOR_STICKY_KEYS_OFF
276 XkbClearAllLatchesAndLocks(dev
, xkbi
, FALSE
, &cause
);
279 } /* AccessXStickyKeysTurnOff */
282 AccessXKRGExpire(OsTimerPtr timer
, CARD32 now
, pointer arg
)
284 xkbControlsNotify cn
;
285 DeviceIntPtr dev
= arg
;
286 XkbSrvInfoPtr xkbi
= dev
->key
->xkbInfo
;
288 if (xkbi
->krgTimerActive
== _KRG_WARN_TIMER
) {
289 XkbDDXAccessXBeep(dev
, _BEEP_SLOW_WARN
, XkbStickyKeysMask
);
290 xkbi
->krgTimerActive
= _KRG_TIMER
;
293 xkbi
->krgTimerActive
= _OFF_TIMER
;
294 cn
.keycode
= xkbi
->slowKeyEnableKey
;
295 cn
.eventType
= KeyPress
;
298 if (xkbi
->desc
->ctrls
->enabled_ctrls
& XkbSlowKeysMask
) {
299 AccessXKRGTurnOff(dev
, &cn
);
300 LogMessage(X_INFO
, "XKB SlowKeys are disabled.\n");
303 AccessXKRGTurnOn(dev
, XkbSlowKeysMask
, &cn
);
304 LogMessage(X_INFO
, "XKB SlowKeys are now enabled. Hold shift to disable.\n");
307 xkbi
->slowKeyEnableKey
= 0;
312 AccessXRepeatKeyExpire(OsTimerPtr timer
, CARD32 now
, pointer arg
)
314 DeviceIntPtr dev
= (DeviceIntPtr
) arg
;
315 XkbSrvInfoPtr xkbi
= dev
->key
->xkbInfo
;
317 if (xkbi
->repeatKey
== 0)
320 AccessXKeyboardEvent(dev
, ET_KeyPress
, xkbi
->repeatKey
, TRUE
);
322 return xkbi
->desc
->ctrls
->repeat_interval
;
326 AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi
, KeyCode key
)
328 if (xkbi
->repeatKey
== key
)
334 AccessXSlowKeyExpire(OsTimerPtr timer
, CARD32 now
, pointer arg
)
339 XkbControlsPtr ctrls
;
341 keybd
= (DeviceIntPtr
) arg
;
342 xkbi
= keybd
->key
->xkbInfo
;
345 if (xkbi
->slowKey
!= 0) {
347 KeySym
*sym
= XkbKeySymsPtr(xkb
, xkbi
->slowKey
);
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
++;
362 /* Start repeating if necessary. Stop autorepeating if the user
363 * presses a non-modifier key that doesn't autorepeat.
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
,
381 AccessXBounceKeyExpire(OsTimerPtr timer
, CARD32 now
, pointer arg
)
383 XkbSrvInfoPtr xkbi
= ((DeviceIntPtr
) arg
)->key
->xkbInfo
;
385 xkbi
->inactiveKey
= 0;
390 AccessXTimeoutExpire(OsTimerPtr timer
, CARD32 now
, pointer arg
)
392 DeviceIntPtr dev
= (DeviceIntPtr
) arg
;
393 XkbSrvInfoPtr xkbi
= dev
->key
->xkbInfo
;
394 XkbControlsPtr ctrls
= xkbi
->desc
->ctrls
;
396 xkbControlsNotify cn
;
397 XkbEventCauseRec cause
;
398 XkbSrvLedInfoPtr sli
;
400 if (xkbi
->lastPtrEventTime
) {
401 unsigned timeToWait
= (ctrls
->ax_timeout
* 1000);
402 unsigned timeElapsed
= (now
- xkbi
->lastPtrEventTime
);
404 if (timeToWait
> timeElapsed
)
405 return timeToWait
- timeElapsed
;
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
);
415 if (XkbComputeControlsNotify(dev
, &old
, ctrls
, &cn
, FALSE
)) {
420 XkbSendControlsNotify(dev
, &cn
);
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
;
428 set
= ctrls
->ax_options
& (~old
.ax_options
);
429 cleared
= (~ctrls
->ax_options
) & old
.ax_options
;
431 bell
= _BEEP_FEATURE_CHANGE
;
433 bell
= _BEEP_FEATURE_ON
;
435 bell
= _BEEP_FEATURE_OFF
;
436 XkbDDXAccessXBeep(dev
, bell
, XkbAccessXTimeoutMask
);
438 xkbi
->krgTimerActive
= _OFF_TIMER
;
442 /************************************************************************/
444 /* AccessXFilterPressEvent */
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. */
450 /* Returns TRUE if this routine has discarded the event. */
451 /* Returns FALSE if the event needs further processing. */
453 /************************************************************************/
455 AccessXFilterPressEvent(DeviceEvent
*event
, DeviceIntPtr keybd
)
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
);
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
);
473 xkbi
->krgTimerActive
= _KRG_TIMER
;
474 xkbi
->krgTimer
= TimerSet(xkbi
->krgTimer
, 0, 8000,
475 AccessXKRGExpire
, (pointer
) keybd
);
477 if (!(ctrls
->enabled_ctrls
& XkbSlowKeysMask
)) {
478 CARD32 now
= GetTimeInMillis();
480 if ((now
- xkbi
->lastShiftEventTime
) > 15000)
481 xkbi
->shiftKeyCount
= 1;
483 xkbi
->shiftKeyCount
++;
484 xkbi
->lastShiftEventTime
= now
;
488 if (xkbi
->krgTimerActive
) {
489 xkbi
->krgTimer
= TimerSet(xkbi
->krgTimer
, 0, 0, NULL
, NULL
);
490 xkbi
->krgTimerActive
= _OFF_TIMER
;
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.
499 if (ctrls
->enabled_ctrls
& XkbSlowKeysMask
) {
502 /* If key was already pressed, ignore subsequent press events
503 * from the server's autorepeat
505 if (xkbi
->slowKey
== key
)
507 ev
.detail
= XkbAXN_SKPress
;
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
);
515 xkbi
->slowKeysTimer
= TimerSet(xkbi
->slowKeysTimer
,
516 0, ctrls
->slow_keys_delay
,
517 AccessXSlowKeyExpire
, (pointer
) keybd
);
518 ignoreKeyEvent
= TRUE
;
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.
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
;
532 /* Start repeating if necessary. Stop autorepeating if the user
533 * presses a non-modifier key that doesn't autorepeat.
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
;
545 xkbi
->repeatKey
= key
;
546 xkbi
->repeatKeyTimer
= TimerSet(xkbi
->repeatKeyTimer
,
547 0, ctrls
->repeat_delay
,
548 AccessXRepeatKeyExpire
,
555 /* Check for two keys being pressed at the same time. This section
556 * essentially says the following:
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.
563 if ((ctrls
->enabled_ctrls
& XkbStickyKeysMask
) &&
564 (xkbi
->state
.base_mods
!= 0) &&
565 (XkbAX_NeedOption(ctrls
, XkbAX_TwoKeysMask
))) {
566 xkbControlsNotify cn
;
569 cn
.eventType
= KeyPress
;
572 AccessXStickyKeysTurnOff(keybd
, &cn
);
576 XkbProcessKeyboardEvent(event
, keybd
);
577 return ignoreKeyEvent
;
578 } /* AccessXFilterPressEvent */
580 /************************************************************************/
582 /* AccessXFilterReleaseEvent */
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. */
588 /* Returns TRUE if this routine has discarded the event. */
589 /* Returns FALSE if the event needs further processing. */
591 /************************************************************************/
593 AccessXFilterReleaseEvent(DeviceEvent
*event
, DeviceIntPtr keybd
)
595 XkbSrvInfoPtr xkbi
= keybd
->key
->xkbInfo
;
596 XkbControlsPtr ctrls
= xkbi
->desc
->ctrls
;
597 KeyCode key
= event
->detail
.key
;
598 Bool ignoreKeyEvent
= FALSE
;
600 /* Don't transmit the KeyRelease if BounceKeys is on and
601 * this is the release of a key that was ignored due to
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
,
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.
618 if (ctrls
->enabled_ctrls
& XkbSlowKeysMask
) {
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
;
630 ev
.detail
= XkbAXN_SKReject
;
631 beep_type
= _BEEP_SLOW_REJECT
;
632 ignoreKeyEvent
= TRUE
;
634 XkbSendAccessXNotify(keybd
, &ev
);
635 if (XkbAX_NeedFeedback(ctrls
, XkbAX_SKRejectFBMask
)) {
636 XkbDDXAccessXBeep(keybd
, beep_type
, XkbSlowKeysMask
);
638 if (xkbi
->slowKey
== key
)
642 /* Stop Repeating if the user releases the key that is currently
645 if (xkbi
->repeatKey
== key
) {
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
;
657 else if (xkbi
->krgTimerActive
!= _OFF_TIMER
) {
658 xkbi
->krgTimer
= TimerSet(xkbi
->krgTimer
, 0, 0, NULL
, NULL
);
659 xkbi
->krgTimerActive
= _OFF_TIMER
;
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.
666 if ((!ignoreKeyEvent
) && (xkbi
->shiftKeyCount
)) {
667 KeySym
*pSym
= XkbKeySymsPtr(xkbi
->desc
, key
);
669 if ((pSym
[0] != XK_Shift_L
) && (pSym
[0] != XK_Shift_R
)) {
670 xkbi
->shiftKeyCount
= 0;
672 else if (xkbi
->shiftKeyCount
>= 5) {
673 xkbControlsNotify cn
;
676 cn
.eventType
= KeyPress
;
679 if (ctrls
->enabled_ctrls
& XkbStickyKeysMask
)
680 AccessXStickyKeysTurnOff(keybd
, &cn
);
682 AccessXStickyKeysTurnOn(keybd
, &cn
);
683 xkbi
->shiftKeyCount
= 0;
688 XkbProcessKeyboardEvent(event
, keybd
);
689 return ignoreKeyEvent
;
691 } /* AccessXFilterReleaseEvent */
693 /************************************************************************/
695 /* ProcessPointerEvent */
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.*/
702 /************************************************************************/
703 extern int xkbDevicePrivateIndex
;
705 ProcessPointerEvent(InternalEvent
*ev
, DeviceIntPtr mouse
)
708 XkbSrvInfoPtr xkbi
= NULL
;
709 unsigned changed
= 0;
710 ProcessInputProc backupproc
;
711 xkbDeviceInfoPtr xkbPrivPtr
= XKBDEVICEINFO(mouse
);
712 DeviceEvent
*event
= &ev
->device_event
;
714 dev
= (IsMaster(mouse
) || IsFloating(mouse
)) ? mouse
: GetMaster(mouse
, MASTER_KEYBOARD
);
716 if (dev
&& dev
->key
) {
717 xkbi
= dev
->key
->xkbInfo
;
718 xkbi
->shiftKeyCount
= 0;
719 xkbi
->lastPtrEventTime
= event
->time
;
722 if (event
->type
== ET_ButtonPress
) {
723 changed
|= XkbPointerButtonMask
;
725 else if (event
->type
== ET_ButtonRelease
) {
730 rc
= dixLookupDevice(&source
, event
->sourceid
, serverClient
,
733 ErrorF("[xkb] bad sourceid '%d' on button release event.\n",
735 else if (!IsXTestDevice(source
, GetMaster(dev
, MASTER_POINTER
))) {
736 DeviceIntPtr xtest_device
;
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
);
745 xkbi
->lockedPtrButtons
&= ~(1 << (event
->detail
.key
& 0x7));
747 changed
|= XkbPointerButtonMask
;
750 UNWRAP_PROCESS_INPUT_PROC(mouse
, xkbPrivPtr
, backupproc
);
751 mouse
->public.processInputProc(ev
, mouse
);
752 COND_WRAP_PROCESS_INPUT_PROC(mouse
, xkbPrivPtr
, backupproc
, xkbUnwrapProc
);
757 xkbi
->state
.ptr_buttons
= (mouse
->button
) ? mouse
->button
->state
: 0;
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
;
765 sli
= XkbFindSrvLedInfo(dev
, XkbDfltXIClass
, XkbDfltXIId
, 0);
766 oldState
= xkbi
->state
;
767 XkbLatchModifiers(dev
, 0xFF, 0x00);
769 XkbComputeDerivedState(xkbi
);
770 changed
|= XkbStateChangedFlags(&oldState
, &xkbi
->state
);
771 if (changed
& sli
->usedComponents
) {
772 changed_leds
= XkbIndicatorsToUpdate(dev
, changed
, FALSE
);
774 XkbEventCauseRec cause
;
776 XkbSetCauseKey(&cause
, (event
->detail
.key
& 0x7), event
->type
);
777 XkbUpdateIndicators(dev
, changed_leds
, TRUE
, NULL
, &cause
);
782 if (((xkbi
->flags
& _XkbStateNotifyInProgress
) == 0) && (changed
!= 0)) {
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
);
792 } /* ProcessPointerEvent */