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 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/************************************************************************/ 125static void 126AccessXKeyboardEvent(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/************************************************************************/ 151static void 152AccessXKRGTurnOn(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/************************************************************************/ 183static void 184AccessXKRGTurnOff(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/************************************************************************/ 218static void 219AccessXStickyKeysTurnOn(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/************************************************************************/ 252static void 253AccessXStickyKeysTurnOff(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 282static CARD32 283AccessXKRGExpire(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 312static CARD32 313AccessXRepeatKeyExpire(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 327void 328AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi, KeyCode key) 329{ 330 if (xkbi->repeatKey == key) 331 xkbi->repeatKey = 0; 332 return; 333} 334 335static CARD32 336AccessXSlowKeyExpire(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 382static CARD32 383AccessXBounceKeyExpire(OsTimerPtr timer, CARD32 now, void *arg) 384{ 385 XkbSrvInfoPtr xkbi = ((DeviceIntPtr) arg)->key->xkbInfo; 386 387 xkbi->inactiveKey = 0; 388 return 0; 389} 390 391static CARD32 392AccessXTimeoutExpire(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/************************************************************************/ 456Bool 457AccessXFilterPressEvent(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/************************************************************************/ 594Bool 595AccessXFilterReleaseEvent(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/************************************************************************/ 708extern int xkbDevicePrivateIndex; 709void 710ProcessPointerEvent(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