1/************************************************************ 2Copyright (c) 1995 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 <ctype.h> 33#include <math.h> 34#include <X11/X.h> 35#include <X11/Xproto.h> 36#include "misc.h" 37#include "inputstr.h" 38 39#include <X11/extensions/XI.h> 40#include <xkbsrv.h> 41#include "xkb.h" 42 43/***====================================================================***/ 44 45 /* 46 * unsigned 47 * XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn) 48 * 49 * Given a keyboard and a set of state components that have changed, 50 * this function returns the indicators on the default keyboard 51 * feedback that might be affected. It also reports whether or not 52 * any extension devices might be affected in check_devs_rtrn. 53 */ 54 55unsigned 56XkbIndicatorsToUpdate(DeviceIntPtr dev, 57 unsigned long state_changes, Bool enable_changes) 58{ 59 register unsigned update = 0; 60 XkbSrvLedInfoPtr sli; 61 62 sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0); 63 64 if (!sli) 65 return update; 66 67 if (state_changes & (XkbModifierStateMask | XkbGroupStateMask)) 68 update |= sli->usesEffective; 69 if (state_changes & (XkbModifierBaseMask | XkbGroupBaseMask)) 70 update |= sli->usesBase; 71 if (state_changes & (XkbModifierLatchMask | XkbGroupLatchMask)) 72 update |= sli->usesLatched; 73 if (state_changes & (XkbModifierLockMask | XkbGroupLockMask)) 74 update |= sli->usesLocked; 75 if (state_changes & XkbCompatStateMask) 76 update |= sli->usesCompat; 77 if (enable_changes) 78 update |= sli->usesControls; 79 return update; 80} 81 82/***====================================================================***/ 83 84 /* 85 * Bool 86 *XkbApplyLEDChangeToKeyboard(xkbi,map,on,change) 87 * 88 * Some indicators "drive" the keyboard when their state is explicitly 89 * changed, as described in section 9.2.1 of the XKB protocol spec. 90 * This function updates the state and controls for the keyboard 91 * specified by 'xkbi' to reflect any changes that are required 92 * when the indicator described by 'map' is turned on or off. The 93 * extent of the changes is reported in change, which must be defined. 94 */ 95static Bool 96XkbApplyLEDChangeToKeyboard(XkbSrvInfoPtr xkbi, 97 XkbIndicatorMapPtr map, 98 Bool on, XkbChangesPtr change) 99{ 100 Bool ctrlChange, stateChange; 101 XkbStatePtr state; 102 103 if ((map->flags & XkbIM_NoExplicit) || 104 ((map->flags & XkbIM_LEDDrivesKB) == 0)) 105 return FALSE; 106 ctrlChange = stateChange = FALSE; 107 if (map->ctrls) { 108 XkbControlsPtr ctrls = xkbi->desc->ctrls; 109 unsigned old; 110 111 old = ctrls->enabled_ctrls; 112 if (on) 113 ctrls->enabled_ctrls |= map->ctrls; 114 else 115 ctrls->enabled_ctrls &= ~map->ctrls; 116 if (old != ctrls->enabled_ctrls) { 117 change->ctrls.changed_ctrls = XkbControlsEnabledMask; 118 change->ctrls.enabled_ctrls_changes = old ^ ctrls->enabled_ctrls; 119 ctrlChange = TRUE; 120 } 121 } 122 state = &xkbi->state; 123 if ((map->groups) && ((map->which_groups & (~XkbIM_UseBase)) != 0)) { 124 register int i; 125 register unsigned bit, match; 126 127 if (on) 128 match = (map->groups) & XkbAllGroupsMask; 129 else 130 match = (~map->groups) & XkbAllGroupsMask; 131 if (map->which_groups & (XkbIM_UseLocked | XkbIM_UseEffective)) { 132 for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) { 133 if (bit & match) 134 break; 135 } 136 if (map->which_groups & XkbIM_UseLatched) 137 XkbLatchGroup(xkbi->device, 0); /* unlatch group */ 138 state->locked_group = i; 139 stateChange = TRUE; 140 } 141 else if (map->which_groups & (XkbIM_UseLatched | XkbIM_UseEffective)) { 142 for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) { 143 if (bit & match) 144 break; 145 } 146 state->locked_group = 0; 147 XkbLatchGroup(xkbi->device, i); 148 stateChange = TRUE; 149 } 150 } 151 if ((map->mods.mask) && ((map->which_mods & (~XkbIM_UseBase)) != 0)) { 152 if (map->which_mods & (XkbIM_UseLocked | XkbIM_UseEffective)) { 153 register unsigned long old; 154 155 old = state->locked_mods; 156 if (on) 157 state->locked_mods |= map->mods.mask; 158 else 159 state->locked_mods &= ~map->mods.mask; 160 if (state->locked_mods != old) 161 stateChange = TRUE; 162 } 163 if (map->which_mods & (XkbIM_UseLatched | XkbIM_UseEffective)) { 164 register unsigned long newmods; 165 166 newmods = state->latched_mods; 167 if (on) 168 newmods |= map->mods.mask; 169 else 170 newmods &= ~map->mods.mask; 171 if (newmods != state->locked_mods) { 172 newmods &= map->mods.mask; 173 XkbLatchModifiers(xkbi->device, map->mods.mask, newmods); 174 stateChange = TRUE; 175 } 176 } 177 } 178 return stateChange || ctrlChange; 179} 180 181 /* 182 * Bool 183 * ComputeAutoState(map,state,ctrls) 184 * 185 * This function reports the effect of applying the specified 186 * indicator map given the specified state and controls, as 187 * described in section 9.2 of the XKB protocol specification. 188 */ 189 190static Bool 191ComputeAutoState(XkbIndicatorMapPtr map, 192 XkbStatePtr state, XkbControlsPtr ctrls) 193{ 194 Bool on; 195 CARD8 mods, group; 196 197 on = FALSE; 198 mods = group = 0; 199 if (map->which_mods & XkbIM_UseAnyMods) { 200 if (map->which_mods & XkbIM_UseBase) 201 mods |= state->base_mods; 202 if (map->which_mods & XkbIM_UseLatched) 203 mods |= state->latched_mods; 204 if (map->which_mods & XkbIM_UseLocked) 205 mods |= state->locked_mods; 206 if (map->which_mods & XkbIM_UseEffective) 207 mods |= state->mods; 208 if (map->which_mods & XkbIM_UseCompat) 209 mods |= state->compat_state; 210 on = ((map->mods.mask & mods) != 0); 211 on = on || ((mods == 0) && (map->mods.mask == 0) && 212 (map->mods.vmods == 0)); 213 } 214 if (map->which_groups & XkbIM_UseAnyGroup) { 215 if (map->which_groups & XkbIM_UseBase) 216 group |= (1L << state->base_group); 217 if (map->which_groups & XkbIM_UseLatched) 218 group |= (1L << state->latched_group); 219 if (map->which_groups & XkbIM_UseLocked) 220 group |= (1L << state->locked_group); 221 if (map->which_groups & XkbIM_UseEffective) 222 group |= (1L << state->group); 223 on = on || (((map->groups & group) != 0) || (map->groups == 0)); 224 } 225 if (map->ctrls) 226 on = on || (ctrls->enabled_ctrls & map->ctrls); 227 return on; 228} 229 230static void 231XkbUpdateLedAutoState(DeviceIntPtr dev, 232 XkbSrvLedInfoPtr sli, 233 unsigned maps_to_check, 234 xkbExtensionDeviceNotify * ed, 235 XkbChangesPtr changes, XkbEventCausePtr cause) 236{ 237 DeviceIntPtr kbd; 238 XkbStatePtr state; 239 XkbControlsPtr ctrls; 240 XkbChangesRec my_changes; 241 xkbExtensionDeviceNotify my_ed; 242 register unsigned i, bit, affected; 243 register XkbIndicatorMapPtr map; 244 unsigned oldState; 245 246 if ((maps_to_check == 0) || (sli->maps == NULL) || (sli->mapsPresent == 0)) 247 return; 248 249 if (dev->key && dev->key->xkbInfo) 250 kbd = dev; 251 else 252 kbd = inputInfo.keyboard; 253 254 state = &kbd->key->xkbInfo->state; 255 ctrls = kbd->key->xkbInfo->desc->ctrls; 256 affected = maps_to_check; 257 oldState = sli->effectiveState; 258 sli->autoState &= ~affected; 259 for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) { 260 if ((affected & bit) == 0) 261 continue; 262 affected &= ~bit; 263 map = &sli->maps[i]; 264 if ((!(map->flags & XkbIM_NoAutomatic)) && 265 ComputeAutoState(map, state, ctrls)) 266 sli->autoState |= bit; 267 } 268 sli->effectiveState = (sli->autoState | sli->explicitState); 269 affected = sli->effectiveState ^ oldState; 270 if (affected == 0) 271 return; 272 273 if (ed == NULL) { 274 ed = &my_ed; 275 memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify)); 276 } 277 else if ((ed->reason & XkbXI_IndicatorsMask) && 278 ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) { 279 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 280 } 281 282 if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) { 283 if (changes == NULL) { 284 changes = &my_changes; 285 memset((char *) changes, 0, sizeof(XkbChangesRec)); 286 } 287 changes->indicators.state_changes |= affected; 288 } 289 290 ed->reason |= XkbXI_IndicatorStateMask; 291 ed->ledClass = sli->class; 292 ed->ledID = sli->id; 293 ed->ledsDefined = sli->namesPresent | sli->mapsPresent; 294 ed->ledState = sli->effectiveState; 295 ed->unsupported = 0; 296 ed->supported = XkbXI_AllFeaturesMask; 297 298 if (changes != &my_changes) 299 changes = NULL; 300 if (ed != &my_ed) 301 ed = NULL; 302 if (changes || ed) 303 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 304 return; 305} 306 307void 308XkbUpdateAllDeviceIndicators(XkbChangesPtr changes, XkbEventCausePtr cause) 309{ 310 DeviceIntPtr edev; 311 XkbSrvLedInfoPtr sli; 312 313 for (edev = inputInfo.devices; edev != NULL; edev = edev->next) { 314 if (edev->kbdfeed) { 315 KbdFeedbackPtr kf; 316 317 for (kf = edev->kbdfeed; kf != NULL; kf = kf->next) { 318 if ((kf->xkb_sli == NULL) || (kf->xkb_sli->maps == NULL)) 319 continue; 320 sli = kf->xkb_sli; 321 XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL, 322 changes, cause); 323 324 } 325 } 326 if (edev->leds) { 327 LedFeedbackPtr lf; 328 329 for (lf = edev->leds; lf != NULL; lf = lf->next) { 330 if ((lf->xkb_sli == NULL) || (lf->xkb_sli->maps == NULL)) 331 continue; 332 sli = lf->xkb_sli; 333 XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL, 334 changes, cause); 335 336 } 337 } 338 } 339 return; 340} 341 342/***====================================================================***/ 343 344 /* 345 * void 346 * XkbSetIndicators(dev,affect,values,cause) 347 * 348 * Attempts to change the indicators specified in 'affect' to the 349 * states specified in 'values' for the default keyboard feedback 350 * on the keyboard specified by 'dev.' Attempts to change indicator 351 * state might be ignored or have no affect, depending on the XKB 352 * indicator map for any affected indicators, as described in section 353 * 9.2 of the XKB protocol specification. 354 * 355 * If 'changes' is non-NULL, this function notes any changes to the 356 * keyboard state, controls, or indicator state that result from this 357 * attempted change. If 'changes' is NULL, this function generates 358 * XKB events to report any such changes to interested clients. 359 * 360 * If 'cause' is non-NULL, it specifies the reason for the change, 361 * as reported in some XKB events. If it is NULL, this function 362 * assumes that the change is the result of a core protocol 363 * ChangeKeyboardMapping request. 364 */ 365 366void 367XkbSetIndicators(DeviceIntPtr dev, 368 CARD32 affect, CARD32 values, XkbEventCausePtr cause) 369{ 370 XkbSrvLedInfoPtr sli; 371 XkbChangesRec changes; 372 xkbExtensionDeviceNotify ed; 373 unsigned side_affected; 374 375 memset((char *) &changes, 0, sizeof(XkbChangesRec)); 376 memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify)); 377 sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0); 378 sli->explicitState &= ~affect; 379 sli->explicitState |= (affect & values); 380 XkbApplyLedStateChanges(dev, sli, affect, &ed, &changes, cause); 381 382 side_affected = 0; 383 if (changes.state_changes != 0) 384 side_affected |= 385 XkbIndicatorsToUpdate(dev, changes.state_changes, FALSE); 386 if (changes.ctrls.enabled_ctrls_changes) 387 side_affected |= sli->usesControls; 388 389 if (side_affected) { 390 XkbUpdateLedAutoState(dev, sli, side_affected, &ed, &changes, cause); 391 affect |= side_affected; 392 } 393 if (changes.state_changes || changes.ctrls.enabled_ctrls_changes) 394 XkbUpdateAllDeviceIndicators(NULL, cause); 395 396 XkbFlushLedEvents(dev, dev, sli, &ed, &changes, cause); 397 return; 398} 399 400/***====================================================================***/ 401 402/***====================================================================***/ 403 404 /* 405 * void 406 * XkbUpdateIndicators(dev,update,check_edevs,changes,cause) 407 * 408 * Applies the indicator maps for any indicators specified in 409 * 'update' from the default keyboard feedback on the device 410 * specified by 'dev.' 411 * 412 * If 'changes' is NULL, this function generates and XKB events 413 * required to report the necessary changes, otherwise it simply 414 * notes the indicators with changed state. 415 * 416 * If 'check_edevs' is TRUE, this function also checks the indicator 417 * maps for any open extension devices that have them, and updates 418 * the state of any extension device indicators as necessary. 419 */ 420 421void 422XkbUpdateIndicators(DeviceIntPtr dev, 423 register CARD32 update, 424 Bool check_edevs, 425 XkbChangesPtr changes, XkbEventCausePtr cause) 426{ 427 XkbSrvLedInfoPtr sli; 428 429 sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0); 430 XkbUpdateLedAutoState(dev, sli, update, NULL, changes, cause); 431 if (check_edevs) 432 XkbUpdateAllDeviceIndicators(changes, cause); 433 return; 434} 435 436/***====================================================================***/ 437 438/***====================================================================***/ 439 440 /* 441 * void 442 * XkbCheckIndicatorMaps(dev,sli,which) 443 * 444 * Updates the 'indicator accelerators' for the indicators specified 445 * by 'which' in the feedback specified by 'sli.' The indicator 446 * accelerators are internal to the server and are used to simplify 447 * and speed up the process of figuring out which indicators might 448 * be affected by a particular change in keyboard state or controls. 449 */ 450 451void 452XkbCheckIndicatorMaps(DeviceIntPtr dev, XkbSrvLedInfoPtr sli, unsigned which) 453{ 454 register unsigned i, bit; 455 XkbIndicatorMapPtr map; 456 XkbDescPtr xkb; 457 458 if ((sli->flags & XkbSLI_HasOwnState) == 0) 459 return; 460 461 sli->usesBase &= ~which; 462 sli->usesLatched &= ~which; 463 sli->usesLocked &= ~which; 464 sli->usesEffective &= ~which; 465 sli->usesCompat &= ~which; 466 sli->usesControls &= ~which; 467 sli->mapsPresent &= ~which; 468 469 xkb = dev->key->xkbInfo->desc; 470 for (i = 0, bit = 1, map = sli->maps; i < XkbNumIndicators; 471 i++, bit <<= 1, map++) { 472 if (which & bit) { 473 CARD8 what; 474 475 if (!map || !XkbIM_InUse(map)) 476 continue; 477 sli->mapsPresent |= bit; 478 479 what = (map->which_mods | map->which_groups); 480 if (what & XkbIM_UseBase) 481 sli->usesBase |= bit; 482 if (what & XkbIM_UseLatched) 483 sli->usesLatched |= bit; 484 if (what & XkbIM_UseLocked) 485 sli->usesLocked |= bit; 486 if (what & XkbIM_UseEffective) 487 sli->usesEffective |= bit; 488 if (what & XkbIM_UseCompat) 489 sli->usesCompat |= bit; 490 if (map->ctrls) 491 sli->usesControls |= bit; 492 493 map->mods.mask = map->mods.real_mods; 494 if (map->mods.vmods != 0) { 495 map->mods.mask |= XkbMaskForVMask(xkb, map->mods.vmods); 496 } 497 } 498 } 499 sli->usedComponents = 0; 500 if (sli->usesBase) 501 sli->usedComponents |= XkbModifierBaseMask | XkbGroupBaseMask; 502 if (sli->usesLatched) 503 sli->usedComponents |= XkbModifierLatchMask | XkbGroupLatchMask; 504 if (sli->usesLocked) 505 sli->usedComponents |= XkbModifierLockMask | XkbGroupLockMask; 506 if (sli->usesEffective) 507 sli->usedComponents |= XkbModifierStateMask | XkbGroupStateMask; 508 if (sli->usesCompat) 509 sli->usedComponents |= XkbCompatStateMask; 510 return; 511} 512 513/***====================================================================***/ 514 515 /* 516 * XkbSrvLedInfoPtr 517 * XkbAllocSrvLedInfo(dev,kf,lf,needed_parts) 518 * 519 * Allocates an XkbSrvLedInfoPtr for the feedback specified by either 520 * 'kf' or 'lf' on the keyboard specified by 'dev.' 521 * 522 * If 'needed_parts' is non-zero, this function makes sure that any 523 * of the parts speicified therein are allocated. 524 */ 525XkbSrvLedInfoPtr 526XkbAllocSrvLedInfo(DeviceIntPtr dev, 527 KbdFeedbackPtr kf, LedFeedbackPtr lf, unsigned needed_parts) 528{ 529 XkbSrvLedInfoPtr sli; 530 Bool checkAccel; 531 Bool checkNames; 532 533 sli = NULL; 534 checkAccel = checkNames = FALSE; 535 if ((kf != NULL) && (kf->xkb_sli == NULL)) { 536 kf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec)); 537 if (sli == NULL) 538 return NULL; /* ALLOCATION ERROR */ 539 if (dev->key && dev->key->xkbInfo) 540 sli->flags = XkbSLI_HasOwnState; 541 else 542 sli->flags = 0; 543 sli->class = KbdFeedbackClass; 544 sli->id = kf->ctrl.id; 545 sli->fb.kf = kf; 546 547 sli->autoState = 0; 548 sli->explicitState = kf->ctrl.leds; 549 sli->effectiveState = kf->ctrl.leds; 550 551 if ((kf == dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) { 552 XkbDescPtr xkb; 553 554 xkb = dev->key->xkbInfo->desc; 555 sli->flags |= XkbSLI_IsDefault; 556 sli->physIndicators = xkb->indicators->phys_indicators; 557 sli->names = xkb->names->indicators; 558 sli->maps = xkb->indicators->maps; 559 checkNames = checkAccel = TRUE; 560 } 561 else { 562 sli->physIndicators = XkbAllIndicatorsMask; 563 sli->names = NULL; 564 sli->maps = NULL; 565 } 566 } 567 else if ((kf != NULL) && ((kf->xkb_sli->flags & XkbSLI_IsDefault) != 0)) { 568 XkbDescPtr xkb; 569 570 xkb = dev->key->xkbInfo->desc; 571 sli = kf->xkb_sli; 572 sli->physIndicators = xkb->indicators->phys_indicators; 573 if (xkb->names->indicators != sli->names) { 574 checkNames = TRUE; 575 sli->names = xkb->names->indicators; 576 } 577 if (xkb->indicators->maps != sli->maps) { 578 checkAccel = TRUE; 579 sli->maps = xkb->indicators->maps; 580 } 581 } 582 else if ((lf != NULL) && (lf->xkb_sli == NULL)) { 583 lf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec)); 584 if (sli == NULL) 585 return NULL; /* ALLOCATION ERROR */ 586 if (dev->key && dev->key->xkbInfo) 587 sli->flags = XkbSLI_HasOwnState; 588 else 589 sli->flags = 0; 590 sli->class = LedFeedbackClass; 591 sli->id = lf->ctrl.id; 592 sli->fb.lf = lf; 593 594 sli->physIndicators = lf->ctrl.led_mask; 595 sli->autoState = 0; 596 sli->explicitState = lf->ctrl.led_values; 597 sli->effectiveState = lf->ctrl.led_values; 598 sli->maps = NULL; 599 sli->names = NULL; 600 } 601 else 602 return NULL; 603 if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask)) 604 sli->names = calloc(XkbNumIndicators, sizeof(Atom)); 605 if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask)) 606 sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); 607 if (checkNames) { 608 register unsigned i, bit; 609 610 sli->namesPresent = 0; 611 for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) { 612 if (sli->names[i] != None) 613 sli->namesPresent |= bit; 614 } 615 } 616 if (checkAccel) 617 XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask); 618 return sli; 619} 620 621void 622XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli) 623{ 624 if ((sli->flags & XkbSLI_IsDefault) == 0) { 625 free(sli->maps); 626 free(sli->names); 627 } 628 sli->maps = NULL; 629 sli->names = NULL; 630 free(sli); 631 return; 632} 633 634/* 635 * XkbSrvLedInfoPtr 636 * XkbCopySrvLedInfo(dev,src,kf,lf) 637 * 638 * Takes the given XkbSrvLedInfoPtr and duplicates it. A deep copy is made, 639 * thus the new copy behaves like the original one and can be freed with 640 * XkbFreeSrvLedInfo. 641 */ 642XkbSrvLedInfoPtr 643XkbCopySrvLedInfo(DeviceIntPtr from, 644 XkbSrvLedInfoPtr src, KbdFeedbackPtr kf, LedFeedbackPtr lf) 645{ 646 XkbSrvLedInfoPtr sli_new = NULL; 647 648 if (!src) 649 goto finish; 650 651 sli_new = calloc(1, sizeof(XkbSrvLedInfoRec)); 652 if (!sli_new) 653 goto finish; 654 655 memcpy(sli_new, src, sizeof(XkbSrvLedInfoRec)); 656 if (sli_new->class == KbdFeedbackClass) 657 sli_new->fb.kf = kf; 658 else 659 sli_new->fb.lf = lf; 660 661 if (!(sli_new->flags & XkbSLI_IsDefault)) { 662 sli_new->names = calloc(XkbNumIndicators, sizeof(Atom)); 663 sli_new->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); 664 } /* else sli_new->names/maps is pointing to 665 dev->key->xkbInfo->desc->names->indicators; 666 dev->key->xkbInfo->desc->names->indicators; */ 667 668 finish: 669 return sli_new; 670} 671 672/***====================================================================***/ 673 674 /* 675 * XkbSrvLedInfoPtr 676 * XkbFindSrvLedInfo(dev,class,id,needed_parts) 677 * 678 * Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id' 679 * on the device specified by 'dev.' If the class and id specify 680 * a valid device feedback, this function returns the existing 681 * feedback or allocates a new one. 682 * 683 */ 684 685XkbSrvLedInfoPtr 686XkbFindSrvLedInfo(DeviceIntPtr dev, 687 unsigned class, unsigned id, unsigned needed_parts) 688{ 689 XkbSrvLedInfoPtr sli; 690 691 /* optimization to check for most common case */ 692 if (((class == XkbDfltXIClass) && (id == XkbDfltXIId)) && (dev->kbdfeed)) { 693 if (dev->kbdfeed->xkb_sli == NULL) { 694 dev->kbdfeed->xkb_sli = 695 XkbAllocSrvLedInfo(dev, dev->kbdfeed, NULL, needed_parts); 696 } 697 return dev->kbdfeed->xkb_sli; 698 } 699 700 sli = NULL; 701 if (class == XkbDfltXIClass) { 702 if (dev->kbdfeed) 703 class = KbdFeedbackClass; 704 else if (dev->leds) 705 class = LedFeedbackClass; 706 else 707 return NULL; 708 } 709 if (class == KbdFeedbackClass) { 710 KbdFeedbackPtr kf; 711 712 for (kf = dev->kbdfeed; kf != NULL; kf = kf->next) { 713 if ((id == XkbDfltXIId) || (id == kf->ctrl.id)) { 714 if (kf->xkb_sli == NULL) 715 kf->xkb_sli = 716 XkbAllocSrvLedInfo(dev, kf, NULL, needed_parts); 717 sli = kf->xkb_sli; 718 break; 719 } 720 } 721 } 722 else if (class == LedFeedbackClass) { 723 LedFeedbackPtr lf; 724 725 for (lf = dev->leds; lf != NULL; lf = lf->next) { 726 if ((id == XkbDfltXIId) || (id == lf->ctrl.id)) { 727 if (lf->xkb_sli == NULL) 728 lf->xkb_sli = 729 XkbAllocSrvLedInfo(dev, NULL, lf, needed_parts); 730 sli = lf->xkb_sli; 731 break; 732 } 733 } 734 } 735 if (sli) { 736 if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask)) 737 sli->names = calloc(XkbNumIndicators, sizeof(Atom)); 738 if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask)) 739 sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec)); 740 } 741 return sli; 742} 743 744/***====================================================================***/ 745 746void 747XkbFlushLedEvents(DeviceIntPtr dev, 748 DeviceIntPtr kbd, 749 XkbSrvLedInfoPtr sli, 750 xkbExtensionDeviceNotify * ed, 751 XkbChangesPtr changes, XkbEventCausePtr cause) 752{ 753 if (changes) { 754 if (changes->indicators.state_changes) 755 XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState); 756 XkbSendNotification(kbd, changes, cause); 757 memset((char *) changes, 0, sizeof(XkbChangesRec)); 758 759 if (XkbAX_NeedFeedback 760 (kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) { 761 if (sli->effectiveState) 762 /* it appears that the which parameter is not used */ 763 XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask); 764 else 765 XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask); 766 } 767 } 768 if (ed) { 769 if (ed->reason) { 770 if ((dev != kbd) && (ed->reason & XkbXI_IndicatorStateMask)) 771 XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState); 772 XkbSendExtensionDeviceNotify(dev, cause->client, ed); 773 } 774 memset((char *) ed, 0, sizeof(XkbExtensionDeviceNotify)); 775 } 776 return; 777} 778 779/***====================================================================***/ 780 781void 782XkbApplyLedNameChanges(DeviceIntPtr dev, 783 XkbSrvLedInfoPtr sli, 784 unsigned changed_names, 785 xkbExtensionDeviceNotify * ed, 786 XkbChangesPtr changes, XkbEventCausePtr cause) 787{ 788 DeviceIntPtr kbd; 789 XkbChangesRec my_changes; 790 xkbExtensionDeviceNotify my_ed; 791 792 if (changed_names == 0) 793 return; 794 if (dev->key && dev->key->xkbInfo) 795 kbd = dev; 796 else 797 kbd = inputInfo.keyboard; 798 799 if (ed == NULL) { 800 ed = &my_ed; 801 memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify)); 802 } 803 else if ((ed->reason & XkbXI_IndicatorsMask) && 804 ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) { 805 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 806 } 807 808 if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) { 809 if (changes == NULL) { 810 changes = &my_changes; 811 memset((char *) changes, 0, sizeof(XkbChangesRec)); 812 } 813 changes->names.changed |= XkbIndicatorNamesMask; 814 changes->names.changed_indicators |= changed_names; 815 } 816 817 ed->reason |= XkbXI_IndicatorNamesMask; 818 ed->ledClass = sli->class; 819 ed->ledID = sli->id; 820 ed->ledsDefined = sli->namesPresent | sli->mapsPresent; 821 ed->ledState = sli->effectiveState; 822 ed->unsupported = 0; 823 ed->supported = XkbXI_AllFeaturesMask; 824 825 if (changes != &my_changes) 826 changes = NULL; 827 if (ed != &my_ed) 828 ed = NULL; 829 if (changes || ed) 830 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 831 return; 832} 833 834/***====================================================================***/ 835 836 /* 837 * void 838 * XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause) 839 * 840 * Handles all of the secondary effects of the changes to the 841 * feedback specified by 'sli' on the device specified by 'dev.' 842 * 843 * If 'changed_maps' specifies any indicators, this function generates 844 * XkbExtensionDeviceNotify events and possibly IndicatorMapNotify 845 * events to report the changes, and recalculates the effective 846 * state of each indicator with a changed map. If any indicators 847 * change state, the server generates XkbExtensionDeviceNotify and 848 * XkbIndicatorStateNotify events as appropriate. 849 * 850 * If 'changes' is non-NULL, this function updates it to reflect 851 * any changes to the keyboard state or controls or to the 'core' 852 * indicator names, maps, or state. If 'changes' is NULL, this 853 * function generates XKB events as needed to report the changes. 854 * If 'dev' is not a keyboard device, any changes are reported 855 * for the core keyboard. 856 * 857 * The 'cause' specifies the reason for the event (key event or 858 * request) for the change, as reported in some XKB events. 859 */ 860 861void 862XkbApplyLedMapChanges(DeviceIntPtr dev, 863 XkbSrvLedInfoPtr sli, 864 unsigned changed_maps, 865 xkbExtensionDeviceNotify * ed, 866 XkbChangesPtr changes, XkbEventCausePtr cause) 867{ 868 DeviceIntPtr kbd; 869 XkbChangesRec my_changes; 870 xkbExtensionDeviceNotify my_ed; 871 872 if (changed_maps == 0) 873 return; 874 if (dev->key && dev->key->xkbInfo) 875 kbd = dev; 876 else 877 kbd = inputInfo.keyboard; 878 879 if (ed == NULL) { 880 ed = &my_ed; 881 memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify)); 882 } 883 else if ((ed->reason & XkbXI_IndicatorsMask) && 884 ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) { 885 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 886 } 887 888 if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) { 889 if (changes == NULL) { 890 changes = &my_changes; 891 memset((char *) changes, 0, sizeof(XkbChangesRec)); 892 } 893 changes->indicators.map_changes |= changed_maps; 894 } 895 896 XkbCheckIndicatorMaps(dev, sli, changed_maps); 897 898 ed->reason |= XkbXI_IndicatorMapsMask; 899 ed->ledClass = sli->class; 900 ed->ledID = sli->id; 901 ed->ledsDefined = sli->namesPresent | sli->mapsPresent; 902 ed->ledState = sli->effectiveState; 903 ed->unsupported = 0; 904 ed->supported = XkbXI_AllFeaturesMask; 905 906 XkbUpdateLedAutoState(dev, sli, changed_maps, ed, changes, cause); 907 908 if (changes != &my_changes) 909 changes = NULL; 910 if (ed != &my_ed) 911 ed = NULL; 912 if (changes || ed) 913 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 914 return; 915} 916 917/***====================================================================***/ 918 919void 920XkbApplyLedStateChanges(DeviceIntPtr dev, 921 XkbSrvLedInfoPtr sli, 922 unsigned changed_leds, 923 xkbExtensionDeviceNotify * ed, 924 XkbChangesPtr changes, XkbEventCausePtr cause) 925{ 926 XkbSrvInfoPtr xkbi; 927 DeviceIntPtr kbd; 928 XkbChangesRec my_changes; 929 xkbExtensionDeviceNotify my_ed; 930 register unsigned i, bit, affected; 931 XkbIndicatorMapPtr map; 932 unsigned oldState; 933 Bool kb_changed; 934 935 if (changed_leds == 0) 936 return; 937 if (dev->key && dev->key->xkbInfo) 938 kbd = dev; 939 else 940 kbd = inputInfo.keyboard; 941 xkbi = kbd->key->xkbInfo; 942 943 if (changes == NULL) { 944 changes = &my_changes; 945 memset((char *) changes, 0, sizeof(XkbChangesRec)); 946 } 947 948 kb_changed = FALSE; 949 affected = changed_leds; 950 oldState = sli->effectiveState; 951 for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) { 952 if ((affected & bit) == 0) 953 continue; 954 affected &= ~bit; 955 map = &sli->maps[i]; 956 if (map->flags & XkbIM_NoExplicit) { 957 sli->explicitState &= ~bit; 958 continue; 959 } 960 if (map->flags & XkbIM_LEDDrivesKB) { 961 Bool on = ((sli->explicitState & bit) != 0); 962 963 if (XkbApplyLEDChangeToKeyboard(xkbi, map, on, changes)) 964 kb_changed = TRUE; 965 } 966 } 967 sli->effectiveState = (sli->autoState | sli->explicitState); 968 affected = sli->effectiveState ^ oldState; 969 970 if (ed == NULL) { 971 ed = &my_ed; 972 memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify)); 973 } 974 else if (affected && (ed->reason & XkbXI_IndicatorsMask) && 975 ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) { 976 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 977 } 978 979 if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) 980 changes->indicators.state_changes |= affected; 981 if (affected) { 982 ed->reason |= XkbXI_IndicatorStateMask; 983 ed->ledClass = sli->class; 984 ed->ledID = sli->id; 985 ed->ledsDefined = sli->namesPresent | sli->mapsPresent; 986 ed->ledState = sli->effectiveState; 987 ed->unsupported = 0; 988 ed->supported = XkbXI_AllFeaturesMask; 989 } 990 991 if (kb_changed) { 992 XkbComputeDerivedState(kbd->key->xkbInfo); 993 XkbUpdateLedAutoState(dev, sli, sli->mapsPresent, ed, changes, cause); 994 } 995 996 if (changes != &my_changes) 997 changes = NULL; 998 if (ed != &my_ed) 999 ed = NULL; 1000 if (changes || ed) 1001 XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause); 1002 if (kb_changed) 1003 XkbUpdateAllDeviceIndicators(NULL, cause); 1004 return; 1005} 1006