xkbEvents.c 35.9 KB
Newer Older
1 2 3 4 5 6 7 8
/************************************************************
Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.

Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
9 10
documentation, and that the name of Silicon Graphics not be
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 14 15
of this software for any purpose. It is provided "as is"
without any express or implied warranty.

16 17
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 20 21
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 23 24 25 26
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
THE USE OR PERFORMANCE OF THIS SOFTWARE.

********************************************************/

27 28 29 30
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

31 32 33 34
#include <stdio.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include <X11/keysym.h>
35
#include <X11/extensions/XI.h>
36
#include <X11/extensions/XIproto.h>
37
#include "inputstr.h"
38 39
#include "exevents.h"
#include "exglobals.h"
40
#include "windowstr.h"
41
#include <xkbsrv.h>
42
#include "xkb.h"
43 44 45

/***====================================================================***/

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
/*
 * This function sends out two kinds of notification:
 *   - Core mapping notify events sent to clients for whom kbd is the
 *     current core ('picked') keyboard _and_ have not explicitly
 *     selected for XKB mapping notify events;
 *   - Xi mapping events, sent unconditionally to all clients who have
 *     explicitly selected for them (including those who have explicitly
 *     selected for XKB mapping notify events!).
 */
static void
XkbSendLegacyMapNotify(DeviceIntPtr kbd, CARD16 xkb_event, CARD16 changed,
                       int first_key, int num_keys)
{
    int i;
    int keymap_changed = 0;
    int modmap_changed = 0;
    CARD32 time = GetTimeInMillis();

    if (xkb_event == XkbNewKeyboardNotify) {
        if (changed & XkbNKN_KeycodesMask) {
            keymap_changed = 1;
            modmap_changed = 1;
        }
    }
    else if (xkb_event == XkbMapNotify) {
        if (changed & XkbKeySymsMask)
            keymap_changed = 1;
        if (changed & XkbModifierMapMask)
            modmap_changed = 1;
    }
    if (!keymap_changed && !modmap_changed)
        return;

    /* 0 is serverClient. */
    for (i = 1; i < currentMaxClients; i++) {
        if (!clients[i] || clients[i]->clientState != ClientStateRunning)
            continue;

84 85 86 87 88
        /* XKB allows clients to restrict the MappingNotify events sent to
         * them.  This was broken for three years.  Sorry. */
        if (xkb_event == XkbMapNotify &&
            (clients[i]->xkbClientFlags & _XkbClientInitialized) &&
            !(clients[i]->mapNotifyMask & changed))
89
            continue;
90 91 92
        /* Emulate previous server behaviour: any client which has activated
         * XKB will not receive core events emulated from a NewKeyboardNotify
         * at all. */
93 94 95 96 97 98 99 100 101
        if (xkb_event == XkbNewKeyboardNotify &&
            (clients[i]->xkbClientFlags & _XkbClientInitialized))
            continue;

        /* Don't send core events to clients who don't know about us. */
        if (!XIShouldNotify(clients[i], kbd))
            continue;

        if (keymap_changed) {
102
            xEvent core_mn = { .u.u.type = MappingNotify };
103 104 105 106 107 108 109 110 111 112 113 114
            core_mn.u.mappingNotify.request = MappingKeyboard;

            /* Clip the keycode range to what the client knows about, so it
             * doesn't freak out. */
            if (first_key >= clients[i]->minKC)
                core_mn.u.mappingNotify.firstKeyCode = first_key;
            else
                core_mn.u.mappingNotify.firstKeyCode = clients[i]->minKC;
            if (first_key + num_keys - 1 <= clients[i]->maxKC)
                core_mn.u.mappingNotify.count = num_keys;
            else
                core_mn.u.mappingNotify.count = clients[i]->maxKC -
115
                    clients[i]->minKC + 1;
116 117 118 119

            WriteEventsToClient(clients[i], 1, &core_mn);
        }
        if (modmap_changed) {
120 121 122 123 124 125
            xEvent core_mn = {
                .u.mappingNotify.request = MappingModifier,
                .u.mappingNotify.firstKeyCode = 0,
                .u.mappingNotify.count = 0
            };
            core_mn.u.u.type = MappingNotify;
126 127 128 129 130 131 132 133
            WriteEventsToClient(clients[i], 1, &core_mn);
        }
    }

    /* Hmm, maybe we can accidentally generate Xi events for core devices
     * here? Clients might be upset, but that seems better than the
     * alternative of stale keymaps. -ds */
    if (keymap_changed) {
134 135 136 137 138 139 140 141
        deviceMappingNotify xi_mn = {
            .type = DeviceMappingNotify,
            .deviceid = kbd->id,
            .request = MappingKeyboard,
            .firstKeyCode = first_key,
            .count = num_keys,
            .time = time
        };
142 143 144 145
        SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
                              1);
    }
    if (modmap_changed) {
146 147 148 149 150 151 152 153
        deviceMappingNotify xi_mn = {
            .type = DeviceMappingNotify,
            .deviceid = kbd->id,
            .request = MappingModifier,
            .firstKeyCode = 0,
            .count = 0,
            .time = time
        };
154 155 156 157 158 159 160
        SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
                              1);
    }
}

/***====================================================================***/

161
void
162
XkbSendNewKeyboardNotify(DeviceIntPtr kbd, xkbNewKeyboardNotify * pNKN)
163 164 165 166
{
    int i;
    Time time = GetTimeInMillis();
    CARD16 changed = pNKN->changed;
167 168 169 170

    pNKN->type = XkbEventCode + XkbEventBase;
    pNKN->xkbType = XkbNewKeyboardNotify;

171
    for (i = 1; i < currentMaxClients; i++) {
172 173 174 175 176 177 178 179 180 181
        if (!clients[i] || clients[i]->clientState != ClientStateRunning)
            continue;

        if (!(clients[i]->newKeyboardNotifyMask & changed))
            continue;

        pNKN->sequenceNumber = clients[i]->sequence;
        pNKN->time = time;
        pNKN->changed = changed;
        if (clients[i]->swapped) {
182 183 184
            swaps(&pNKN->sequenceNumber);
            swapl(&pNKN->time);
            swaps(&pNKN->changed);
185 186 187 188 189 190 191
        }
        WriteToClient(clients[i], sizeof(xEvent), pNKN);

        if (changed & XkbNKN_KeycodesMask) {
            clients[i]->minKC = pNKN->minKeyCode;
            clients[i]->maxKC = pNKN->maxKeyCode;
        }
192
    }
193 194 195 196

    XkbSendLegacyMapNotify(kbd, XkbNewKeyboardNotify, changed, pNKN->minKeyCode,
                           pNKN->maxKeyCode - pNKN->minKeyCode + 1);

197 198 199 200 201
    return;
}

/***====================================================================***/

202
void
203
XkbSendStateNotify(DeviceIntPtr kbd, xkbStateNotify * pSN)
204
{
205 206 207 208 209
    XkbSrvInfoPtr xkbi;
    XkbStatePtr state;
    XkbInterestPtr interest;
    Time time;
    register CARD16 changed, bState;
210 211

    interest = kbd->xkb_interest;
212
    if (!interest || !kbd->key || !kbd->key->xkbInfo)
213
        return;
214
    xkbi = kbd->key->xkbInfo;
215
    state = &xkbi->state;
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

    pSN->type = XkbEventCode + XkbEventBase;
    pSN->xkbType = XkbStateNotify;
    pSN->deviceID = kbd->id;
    pSN->time = time = GetTimeInMillis();
    pSN->mods = state->mods;
    pSN->baseMods = state->base_mods;
    pSN->latchedMods = state->latched_mods;
    pSN->lockedMods = state->locked_mods;
    pSN->group = state->group;
    pSN->baseGroup = state->base_group;
    pSN->latchedGroup = state->latched_group;
    pSN->lockedGroup = state->locked_group;
    pSN->compatState = state->compat_state;
    pSN->grabMods = state->grab_mods;
    pSN->compatGrabMods = state->compat_grab_mods;
    pSN->lookupMods = state->lookup_mods;
    pSN->compatLookupMods = state->compat_lookup_mods;
    pSN->ptrBtnState = state->ptr_buttons;
    changed = pSN->changed;
236
    bState = pSN->ptrBtnState;
237 238

    while (interest) {
239 240 241 242 243 244 245 246 247 248 249 250 251
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->stateNotifyMask & changed)) {
            pSN->sequenceNumber = interest->client->sequence;
            pSN->time = time;
            pSN->changed = changed;
            pSN->ptrBtnState = bState;
            if (interest->client->swapped) {
                swaps(&pSN->sequenceNumber);
                swapl(&pSN->time);
                swaps(&pSN->changed);
                swaps(&pSN->ptrBtnState);
            }
252
            WriteToClient(interest->client, sizeof(xEvent), pSN);
253 254
        }
        interest = interest->next;
255 256 257 258 259 260
    }
    return;
}

/***====================================================================***/

261 262 263 264
/*
 * This function sends out XKB mapping notify events to clients which
 * have explicitly selected for them.  Core and Xi events are handled by
 * XkbSendLegacyMapNotify. */
265
void
266
XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify * pMN)
267
{
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    int i;
    CARD32 time = GetTimeInMillis();
    CARD16 changed = pMN->changed;
    XkbSrvInfoPtr xkbi = kbd->key->xkbInfo;

    pMN->minKeyCode = xkbi->desc->min_key_code;
    pMN->maxKeyCode = xkbi->desc->max_key_code;
    pMN->type = XkbEventCode + XkbEventBase;
    pMN->xkbType = XkbMapNotify;
    pMN->deviceID = kbd->id;

    /* 0 is serverClient. */
    for (i = 1; i < currentMaxClients; i++) {
        if (!clients[i] || clients[i]->clientState != ClientStateRunning)
            continue;

        if (!(clients[i]->mapNotifyMask & changed))
            continue;

        pMN->time = time;
        pMN->sequenceNumber = clients[i]->sequence;
        pMN->changed = changed;

        if (clients[i]->swapped) {
292 293 294
            swaps(&pMN->sequenceNumber);
            swapl(&pMN->time);
            swaps(&pMN->changed);
295 296
        }
        WriteToClient(clients[i], sizeof(xEvent), pMN);
297
    }
298 299 300

    XkbSendLegacyMapNotify(kbd, XkbMapNotify, changed, pMN->firstKeySym,
                           pMN->nKeySyms);
301 302
}

303
int
304 305 306 307
XkbComputeControlsNotify(DeviceIntPtr kbd,
                         XkbControlsPtr old,
                         XkbControlsPtr new,
                         xkbControlsNotify * pCN, Bool forceCtrlProc)
308
{
309 310
    int i;
    CARD32 changedControls;
311

312
    changedControls = 0;
313 314 315

    if (!kbd || !kbd->kbdfeed)
        return 0;
316 317 318 319 320 321

    if (old->enabled_ctrls != new->enabled_ctrls)
        changedControls |= XkbControlsEnabledMask;
    if ((old->repeat_delay != new->repeat_delay) ||
        (old->repeat_interval != new->repeat_interval))
        changedControls |= XkbRepeatKeysMask;
322
    for (i = 0; i < XkbPerKeyBitArraySize; i++)
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
        if (old->per_key_repeat[i] != new->per_key_repeat[i])
            changedControls |= XkbPerKeyRepeatMask;
    if (old->slow_keys_delay != new->slow_keys_delay)
        changedControls |= XkbSlowKeysMask;
    if (old->debounce_delay != new->debounce_delay)
        changedControls |= XkbBounceKeysMask;
    if ((old->mk_delay != new->mk_delay) ||
        (old->mk_interval != new->mk_interval) ||
        (old->mk_dflt_btn != new->mk_dflt_btn))
        changedControls |= XkbMouseKeysMask;
    if ((old->mk_time_to_max != new->mk_time_to_max) ||
        (old->mk_curve != new->mk_curve) ||
        (old->mk_max_speed != new->mk_max_speed))
        changedControls |= XkbMouseKeysAccelMask;
    if (old->ax_options != new->ax_options)
        changedControls |= XkbAccessXKeysMask;
    if ((old->ax_options ^ new->ax_options) & XkbAX_SKOptionsMask)
        changedControls |= XkbStickyKeysMask;
    if ((old->ax_options ^ new->ax_options) & XkbAX_FBOptionsMask)
        changedControls |= XkbAccessXFeedbackMask;
    if ((old->ax_timeout != new->ax_timeout) ||
        (old->axt_ctrls_mask != new->axt_ctrls_mask) ||
        (old->axt_ctrls_values != new->axt_ctrls_values) ||
        (old->axt_opts_mask != new->axt_opts_mask) ||
        (old->axt_opts_values != new->axt_opts_values)) {
        changedControls |= XkbAccessXTimeoutMask;
349
    }
350 351 352 353 354 355 356 357 358 359 360 361 362
    if ((old->internal.mask != new->internal.mask) ||
        (old->internal.real_mods != new->internal.real_mods) ||
        (old->internal.vmods != new->internal.vmods))
        changedControls |= XkbInternalModsMask;
    if ((old->ignore_lock.mask != new->ignore_lock.mask) ||
        (old->ignore_lock.real_mods != new->ignore_lock.real_mods) ||
        (old->ignore_lock.vmods != new->ignore_lock.vmods))
        changedControls |= XkbIgnoreLockModsMask;

    if (new->enabled_ctrls & XkbRepeatKeysMask)
        kbd->kbdfeed->ctrl.autoRepeat = TRUE;
    else
        kbd->kbdfeed->ctrl.autoRepeat = FALSE;
363 364

    if (kbd->kbdfeed && kbd->kbdfeed->CtrlProc &&
365 366
        (changedControls || forceCtrlProc))
        (*kbd->kbdfeed->CtrlProc) (kbd, &kbd->kbdfeed->ctrl);
367

368 369
    if ((!changedControls) && (old->num_groups == new->num_groups))
        return 0;
370 371

    if (!kbd->xkb_interest)
372
        return 0;
373 374 375

    pCN->changedControls = changedControls;
    pCN->enabledControls = new->enabled_ctrls;
376
    pCN->enabledControlChanges = (new->enabled_ctrls ^ old->enabled_ctrls);
377 378 379 380 381
    pCN->numGroups = new->num_groups;

    return 1;
}

382
void
383
XkbSendControlsNotify(DeviceIntPtr kbd, xkbControlsNotify * pCN)
384
{
385 386 387 388 389
    int initialized;
    CARD32 changedControls, enabledControls, enabledChanges = 0;
    XkbSrvInfoPtr xkbi;
    XkbInterestPtr interest;
    Time time = 0;
390 391

    interest = kbd->xkb_interest;
392
    if (!interest || !kbd->key || !kbd->key->xkbInfo)
393
        return;
394
    xkbi = kbd->key->xkbInfo;
395

396 397 398
    initialized = 0;
    enabledControls = xkbi->desc->ctrls->enabled_ctrls;
    changedControls = pCN->changedControls;
399
    pCN->numGroups = xkbi->desc->ctrls->num_groups;
400
    while (interest) {
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->ctrlsNotifyMask & changedControls)) {
            if (!initialized) {
                pCN->type = XkbEventCode + XkbEventBase;
                pCN->xkbType = XkbControlsNotify;
                pCN->deviceID = kbd->id;
                pCN->time = time = GetTimeInMillis();
                enabledChanges = pCN->enabledControlChanges;
                initialized = 1;
            }
            pCN->changedControls = changedControls;
            pCN->enabledControls = enabledControls;
            pCN->enabledControlChanges = enabledChanges;
            pCN->sequenceNumber = interest->client->sequence;
            pCN->time = time;
            if (interest->client->swapped) {
                swaps(&pCN->sequenceNumber);
                swapl(&pCN->changedControls);
                swapl(&pCN->enabledControls);
                swapl(&pCN->enabledControlChanges);
                swapl(&pCN->time);
            }
424
            WriteToClient(interest->client, sizeof(xEvent), pCN);
425 426
        }
        interest = interest->next;
427 428 429 430
    }
    return;
}

431
static void
432
XkbSendIndicatorNotify(DeviceIntPtr kbd, int xkbType, xkbIndicatorNotify * pEv)
433
{
434 435 436 437
    int initialized;
    XkbInterestPtr interest;
    Time time = 0;
    CARD32 state, changed;
438 439 440

    interest = kbd->xkb_interest;
    if (!interest)
441 442
        return;

443 444 445 446
    initialized = 0;
    state = pEv->state;
    changed = pEv->changed;
    while (interest) {
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (((xkbType == XkbIndicatorStateNotify) &&
              (interest->iStateNotifyMask & changed)) ||
             ((xkbType == XkbIndicatorMapNotify) &&
              (interest->iMapNotifyMask & changed)))) {
            if (!initialized) {
                pEv->type = XkbEventCode + XkbEventBase;
                pEv->xkbType = xkbType;
                pEv->deviceID = kbd->id;
                pEv->time = time = GetTimeInMillis();
                initialized = 1;
            }
            pEv->sequenceNumber = interest->client->sequence;
            pEv->time = time;
            pEv->changed = changed;
            pEv->state = state;
            if (interest->client->swapped) {
                swaps(&pEv->sequenceNumber);
                swapl(&pEv->time);
                swapl(&pEv->changed);
                swapl(&pEv->state);
            }
470
            WriteToClient(interest->client, sizeof(xEvent), pEv);
471 472
        }
        interest = interest->next;
473 474 475 476
    }
    return;
}

477
void
478 479 480 481
XkbHandleBell(BOOL force,
              BOOL eventOnly,
              DeviceIntPtr kbd,
              CARD8 percent,
482
              void *pCtrl,
483
              CARD8 class, Atom name, WindowPtr pWin, ClientPtr pClient)
484
{
485 486 487 488 489 490 491 492
    xkbBellNotify bn;
    int initialized;
    XkbSrvInfoPtr xkbi;
    XkbInterestPtr interest;
    CARD8 id;
    CARD16 pitch, duration;
    Time time = 0;
    XID winID = 0;
493

494 495 496
    if (!kbd->key || !kbd->key->xkbInfo)
        return;

497 498
    xkbi = kbd->key->xkbInfo;

499 500
    if ((force || (xkbi->desc->ctrls->enabled_ctrls & XkbAudibleBellMask)) &&
        (!eventOnly)) {
501
        if (kbd->kbdfeed->BellProc)
502
            (*kbd->kbdfeed->BellProc) (percent, kbd, (void *) pCtrl, class);
503 504
    }
    interest = kbd->xkb_interest;
505 506 507
    if ((!interest) || (force))
        return;

508
    if (class == KbdFeedbackClass) {
509 510 511 512 513
        KeybdCtrl *pKeyCtrl = (KeybdCtrl *) pCtrl;

        id = pKeyCtrl->id;
        pitch = pKeyCtrl->bell_pitch;
        duration = pKeyCtrl->bell_duration;
514
    }
515 516 517 518 519 520
    else if (class == BellFeedbackClass) {
        BellCtrl *pBellCtrl = (BellCtrl *) pCtrl;

        id = pBellCtrl->id;
        pitch = pBellCtrl->pitch;
        duration = pBellCtrl->duration;
521
    }
522 523 524
    else
        return;

525 526
    initialized = 0;
    while (interest) {
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->bellNotifyMask)) {
            if (!initialized) {
                time = GetTimeInMillis();
                bn.type = XkbEventCode + XkbEventBase;
                bn.xkbType = XkbBellNotify;
                bn.deviceID = kbd->id;
                bn.bellClass = class;
                bn.bellID = id;
                bn.percent = percent;
                bn.eventOnly = (eventOnly != 0);
                winID = (pWin ? pWin->drawable.id : None);
                initialized = 1;
            }
            bn.sequenceNumber = interest->client->sequence;
            bn.time = time;
            bn.pitch = pitch;
            bn.duration = duration;
            bn.name = name;
            bn.window = winID;
            if (interest->client->swapped) {
                swaps(&bn.sequenceNumber);
                swapl(&bn.time);
                swaps(&bn.pitch);
                swaps(&bn.duration);
                swapl(&bn.name);
                swapl(&bn.window);
            }
556
            WriteToClient(interest->client, sizeof(xEvent), &bn);
557 558
        }
        interest = interest->next;
559 560 561 562
    }
    return;
}

563
void
564
XkbSendAccessXNotify(DeviceIntPtr kbd, xkbAccessXNotify * pEv)
565
{
566 567 568 569
    int initialized;
    XkbInterestPtr interest;
    Time time = 0;
    CARD16 sk_delay, db_delay;
570 571 572

    interest = kbd->xkb_interest;
    if (!interest)
573 574
        return;

575
    initialized = 0;
576 577
    sk_delay = pEv->slowKeysDelay;
    db_delay = pEv->debounceDelay;
578
    while (interest) {
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->accessXNotifyMask & (1 << pEv->detail))) {
            if (!initialized) {
                pEv->type = XkbEventCode + XkbEventBase;
                pEv->xkbType = XkbAccessXNotify;
                pEv->deviceID = kbd->id;
                pEv->time = time = GetTimeInMillis();
                initialized = 1;
            }
            pEv->sequenceNumber = interest->client->sequence;
            pEv->time = time;
            pEv->slowKeysDelay = sk_delay;
            pEv->debounceDelay = db_delay;
            if (interest->client->swapped) {
                swaps(&pEv->sequenceNumber);
                swapl(&pEv->time);
                swaps(&pEv->slowKeysDelay);
                swaps(&pEv->debounceDelay);
            }
599
            WriteToClient(interest->client, sizeof(xEvent), pEv);
600 601
        }
        interest = interest->next;
602 603 604 605
    }
    return;
}

606
void
607
XkbSendNamesNotify(DeviceIntPtr kbd, xkbNamesNotify * pEv)
608
{
609 610 611 612 613
    int initialized;
    XkbInterestPtr interest;
    Time time = 0;
    CARD16 changed, changedVirtualMods;
    CARD32 changedIndicators;
614 615 616

    interest = kbd->xkb_interest;
    if (!interest)
617 618
        return;

619
    initialized = 0;
620 621 622
    changed = pEv->changed;
    changedIndicators = pEv->changedIndicators;
    changedVirtualMods = pEv->changedVirtualMods;
623
    while (interest) {
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->namesNotifyMask & pEv->changed)) {
            if (!initialized) {
                pEv->type = XkbEventCode + XkbEventBase;
                pEv->xkbType = XkbNamesNotify;
                pEv->deviceID = kbd->id;
                pEv->time = time = GetTimeInMillis();
                initialized = 1;
            }
            pEv->sequenceNumber = interest->client->sequence;
            pEv->time = time;
            pEv->changed = changed;
            pEv->changedIndicators = changedIndicators;
            pEv->changedVirtualMods = changedVirtualMods;
            if (interest->client->swapped) {
                swaps(&pEv->sequenceNumber);
                swapl(&pEv->time);
                swaps(&pEv->changed);
                swapl(&pEv->changedIndicators);
                swaps(&pEv->changedVirtualMods);
            }
646
            WriteToClient(interest->client, sizeof(xEvent), pEv);
647 648
        }
        interest = interest->next;
649 650 651 652
    }
    return;
}

653
void
654
XkbSendCompatMapNotify(DeviceIntPtr kbd, xkbCompatMapNotify * pEv)
655
{
656 657 658 659
    int initialized;
    XkbInterestPtr interest;
    Time time = 0;
    CARD16 firstSI = 0, nSI = 0, nTotalSI = 0;
660 661 662

    interest = kbd->xkb_interest;
    if (!interest)
663 664
        return;

665 666
    initialized = 0;
    while (interest) {
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->compatNotifyMask)) {
            if (!initialized) {
                pEv->type = XkbEventCode + XkbEventBase;
                pEv->xkbType = XkbCompatMapNotify;
                pEv->deviceID = kbd->id;
                pEv->time = time = GetTimeInMillis();
                firstSI = pEv->firstSI;
                nSI = pEv->nSI;
                nTotalSI = pEv->nTotalSI;
                initialized = 1;
            }
            pEv->sequenceNumber = interest->client->sequence;
            pEv->time = time;
            pEv->firstSI = firstSI;
            pEv->nSI = nSI;
            pEv->nTotalSI = nTotalSI;
            if (interest->client->swapped) {
                swaps(&pEv->sequenceNumber);
                swapl(&pEv->time);
                swaps(&pEv->firstSI);
                swaps(&pEv->nSI);
                swaps(&pEv->nTotalSI);
            }
692
            WriteToClient(interest->client, sizeof(xEvent), pEv);
693 694
        }
        interest = interest->next;
695 696 697 698
    }
    return;
}

699
void
700
XkbSendActionMessage(DeviceIntPtr kbd, xkbActionMessage * pEv)
701
{
702 703 704 705
    int initialized;
    XkbSrvInfoPtr xkbi;
    XkbInterestPtr interest;
    Time time = 0;
706 707

    interest = kbd->xkb_interest;
708
    if (!interest || !kbd->key || !kbd->key->xkbInfo)
709 710
        return;

711 712
    xkbi = kbd->key->xkbInfo;

713
    initialized = 0;
714 715
    pEv->mods = xkbi->state.mods;
    pEv->group = xkbi->state.group;
716
    while (interest) {
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->actionMessageMask)) {
            if (!initialized) {
                pEv->type = XkbEventCode + XkbEventBase;
                pEv->xkbType = XkbActionMessage;
                pEv->deviceID = kbd->id;
                pEv->sequenceNumber = interest->client->sequence;
                pEv->time = time = GetTimeInMillis();
                initialized = 1;
            }
            pEv->sequenceNumber = interest->client->sequence;
            pEv->time = time;
            if (interest->client->swapped) {
                swaps(&pEv->sequenceNumber);
                swapl(&pEv->time);
            }
734
            WriteToClient(interest->client, sizeof(xEvent), pEv);
735 736
        }
        interest = interest->next;
737 738 739 740
    }
    return;
}

741
void
742 743
XkbSendExtensionDeviceNotify(DeviceIntPtr dev,
                             ClientPtr client, xkbExtensionDeviceNotify * pEv)
744
{
745 746 747 748 749
    int initialized;
    XkbInterestPtr interest;
    Time time = 0;
    CARD32 defined, state;
    CARD16 reason;
750 751 752

    interest = dev->xkb_interest;
    if (!interest)
753 754
        return;

755
    initialized = 0;
756 757 758
    reason = pEv->reason;
    defined = pEv->ledsDefined;
    state = pEv->ledState;
759
    while (interest) {
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
        if ((!interest->client->clientGone) &&
            (interest->client->xkbClientFlags & _XkbClientInitialized) &&
            (interest->extDevNotifyMask & reason)) {
            if (!initialized) {
                pEv->type = XkbEventCode + XkbEventBase;
                pEv->xkbType = XkbExtensionDeviceNotify;
                pEv->deviceID = dev->id;
                pEv->sequenceNumber = interest->client->sequence;
                pEv->time = time = GetTimeInMillis();
                initialized = 1;
            }
            else {
                pEv->sequenceNumber = interest->client->sequence;
                pEv->time = time;
                pEv->ledsDefined = defined;
                pEv->ledState = state;
                pEv->reason = reason;
                pEv->supported = XkbXI_AllFeaturesMask;
            }
            if (interest->client->swapped) {
                swaps(&pEv->sequenceNumber);
                swapl(&pEv->time);
                swapl(&pEv->ledsDefined);
                swapl(&pEv->ledState);
                swaps(&pEv->reason);
                swaps(&pEv->supported);
            }
787
            WriteToClient(interest->client, sizeof(xEvent), pEv);
788 789
        }
        interest = interest->next;
790 791 792 793
    }
    return;
}

794
void
795 796
XkbSendNotification(DeviceIntPtr kbd,
                    XkbChangesPtr pChanges, XkbEventCausePtr cause)
797
{
798
    XkbSrvLedInfoPtr sli;
799

800
    sli = NULL;
801
    if (pChanges->state_changes) {
802 803 804 805 806 807 808 809
        xkbStateNotify sn;

        sn.changed = pChanges->state_changes;
        sn.keycode = cause->kc;
        sn.eventType = cause->event;
        sn.requestMajor = cause->mjr;
        sn.requestMinor = cause->mnr;
        XkbSendStateNotify(kbd, &sn);
810 811
    }
    if (pChanges->map.changed) {
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
        xkbMapNotify mn;

        memset(&mn, 0, sizeof(xkbMapNotify));
        mn.changed = pChanges->map.changed;
        mn.firstType = pChanges->map.first_type;
        mn.nTypes = pChanges->map.num_types;
        mn.firstKeySym = pChanges->map.first_key_sym;
        mn.nKeySyms = pChanges->map.num_key_syms;
        mn.firstKeyAct = pChanges->map.first_key_act;
        mn.nKeyActs = pChanges->map.num_key_acts;
        mn.firstKeyBehavior = pChanges->map.first_key_behavior;
        mn.nKeyBehaviors = pChanges->map.num_key_behaviors;
        mn.virtualMods = pChanges->map.vmods;
        mn.firstKeyExplicit = pChanges->map.first_key_explicit;
        mn.nKeyExplicit = pChanges->map.num_key_explicit;
        mn.firstModMapKey = pChanges->map.first_modmap_key;
        mn.nModMapKeys = pChanges->map.num_modmap_keys;
        mn.firstVModMapKey = pChanges->map.first_vmodmap_key;
        mn.nVModMapKeys = pChanges->map.num_vmodmap_keys;
        XkbSendMapNotify(kbd, &mn);
832
    }
833 834 835 836 837 838 839 840 841 842 843 844
    if ((pChanges->ctrls.changed_ctrls) ||
        (pChanges->ctrls.enabled_ctrls_changes)) {
        xkbControlsNotify cn;

        memset(&cn, 0, sizeof(xkbControlsNotify));
        cn.changedControls = pChanges->ctrls.changed_ctrls;
        cn.enabledControlChanges = pChanges->ctrls.enabled_ctrls_changes;
        cn.keycode = cause->kc;
        cn.eventType = cause->event;
        cn.requestMajor = cause->mjr;
        cn.requestMinor = cause->mnr;
        XkbSendControlsNotify(kbd, &cn);
845 846
    }
    if (pChanges->indicators.map_changes) {
847 848 849 850 851 852 853 854
        xkbIndicatorNotify in;

        if (sli == NULL)
            sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
        memset(&in, 0, sizeof(xkbIndicatorNotify));
        in.state = sli->effectiveState;
        in.changed = pChanges->indicators.map_changes;
        XkbSendIndicatorNotify(kbd, XkbIndicatorMapNotify, &in);
855 856
    }
    if (pChanges->indicators.state_changes) {
857 858 859 860 861 862 863 864
        xkbIndicatorNotify in;

        if (sli == NULL)
            sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
        memset(&in, 0, sizeof(xkbIndicatorNotify));
        in.state = sli->effectiveState;
        in.changed = pChanges->indicators.state_changes;
        XkbSendIndicatorNotify(kbd, XkbIndicatorStateNotify, &in);
865 866
    }
    if (pChanges->names.changed) {
867 868 869 870 871 872 873 874 875 876 877 878
        xkbNamesNotify nn;

        memset(&nn, 0, sizeof(xkbNamesNotify));
        nn.changed = pChanges->names.changed;
        nn.firstType = pChanges->names.first_type;
        nn.nTypes = pChanges->names.num_types;
        nn.firstLevelName = pChanges->names.first_lvl;
        nn.nLevelNames = pChanges->names.num_lvls;
        nn.nRadioGroups = pChanges->names.num_rg;
        nn.changedVirtualMods = pChanges->names.changed_vmods;
        nn.changedIndicators = pChanges->names.changed_indicators;
        XkbSendNamesNotify(kbd, &nn);
879
    }
880 881 882 883 884 885 886 887 888
    if ((pChanges->compat.changed_groups) || (pChanges->compat.num_si > 0)) {
        xkbCompatMapNotify cmn;

        memset(&cmn, 0, sizeof(xkbCompatMapNotify));
        cmn.changedGroups = pChanges->compat.changed_groups;
        cmn.firstSI = pChanges->compat.first_si;
        cmn.nSI = pChanges->compat.num_si;
        cmn.nTotalSI = kbd->key->xkbInfo->desc->compat->num_si;
        XkbSendCompatMapNotify(kbd, &cmn);
889 890 891 892 893 894
    }
    return;
}

/***====================================================================***/

895
void
896
XkbFilterEvents(ClientPtr client, int nEvents, xEvent *xE)
897
{
898 899 900
    DeviceIntPtr dev = NULL;
    XkbSrvInfoPtr xkbi;
    CARD8 type = xE[0].u.u.type;
901

902
    if (xE->u.u.type & EXTENSION_EVENT_BASE)
903
        dev = XIGetDevice(xE);
904

905 906
    if (!dev)
        dev = PickKeyboard(client);
907

908 909
    if (!dev->key)
        return;
910

911
    xkbi = dev->key->xkbInfo;
912

913
    if (client->xkbClientFlags & _XkbClientInitialized) {
914
        if ((xkbDebugFlags & 0x10) &&
915 916
            (type == KeyPress || type == KeyRelease ||
             type == DeviceKeyPress || type == DeviceKeyRelease))
917
            DebugF("[xkb] XkbFilterWriteEvents (XKB client): state 0x%04x\n",
918 919
                   xE[0].u.keyButtonPointer.state);

920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
        if (dev->deviceGrab.grab != NullGrab && dev->deviceGrab.fromPassiveGrab
            && (type == KeyPress || type == KeyRelease || type == DeviceKeyPress
                || type == DeviceKeyRelease)) {
            unsigned int state, flags;

            flags = client->xkbClientFlags;
            state = xkbi->state.compat_grab_mods;
            if (flags & XkbPCF_GrabsUseXKBStateMask) {
                int group;

                if (flags & XkbPCF_LookupStateWhenGrabbed) {
                    group = xkbi->state.group;
                    state = xkbi->state.lookup_mods;
                }
                else {
                    state = xkbi->state.grab_mods;
                    group = xkbi->state.base_group + xkbi->state.latched_group;
                    if (group < 0 || group >= xkbi->desc->ctrls->num_groups)
                        group = XkbAdjustGroup(group, xkbi->desc->ctrls);
                }
                state = XkbBuildCoreState(state, group);
            }
            else if (flags & XkbPCF_LookupStateWhenGrabbed) {
                state = xkbi->state.compat_lookup_mods;
944
            }
945 946
            xE[0].u.keyButtonPointer.state = state;
        }
947 948
    }
    else {
949
        if ((xkbDebugFlags & 0x4) &&
950
            (xE[0].u.u.type == KeyPress || xE[0].u.u.type == KeyRelease ||
951 952
             xE[0].u.u.type == DeviceKeyPress ||
             xE[0].u.u.type == DeviceKeyRelease)) {
953 954 955
            DebugF("[xkb] XKbFilterWriteEvents (non-XKB):\n");
            DebugF("[xkb] event= 0x%04x\n", xE[0].u.keyButtonPointer.state);
            DebugF("[xkb] lookup= 0x%02x, grab= 0x%02x\n",
956
                   xkbi->state.lookup_mods, xkbi->state.grab_mods);
957 958 959 960 961 962 963 964 965 966 967 968 969
            DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n",
                   xkbi->state.compat_lookup_mods,
                   xkbi->state.compat_grab_mods);
        }
        if (type >= KeyPress && type <= MotionNotify) {
            CARD16 old, new;

            old = xE[0].u.keyButtonPointer.state & ~0x1f00;
            new = xE[0].u.keyButtonPointer.state & 0x1F00;

            if (old == XkbStateFieldFromRec(&xkbi->state))
                new |= xkbi->state.compat_lookup_mods;
            else
970
                new |= xkbi->state.compat_grab_mods;
971 972 973 974 975 976
            xE[0].u.keyButtonPointer.state = new;
        }
        else if (type == EnterNotify || type == LeaveNotify) {
            xE[0].u.enterLeave.state &= 0x1F00;
            xE[0].u.enterLeave.state |= xkbi->state.compat_grab_mods;
        }
977 978
        else if (type >= DeviceKeyPress && type <= DeviceMotionNotify) {
            CARD16 old, new;
979
            deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer *) &xE[0];
980 981 982

            old = kbp->state & ~0x1F00;
            new = kbp->state & 0x1F00;
983 984 985
            if (old == XkbStateFieldFromRec(&xkbi->state))
                new |= xkbi->state.compat_lookup_mods;
            else
986 987 988
                new |= xkbi->state.compat_grab_mods;
            kbp->state = new;
        }
989 990 991 992 993
    }
}

/***====================================================================***/

994
XkbInterestPtr
995
XkbFindClientResource(DevicePtr inDev, ClientPtr client)
996
{
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    DeviceIntPtr dev = (DeviceIntPtr) inDev;
    XkbInterestPtr interest;

    if (dev->xkb_interest) {
        interest = dev->xkb_interest;
        while (interest) {
            if (interest->client == client) {
                return interest;
            }
            interest = interest->next;
        }
1008 1009 1010 1011
    }
    return NULL;
}

1012
XkbInterestPtr
1013
XkbAddClientResource(DevicePtr inDev, ClientPtr client, XID id)
1014
{
1015 1016
    DeviceIntPtr dev = (DeviceIntPtr) inDev;
    XkbInterestPtr interest;
1017 1018 1019

    interest = dev->xkb_interest;
    while (interest) {
1020 1021 1022
        if (interest->client == client)
            return ((interest->resource == id) ? interest : NULL);
        interest = interest->next;
1023
    }
1024
    interest = calloc(1, sizeof(XkbInterestRec));
1025
    if (interest) {
1026 1027 1028 1029 1030 1031
        interest->dev = dev;
        interest->client = client;
        interest->resource = id;
        interest->next = dev->xkb_interest;
        dev->xkb_interest = interest;
        return interest;
1032 1033 1034 1035
    }
    return NULL;
}

1036
int
1037
XkbRemoveResourceClient(DevicePtr inDev, XID id)
1038
{
1039 1040 1041 1042 1043 1044
    XkbSrvInfoPtr xkbi;
    DeviceIntPtr dev = (DeviceIntPtr) inDev;
    XkbInterestPtr interest;
    Bool found;
    unsigned long autoCtrls, autoValues;
    ClientPtr client = NULL;
1045

1046
    found = FALSE;
1047 1048 1049 1050

    if (!dev->key || !dev->key->xkbInfo)
        return found;

1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
    autoCtrls = autoValues = 0;
    if (dev->xkb_interest) {
        interest = dev->xkb_interest;
        if (interest && (interest->resource == id)) {
            dev->xkb_interest = interest->next;
            autoCtrls = interest->autoCtrls;
            autoValues = interest->autoCtrlValues;
            client = interest->client;
            free(interest);
            found = TRUE;
        }
        while ((!found) && (interest->next)) {
            if (interest->next->resource == id) {
                XkbInterestPtr victim = interest->next;

                interest->next = victim->next;
                autoCtrls = victim->autoCtrls;
                autoValues = victim->autoCtrlValues;
                client = victim->client;
                free(victim);
                found = TRUE;
            }
            interest = interest->next;
        }
1075
    }
1076 1077
    if (found && autoCtrls && dev->key && dev->key->xkbInfo) {
        XkbEventCauseRec cause;
1078

1079 1080 1081
        xkbi = dev->key->xkbInfo;
        XkbSetCauseXkbReq(&cause, X_kbPerClientFlags, client);
        XkbEnableDisableControls(xkbi, autoCtrls, autoValues, NULL, &cause);
1082 1083 1084
    }
    return found;
}