Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | |
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 | |
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 | 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 | /************************************************************************/ | |
124 | static void | |
125 | AccessXKeyboardEvent(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 | /************************************************************************/ | |
150 | static void | |
151 | AccessXKRGTurnOn(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 | /************************************************************************/ | |
182 | static void | |
183 | AccessXKRGTurnOff(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 | /************************************************************************/ | |
217 | static void | |
218 | AccessXStickyKeysTurnOn(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 | /************************************************************************/ | |
251 | static void | |
252 | AccessXStickyKeysTurnOff(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 | ||
281 | static CARD32 | |
282 | AccessXKRGExpire(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 | ||
311 | static CARD32 | |
312 | AccessXRepeatKeyExpire(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 | ||
325 | void | |
326 | AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi, KeyCode key) | |
327 | { | |
328 | if (xkbi->repeatKey == key) | |
329 | xkbi->repeatKey = 0; | |
330 | return; | |
331 | } | |
332 | ||
333 | static CARD32 | |
334 | AccessXSlowKeyExpire(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 | ||
380 | static CARD32 | |
381 | AccessXBounceKeyExpire(OsTimerPtr timer, CARD32 now, pointer arg) | |
382 | { | |
383 | XkbSrvInfoPtr xkbi = ((DeviceIntPtr) arg)->key->xkbInfo; | |
384 | ||
385 | xkbi->inactiveKey = 0; | |
386 | return 0; | |
387 | } | |
388 | ||
389 | static CARD32 | |
390 | AccessXTimeoutExpire(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 | /************************************************************************/ | |
454 | Bool | |
455 | AccessXFilterPressEvent(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 | /************************************************************************/ | |
592 | Bool | |
593 | AccessXFilterReleaseEvent(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 | /************************************************************************/ | |
703 | extern int xkbDevicePrivateIndex; | |
704 | void | |
705 | ProcessPointerEvent(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 */ |