1 /************************************************************
2 Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3 
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15 
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 
25 ********************************************************/
26 
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <X11/X.h>
33 #include <X11/Xproto.h>
34 #include <X11/keysym.h>
35 #include <X11/extensions/XI.h>
36 #include <X11/extensions/XIproto.h>
37 #include "inputstr.h"
38 #include "exevents.h"
39 #include "exglobals.h"
40 #include "windowstr.h"
41 #include <xkbsrv.h>
42 #include "xkb.h"
43 
44 /***====================================================================***/
45 
46 /*
47  * This function sends out two kinds of notification:
48  *   - Core mapping notify events sent to clients for whom kbd is the
49  *     current core ('picked') keyboard _and_ have not explicitly
50  *     selected for XKB mapping notify events;
51  *   - Xi mapping events, sent unconditionally to all clients who have
52  *     explicitly selected for them (including those who have explicitly
53  *     selected for XKB mapping notify events!).
54  */
55 static void
XkbSendLegacyMapNotify(DeviceIntPtr kbd,CARD16 xkb_event,CARD16 changed,int first_key,int num_keys)56 XkbSendLegacyMapNotify(DeviceIntPtr kbd, CARD16 xkb_event, CARD16 changed,
57                        int first_key, int num_keys)
58 {
59     int i;
60     int keymap_changed = 0;
61     int modmap_changed = 0;
62     CARD32 time = GetTimeInMillis();
63 
64     if (xkb_event == XkbNewKeyboardNotify) {
65         if (changed & XkbNKN_KeycodesMask) {
66             keymap_changed = 1;
67             modmap_changed = 1;
68         }
69     }
70     else if (xkb_event == XkbMapNotify) {
71         if (changed & XkbKeySymsMask)
72             keymap_changed = 1;
73         if (changed & XkbModifierMapMask)
74             modmap_changed = 1;
75     }
76     if (!keymap_changed && !modmap_changed)
77         return;
78 
79     /* 0 is serverClient. */
80     for (i = 1; i < currentMaxClients; i++) {
81         if (!clients[i] || clients[i]->clientState != ClientStateRunning)
82             continue;
83 
84         /* XKB allows clients to restrict the MappingNotify events sent to
85          * them.  This was broken for three years.  Sorry. */
86         if (xkb_event == XkbMapNotify &&
87             (clients[i]->xkbClientFlags & _XkbClientInitialized) &&
88             !(clients[i]->mapNotifyMask & changed))
89             continue;
90         /* Emulate previous server behaviour: any client which has activated
91          * XKB will not receive core events emulated from a NewKeyboardNotify
92          * at all. */
93         if (xkb_event == XkbNewKeyboardNotify &&
94             (clients[i]->xkbClientFlags & _XkbClientInitialized))
95             continue;
96 
97         /* Don't send core events to clients who don't know about us. */
98         if (!XIShouldNotify(clients[i], kbd))
99             continue;
100 
101         if (keymap_changed) {
102             xEvent core_mn = { .u.u.type = MappingNotify };
103             core_mn.u.mappingNotify.request = MappingKeyboard;
104 
105             /* Clip the keycode range to what the client knows about, so it
106              * doesn't freak out. */
107             if (first_key >= clients[i]->minKC)
108                 core_mn.u.mappingNotify.firstKeyCode = first_key;
109             else
110                 core_mn.u.mappingNotify.firstKeyCode = clients[i]->minKC;
111             if (first_key + num_keys - 1 <= clients[i]->maxKC)
112                 core_mn.u.mappingNotify.count = num_keys;
113             else
114                 core_mn.u.mappingNotify.count = clients[i]->maxKC -
115                     clients[i]->minKC + 1;
116 
117             WriteEventsToClient(clients[i], 1, &core_mn);
118         }
119         if (modmap_changed) {
120             xEvent core_mn = {
121                 .u.mappingNotify.request = MappingModifier,
122                 .u.mappingNotify.firstKeyCode = 0,
123                 .u.mappingNotify.count = 0
124             };
125             core_mn.u.u.type = MappingNotify;
126             WriteEventsToClient(clients[i], 1, &core_mn);
127         }
128     }
129 
130     /* Hmm, maybe we can accidentally generate Xi events for core devices
131      * here? Clients might be upset, but that seems better than the
132      * alternative of stale keymaps. -ds */
133     if (keymap_changed) {
134         deviceMappingNotify xi_mn = {
135             .type = DeviceMappingNotify,
136             .deviceid = kbd->id,
137             .request = MappingKeyboard,
138             .firstKeyCode = first_key,
139             .count = num_keys,
140             .time = time
141         };
142         SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
143                               1);
144     }
145     if (modmap_changed) {
146         deviceMappingNotify xi_mn = {
147             .type = DeviceMappingNotify,
148             .deviceid = kbd->id,
149             .request = MappingModifier,
150             .firstKeyCode = 0,
151             .count = 0,
152             .time = time
153         };
154         SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
155                               1);
156     }
157 }
158 
159 /***====================================================================***/
160 
161 void
XkbSendNewKeyboardNotify(DeviceIntPtr kbd,xkbNewKeyboardNotify * pNKN)162 XkbSendNewKeyboardNotify(DeviceIntPtr kbd, xkbNewKeyboardNotify * pNKN)
163 {
164     int i;
165     Time time = GetTimeInMillis();
166     CARD16 changed = pNKN->changed;
167 
168     pNKN->type = XkbEventCode + XkbEventBase;
169     pNKN->xkbType = XkbNewKeyboardNotify;
170 
171     for (i = 1; i < currentMaxClients; i++) {
172         if (!clients[i] || clients[i]->clientState != ClientStateRunning)
173             continue;
174 
175         if (!(clients[i]->newKeyboardNotifyMask & changed))
176             continue;
177 
178         pNKN->sequenceNumber = clients[i]->sequence;
179         pNKN->time = time;
180         pNKN->changed = changed;
181         if (clients[i]->swapped) {
182             swaps(&pNKN->sequenceNumber);
183             swapl(&pNKN->time);
184             swaps(&pNKN->changed);
185         }
186         WriteToClient(clients[i], sizeof(xEvent), pNKN);
187 
188         if (changed & XkbNKN_KeycodesMask) {
189             clients[i]->minKC = pNKN->minKeyCode;
190             clients[i]->maxKC = pNKN->maxKeyCode;
191         }
192     }
193 
194     XkbSendLegacyMapNotify(kbd, XkbNewKeyboardNotify, changed, pNKN->minKeyCode,
195                            pNKN->maxKeyCode - pNKN->minKeyCode + 1);
196 
197     return;
198 }
199 
200 /***====================================================================***/
201 
202 void
XkbSendStateNotify(DeviceIntPtr kbd,xkbStateNotify * pSN)203 XkbSendStateNotify(DeviceIntPtr kbd, xkbStateNotify * pSN)
204 {
205     XkbSrvInfoPtr xkbi;
206     XkbStatePtr state;
207     XkbInterestPtr interest;
208     Time time;
209     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     pSN->type = XkbEventCode + XkbEventBase;
218     pSN->xkbType = XkbStateNotify;
219     pSN->deviceID = kbd->id;
220     pSN->time = time = GetTimeInMillis();
221     pSN->mods = state->mods;
222     pSN->baseMods = state->base_mods;
223     pSN->latchedMods = state->latched_mods;
224     pSN->lockedMods = state->locked_mods;
225     pSN->group = state->group;
226     pSN->baseGroup = state->base_group;
227     pSN->latchedGroup = state->latched_group;
228     pSN->lockedGroup = state->locked_group;
229     pSN->compatState = state->compat_state;
230     pSN->grabMods = state->grab_mods;
231     pSN->compatGrabMods = state->compat_grab_mods;
232     pSN->lookupMods = state->lookup_mods;
233     pSN->compatLookupMods = state->compat_lookup_mods;
234     pSN->ptrBtnState = state->ptr_buttons;
235     changed = pSN->changed;
236     bState = pSN->ptrBtnState;
237 
238     while (interest) {
239         if ((!interest->client->clientGone) &&
240             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
241             (interest->stateNotifyMask & changed)) {
242             pSN->sequenceNumber = interest->client->sequence;
243             pSN->time = time;
244             pSN->changed = changed;
245             pSN->ptrBtnState = bState;
246             if (interest->client->swapped) {
247                 swaps(&pSN->sequenceNumber);
248                 swapl(&pSN->time);
249                 swaps(&pSN->changed);
250                 swaps(&pSN->ptrBtnState);
251             }
252             WriteToClient(interest->client, sizeof(xEvent), pSN);
253         }
254         interest = interest->next;
255     }
256     return;
257 }
258 
259 /***====================================================================***/
260 
261 /*
262  * This function sends out XKB mapping notify events to clients which
263  * have explicitly selected for them.  Core and Xi events are handled by
264  * XkbSendLegacyMapNotify. */
265 void
XkbSendMapNotify(DeviceIntPtr kbd,xkbMapNotify * pMN)266 XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify * pMN)
267 {
268     int i;
269     CARD32 time = GetTimeInMillis();
270     CARD16 changed = pMN->changed;
271     XkbSrvInfoPtr xkbi = kbd->key->xkbInfo;
272 
273     pMN->minKeyCode = xkbi->desc->min_key_code;
274     pMN->maxKeyCode = xkbi->desc->max_key_code;
275     pMN->type = XkbEventCode + XkbEventBase;
276     pMN->xkbType = XkbMapNotify;
277     pMN->deviceID = kbd->id;
278 
279     /* 0 is serverClient. */
280     for (i = 1; i < currentMaxClients; i++) {
281         if (!clients[i] || clients[i]->clientState != ClientStateRunning)
282             continue;
283 
284         if (!(clients[i]->mapNotifyMask & changed))
285             continue;
286 
287         pMN->time = time;
288         pMN->sequenceNumber = clients[i]->sequence;
289         pMN->changed = changed;
290 
291         if (clients[i]->swapped) {
292             swaps(&pMN->sequenceNumber);
293             swapl(&pMN->time);
294             swaps(&pMN->changed);
295         }
296         WriteToClient(clients[i], sizeof(xEvent), pMN);
297     }
298 
299     XkbSendLegacyMapNotify(kbd, XkbMapNotify, changed, pMN->firstKeySym,
300                            pMN->nKeySyms);
301 }
302 
303 int
XkbComputeControlsNotify(DeviceIntPtr kbd,XkbControlsPtr old,XkbControlsPtr new,xkbControlsNotify * pCN,Bool forceCtrlProc)304 XkbComputeControlsNotify(DeviceIntPtr kbd,
305                          XkbControlsPtr old,
306                          XkbControlsPtr new,
307                          xkbControlsNotify * pCN, Bool forceCtrlProc)
308 {
309     int i;
310     CARD32 changedControls;
311 
312     changedControls = 0;
313 
314     if (!kbd || !kbd->kbdfeed)
315         return 0;
316 
317     if (old->enabled_ctrls != new->enabled_ctrls)
318         changedControls |= XkbControlsEnabledMask;
319     if ((old->repeat_delay != new->repeat_delay) ||
320         (old->repeat_interval != new->repeat_interval))
321         changedControls |= XkbRepeatKeysMask;
322     for (i = 0; i < XkbPerKeyBitArraySize; i++)
323         if (old->per_key_repeat[i] != new->per_key_repeat[i])
324             changedControls |= XkbPerKeyRepeatMask;
325     if (old->slow_keys_delay != new->slow_keys_delay)
326         changedControls |= XkbSlowKeysMask;
327     if (old->debounce_delay != new->debounce_delay)
328         changedControls |= XkbBounceKeysMask;
329     if ((old->mk_delay != new->mk_delay) ||
330         (old->mk_interval != new->mk_interval) ||
331         (old->mk_dflt_btn != new->mk_dflt_btn))
332         changedControls |= XkbMouseKeysMask;
333     if ((old->mk_time_to_max != new->mk_time_to_max) ||
334         (old->mk_curve != new->mk_curve) ||
335         (old->mk_max_speed != new->mk_max_speed))
336         changedControls |= XkbMouseKeysAccelMask;
337     if (old->ax_options != new->ax_options)
338         changedControls |= XkbAccessXKeysMask;
339     if ((old->ax_options ^ new->ax_options) & XkbAX_SKOptionsMask)
340         changedControls |= XkbStickyKeysMask;
341     if ((old->ax_options ^ new->ax_options) & XkbAX_FBOptionsMask)
342         changedControls |= XkbAccessXFeedbackMask;
343     if ((old->ax_timeout != new->ax_timeout) ||
344         (old->axt_ctrls_mask != new->axt_ctrls_mask) ||
345         (old->axt_ctrls_values != new->axt_ctrls_values) ||
346         (old->axt_opts_mask != new->axt_opts_mask) ||
347         (old->axt_opts_values != new->axt_opts_values)) {
348         changedControls |= XkbAccessXTimeoutMask;
349     }
350     if ((old->internal.mask != new->internal.mask) ||
351         (old->internal.real_mods != new->internal.real_mods) ||
352         (old->internal.vmods != new->internal.vmods))
353         changedControls |= XkbInternalModsMask;
354     if ((old->ignore_lock.mask != new->ignore_lock.mask) ||
355         (old->ignore_lock.real_mods != new->ignore_lock.real_mods) ||
356         (old->ignore_lock.vmods != new->ignore_lock.vmods))
357         changedControls |= XkbIgnoreLockModsMask;
358 
359     if (new->enabled_ctrls & XkbRepeatKeysMask)
360         kbd->kbdfeed->ctrl.autoRepeat = TRUE;
361     else
362         kbd->kbdfeed->ctrl.autoRepeat = FALSE;
363 
364     if (kbd->kbdfeed && kbd->kbdfeed->CtrlProc &&
365         (changedControls || forceCtrlProc))
366         (*kbd->kbdfeed->CtrlProc) (kbd, &kbd->kbdfeed->ctrl);
367 
368     if ((!changedControls) && (old->num_groups == new->num_groups))
369         return 0;
370 
371     if (!kbd->xkb_interest)
372         return 0;
373 
374     pCN->changedControls = changedControls;
375     pCN->enabledControls = new->enabled_ctrls;
376     pCN->enabledControlChanges = (new->enabled_ctrls ^ old->enabled_ctrls);
377     pCN->numGroups = new->num_groups;
378 
379     return 1;
380 }
381 
382 void
XkbSendControlsNotify(DeviceIntPtr kbd,xkbControlsNotify * pCN)383 XkbSendControlsNotify(DeviceIntPtr kbd, xkbControlsNotify * pCN)
384 {
385     int initialized;
386     CARD32 changedControls, enabledControls, enabledChanges = 0;
387     XkbSrvInfoPtr xkbi;
388     XkbInterestPtr interest;
389     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     initialized = 0;
397     enabledControls = xkbi->desc->ctrls->enabled_ctrls;
398     changedControls = pCN->changedControls;
399     pCN->numGroups = xkbi->desc->ctrls->num_groups;
400     while (interest) {
401         if ((!interest->client->clientGone) &&
402             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
403             (interest->ctrlsNotifyMask & changedControls)) {
404             if (!initialized) {
405                 pCN->type = XkbEventCode + XkbEventBase;
406                 pCN->xkbType = XkbControlsNotify;
407                 pCN->deviceID = kbd->id;
408                 pCN->time = time = GetTimeInMillis();
409                 enabledChanges = pCN->enabledControlChanges;
410                 initialized = 1;
411             }
412             pCN->changedControls = changedControls;
413             pCN->enabledControls = enabledControls;
414             pCN->enabledControlChanges = enabledChanges;
415             pCN->sequenceNumber = interest->client->sequence;
416             pCN->time = time;
417             if (interest->client->swapped) {
418                 swaps(&pCN->sequenceNumber);
419                 swapl(&pCN->changedControls);
420                 swapl(&pCN->enabledControls);
421                 swapl(&pCN->enabledControlChanges);
422                 swapl(&pCN->time);
423             }
424             WriteToClient(interest->client, sizeof(xEvent), pCN);
425         }
426         interest = interest->next;
427     }
428     return;
429 }
430 
431 static void
XkbSendIndicatorNotify(DeviceIntPtr kbd,int xkbType,xkbIndicatorNotify * pEv)432 XkbSendIndicatorNotify(DeviceIntPtr kbd, int xkbType, xkbIndicatorNotify * pEv)
433 {
434     int initialized;
435     XkbInterestPtr interest;
436     Time time = 0;
437     CARD32 state, changed;
438 
439     interest = kbd->xkb_interest;
440     if (!interest)
441         return;
442 
443     initialized = 0;
444     state = pEv->state;
445     changed = pEv->changed;
446     while (interest) {
447         if ((!interest->client->clientGone) &&
448             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
449             (((xkbType == XkbIndicatorStateNotify) &&
450               (interest->iStateNotifyMask & changed)) ||
451              ((xkbType == XkbIndicatorMapNotify) &&
452               (interest->iMapNotifyMask & changed)))) {
453             if (!initialized) {
454                 pEv->type = XkbEventCode + XkbEventBase;
455                 pEv->xkbType = xkbType;
456                 pEv->deviceID = kbd->id;
457                 pEv->time = time = GetTimeInMillis();
458                 initialized = 1;
459             }
460             pEv->sequenceNumber = interest->client->sequence;
461             pEv->time = time;
462             pEv->changed = changed;
463             pEv->state = state;
464             if (interest->client->swapped) {
465                 swaps(&pEv->sequenceNumber);
466                 swapl(&pEv->time);
467                 swapl(&pEv->changed);
468                 swapl(&pEv->state);
469             }
470             WriteToClient(interest->client, sizeof(xEvent), pEv);
471         }
472         interest = interest->next;
473     }
474     return;
475 }
476 
477 void
XkbHandleBell(BOOL force,BOOL eventOnly,DeviceIntPtr kbd,CARD8 percent,void * pCtrl,CARD8 class,Atom name,WindowPtr pWin,ClientPtr pClient)478 XkbHandleBell(BOOL force,
479               BOOL eventOnly,
480               DeviceIntPtr kbd,
481               CARD8 percent,
482               void *pCtrl,
483               CARD8 class, Atom name, WindowPtr pWin, ClientPtr pClient)
484 {
485     xkbBellNotify bn;
486     int initialized;
487     XkbSrvInfoPtr xkbi;
488     XkbInterestPtr interest;
489     CARD8 id;
490     CARD16 pitch, duration;
491     Time time = 0;
492     XID winID = 0;
493 
494     if (!kbd->key || !kbd->key->xkbInfo)
495         return;
496 
497     xkbi = kbd->key->xkbInfo;
498 
499     if ((force || (xkbi->desc->ctrls->enabled_ctrls & XkbAudibleBellMask)) &&
500         (!eventOnly)) {
501         if (kbd->kbdfeed->BellProc)
502             (*kbd->kbdfeed->BellProc) (percent, kbd, (void *) pCtrl, class);
503     }
504     interest = kbd->xkb_interest;
505     if ((!interest) || (force))
506         return;
507 
508     if (class == KbdFeedbackClass) {
509         KeybdCtrl *pKeyCtrl = (KeybdCtrl *) pCtrl;
510 
511         id = pKeyCtrl->id;
512         pitch = pKeyCtrl->bell_pitch;
513         duration = pKeyCtrl->bell_duration;
514     }
515     else if (class == BellFeedbackClass) {
516         BellCtrl *pBellCtrl = (BellCtrl *) pCtrl;
517 
518         id = pBellCtrl->id;
519         pitch = pBellCtrl->pitch;
520         duration = pBellCtrl->duration;
521     }
522     else
523         return;
524 
525     initialized = 0;
526     while (interest) {
527         if ((!interest->client->clientGone) &&
528             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
529             (interest->bellNotifyMask)) {
530             if (!initialized) {
531                 time = GetTimeInMillis();
532                 bn.type = XkbEventCode + XkbEventBase;
533                 bn.xkbType = XkbBellNotify;
534                 bn.deviceID = kbd->id;
535                 bn.bellClass = class;
536                 bn.bellID = id;
537                 bn.percent = percent;
538                 bn.eventOnly = (eventOnly != 0);
539                 winID = (pWin ? pWin->drawable.id : None);
540                 initialized = 1;
541             }
542             bn.sequenceNumber = interest->client->sequence;
543             bn.time = time;
544             bn.pitch = pitch;
545             bn.duration = duration;
546             bn.name = name;
547             bn.window = winID;
548             if (interest->client->swapped) {
549                 swaps(&bn.sequenceNumber);
550                 swapl(&bn.time);
551                 swaps(&bn.pitch);
552                 swaps(&bn.duration);
553                 swapl(&bn.name);
554                 swapl(&bn.window);
555             }
556             WriteToClient(interest->client, sizeof(xEvent), &bn);
557         }
558         interest = interest->next;
559     }
560     return;
561 }
562 
563 void
XkbSendAccessXNotify(DeviceIntPtr kbd,xkbAccessXNotify * pEv)564 XkbSendAccessXNotify(DeviceIntPtr kbd, xkbAccessXNotify * pEv)
565 {
566     int initialized;
567     XkbInterestPtr interest;
568     Time time = 0;
569     CARD16 sk_delay, db_delay;
570 
571     interest = kbd->xkb_interest;
572     if (!interest)
573         return;
574 
575     initialized = 0;
576     sk_delay = pEv->slowKeysDelay;
577     db_delay = pEv->debounceDelay;
578     while (interest) {
579         if ((!interest->client->clientGone) &&
580             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
581             (interest->accessXNotifyMask & (1 << pEv->detail))) {
582             if (!initialized) {
583                 pEv->type = XkbEventCode + XkbEventBase;
584                 pEv->xkbType = XkbAccessXNotify;
585                 pEv->deviceID = kbd->id;
586                 pEv->time = time = GetTimeInMillis();
587                 initialized = 1;
588             }
589             pEv->sequenceNumber = interest->client->sequence;
590             pEv->time = time;
591             pEv->slowKeysDelay = sk_delay;
592             pEv->debounceDelay = db_delay;
593             if (interest->client->swapped) {
594                 swaps(&pEv->sequenceNumber);
595                 swapl(&pEv->time);
596                 swaps(&pEv->slowKeysDelay);
597                 swaps(&pEv->debounceDelay);
598             }
599             WriteToClient(interest->client, sizeof(xEvent), pEv);
600         }
601         interest = interest->next;
602     }
603     return;
604 }
605 
606 void
XkbSendNamesNotify(DeviceIntPtr kbd,xkbNamesNotify * pEv)607 XkbSendNamesNotify(DeviceIntPtr kbd, xkbNamesNotify * pEv)
608 {
609     int initialized;
610     XkbInterestPtr interest;
611     Time time = 0;
612     CARD16 changed, changedVirtualMods;
613     CARD32 changedIndicators;
614 
615     interest = kbd->xkb_interest;
616     if (!interest)
617         return;
618 
619     initialized = 0;
620     changed = pEv->changed;
621     changedIndicators = pEv->changedIndicators;
622     changedVirtualMods = pEv->changedVirtualMods;
623     while (interest) {
624         if ((!interest->client->clientGone) &&
625             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
626             (interest->namesNotifyMask & pEv->changed)) {
627             if (!initialized) {
628                 pEv->type = XkbEventCode + XkbEventBase;
629                 pEv->xkbType = XkbNamesNotify;
630                 pEv->deviceID = kbd->id;
631                 pEv->time = time = GetTimeInMillis();
632                 initialized = 1;
633             }
634             pEv->sequenceNumber = interest->client->sequence;
635             pEv->time = time;
636             pEv->changed = changed;
637             pEv->changedIndicators = changedIndicators;
638             pEv->changedVirtualMods = changedVirtualMods;
639             if (interest->client->swapped) {
640                 swaps(&pEv->sequenceNumber);
641                 swapl(&pEv->time);
642                 swaps(&pEv->changed);
643                 swapl(&pEv->changedIndicators);
644                 swaps(&pEv->changedVirtualMods);
645             }
646             WriteToClient(interest->client, sizeof(xEvent), pEv);
647         }
648         interest = interest->next;
649     }
650     return;
651 }
652 
653 void
XkbSendCompatMapNotify(DeviceIntPtr kbd,xkbCompatMapNotify * pEv)654 XkbSendCompatMapNotify(DeviceIntPtr kbd, xkbCompatMapNotify * pEv)
655 {
656     int initialized;
657     XkbInterestPtr interest;
658     Time time = 0;
659     CARD16 firstSI = 0, nSI = 0, nTotalSI = 0;
660 
661     interest = kbd->xkb_interest;
662     if (!interest)
663         return;
664 
665     initialized = 0;
666     while (interest) {
667         if ((!interest->client->clientGone) &&
668             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
669             (interest->compatNotifyMask)) {
670             if (!initialized) {
671                 pEv->type = XkbEventCode + XkbEventBase;
672                 pEv->xkbType = XkbCompatMapNotify;
673                 pEv->deviceID = kbd->id;
674                 pEv->time = time = GetTimeInMillis();
675                 firstSI = pEv->firstSI;
676                 nSI = pEv->nSI;
677                 nTotalSI = pEv->nTotalSI;
678                 initialized = 1;
679             }
680             pEv->sequenceNumber = interest->client->sequence;
681             pEv->time = time;
682             pEv->firstSI = firstSI;
683             pEv->nSI = nSI;
684             pEv->nTotalSI = nTotalSI;
685             if (interest->client->swapped) {
686                 swaps(&pEv->sequenceNumber);
687                 swapl(&pEv->time);
688                 swaps(&pEv->firstSI);
689                 swaps(&pEv->nSI);
690                 swaps(&pEv->nTotalSI);
691             }
692             WriteToClient(interest->client, sizeof(xEvent), pEv);
693         }
694         interest = interest->next;
695     }
696     return;
697 }
698 
699 void
XkbSendActionMessage(DeviceIntPtr kbd,xkbActionMessage * pEv)700 XkbSendActionMessage(DeviceIntPtr kbd, xkbActionMessage * pEv)
701 {
702     int initialized;
703     XkbSrvInfoPtr xkbi;
704     XkbInterestPtr interest;
705     Time time = 0;
706 
707     interest = kbd->xkb_interest;
708     if (!interest || !kbd->key || !kbd->key->xkbInfo)
709         return;
710 
711     xkbi = kbd->key->xkbInfo;
712 
713     initialized = 0;
714     pEv->mods = xkbi->state.mods;
715     pEv->group = xkbi->state.group;
716     while (interest) {
717         if ((!interest->client->clientGone) &&
718             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
719             (interest->actionMessageMask)) {
720             if (!initialized) {
721                 pEv->type = XkbEventCode + XkbEventBase;
722                 pEv->xkbType = XkbActionMessage;
723                 pEv->deviceID = kbd->id;
724                 pEv->sequenceNumber = interest->client->sequence;
725                 pEv->time = time = GetTimeInMillis();
726                 initialized = 1;
727             }
728             pEv->sequenceNumber = interest->client->sequence;
729             pEv->time = time;
730             if (interest->client->swapped) {
731                 swaps(&pEv->sequenceNumber);
732                 swapl(&pEv->time);
733             }
734             WriteToClient(interest->client, sizeof(xEvent), pEv);
735         }
736         interest = interest->next;
737     }
738     return;
739 }
740 
741 void
XkbSendExtensionDeviceNotify(DeviceIntPtr dev,ClientPtr client,xkbExtensionDeviceNotify * pEv)742 XkbSendExtensionDeviceNotify(DeviceIntPtr dev,
743                              ClientPtr client, xkbExtensionDeviceNotify * pEv)
744 {
745     int initialized;
746     XkbInterestPtr interest;
747     Time time = 0;
748     CARD32 defined, state;
749     CARD16 reason;
750 
751     interest = dev->xkb_interest;
752     if (!interest)
753         return;
754 
755     initialized = 0;
756     reason = pEv->reason;
757     defined = pEv->ledsDefined;
758     state = pEv->ledState;
759     while (interest) {
760         if ((!interest->client->clientGone) &&
761             (interest->client->xkbClientFlags & _XkbClientInitialized) &&
762             (interest->extDevNotifyMask & reason)) {
763             if (!initialized) {
764                 pEv->type = XkbEventCode + XkbEventBase;
765                 pEv->xkbType = XkbExtensionDeviceNotify;
766                 pEv->deviceID = dev->id;
767                 pEv->sequenceNumber = interest->client->sequence;
768                 pEv->time = time = GetTimeInMillis();
769                 initialized = 1;
770             }
771             else {
772                 pEv->sequenceNumber = interest->client->sequence;
773                 pEv->time = time;
774                 pEv->ledsDefined = defined;
775                 pEv->ledState = state;
776                 pEv->reason = reason;
777                 pEv->supported = XkbXI_AllFeaturesMask;
778             }
779             if (interest->client->swapped) {
780                 swaps(&pEv->sequenceNumber);
781                 swapl(&pEv->time);
782                 swapl(&pEv->ledsDefined);
783                 swapl(&pEv->ledState);
784                 swaps(&pEv->reason);
785                 swaps(&pEv->supported);
786             }
787             WriteToClient(interest->client, sizeof(xEvent), pEv);
788         }
789         interest = interest->next;
790     }
791     return;
792 }
793 
794 void
XkbSendNotification(DeviceIntPtr kbd,XkbChangesPtr pChanges,XkbEventCausePtr cause)795 XkbSendNotification(DeviceIntPtr kbd,
796                     XkbChangesPtr pChanges, XkbEventCausePtr cause)
797 {
798     XkbSrvLedInfoPtr sli;
799 
800     sli = NULL;
801     if (pChanges->state_changes) {
802         xkbStateNotify sn;
803 
804         sn.changed = pChanges->state_changes;
805         sn.keycode = cause->kc;
806         sn.eventType = cause->event;
807         sn.requestMajor = cause->mjr;
808         sn.requestMinor = cause->mnr;
809         XkbSendStateNotify(kbd, &sn);
810     }
811     if (pChanges->map.changed) {
812         xkbMapNotify mn;
813 
814         memset(&mn, 0, sizeof(xkbMapNotify));
815         mn.changed = pChanges->map.changed;
816         mn.firstType = pChanges->map.first_type;
817         mn.nTypes = pChanges->map.num_types;
818         mn.firstKeySym = pChanges->map.first_key_sym;
819         mn.nKeySyms = pChanges->map.num_key_syms;
820         mn.firstKeyAct = pChanges->map.first_key_act;
821         mn.nKeyActs = pChanges->map.num_key_acts;
822         mn.firstKeyBehavior = pChanges->map.first_key_behavior;
823         mn.nKeyBehaviors = pChanges->map.num_key_behaviors;
824         mn.virtualMods = pChanges->map.vmods;
825         mn.firstKeyExplicit = pChanges->map.first_key_explicit;
826         mn.nKeyExplicit = pChanges->map.num_key_explicit;
827         mn.firstModMapKey = pChanges->map.first_modmap_key;
828         mn.nModMapKeys = pChanges->map.num_modmap_keys;
829         mn.firstVModMapKey = pChanges->map.first_vmodmap_key;
830         mn.nVModMapKeys = pChanges->map.num_vmodmap_keys;
831         XkbSendMapNotify(kbd, &mn);
832     }
833     if ((pChanges->ctrls.changed_ctrls) ||
834         (pChanges->ctrls.enabled_ctrls_changes)) {
835         xkbControlsNotify cn;
836 
837         memset(&cn, 0, sizeof(xkbControlsNotify));
838         cn.changedControls = pChanges->ctrls.changed_ctrls;
839         cn.enabledControlChanges = pChanges->ctrls.enabled_ctrls_changes;
840         cn.keycode = cause->kc;
841         cn.eventType = cause->event;
842         cn.requestMajor = cause->mjr;
843         cn.requestMinor = cause->mnr;
844         XkbSendControlsNotify(kbd, &cn);
845     }
846     if (pChanges->indicators.map_changes) {
847         xkbIndicatorNotify in;
848 
849         if (sli == NULL)
850             sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
851         memset(&in, 0, sizeof(xkbIndicatorNotify));
852         in.state = sli->effectiveState;
853         in.changed = pChanges->indicators.map_changes;
854         XkbSendIndicatorNotify(kbd, XkbIndicatorMapNotify, &in);
855     }
856     if (pChanges->indicators.state_changes) {
857         xkbIndicatorNotify in;
858 
859         if (sli == NULL)
860             sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
861         memset(&in, 0, sizeof(xkbIndicatorNotify));
862         in.state = sli->effectiveState;
863         in.changed = pChanges->indicators.state_changes;
864         XkbSendIndicatorNotify(kbd, XkbIndicatorStateNotify, &in);
865     }
866     if (pChanges->names.changed) {
867         xkbNamesNotify nn;
868 
869         memset(&nn, 0, sizeof(xkbNamesNotify));
870         nn.changed = pChanges->names.changed;
871         nn.firstType = pChanges->names.first_type;
872         nn.nTypes = pChanges->names.num_types;
873         nn.firstLevelName = pChanges->names.first_lvl;
874         nn.nLevelNames = pChanges->names.num_lvls;
875         nn.nRadioGroups = pChanges->names.num_rg;
876         nn.changedVirtualMods = pChanges->names.changed_vmods;
877         nn.changedIndicators = pChanges->names.changed_indicators;
878         XkbSendNamesNotify(kbd, &nn);
879     }
880     if ((pChanges->compat.changed_groups) || (pChanges->compat.num_si > 0)) {
881         xkbCompatMapNotify cmn;
882 
883         memset(&cmn, 0, sizeof(xkbCompatMapNotify));
884         cmn.changedGroups = pChanges->compat.changed_groups;
885         cmn.firstSI = pChanges->compat.first_si;
886         cmn.nSI = pChanges->compat.num_si;
887         cmn.nTotalSI = kbd->key->xkbInfo->desc->compat->num_si;
888         XkbSendCompatMapNotify(kbd, &cmn);
889     }
890     return;
891 }
892 
893 /***====================================================================***/
894 
895 void
XkbFilterEvents(ClientPtr client,int nEvents,xEvent * xE)896 XkbFilterEvents(ClientPtr client, int nEvents, xEvent *xE)
897 {
898     DeviceIntPtr dev = NULL;
899     XkbSrvInfoPtr xkbi;
900     CARD8 type = xE[0].u.u.type;
901 
902     if (xE->u.u.type & EXTENSION_EVENT_BASE)
903         dev = XIGetDevice(xE);
904 
905     if (!dev)
906         dev = PickKeyboard(client);
907 
908     if (!dev->key)
909         return;
910 
911     xkbi = dev->key->xkbInfo;
912 
913     if (client->xkbClientFlags & _XkbClientInitialized) {
914         if ((xkbDebugFlags & 0x10) &&
915             (type == KeyPress || type == KeyRelease ||
916              type == DeviceKeyPress || type == DeviceKeyRelease))
917             DebugF("[xkb] XkbFilterWriteEvents (XKB client): state 0x%04x\n",
918                    xE[0].u.keyButtonPointer.state);
919 
920         if (dev->deviceGrab.grab != NullGrab && dev->deviceGrab.fromPassiveGrab
921             && (type == KeyPress || type == KeyRelease || type == DeviceKeyPress
922                 || type == DeviceKeyRelease)) {
923             unsigned int state, flags;
924 
925             flags = client->xkbClientFlags;
926             state = xkbi->state.compat_grab_mods;
927             if (flags & XkbPCF_GrabsUseXKBStateMask) {
928                 int group;
929 
930                 if (flags & XkbPCF_LookupStateWhenGrabbed) {
931                     group = xkbi->state.group;
932                     state = xkbi->state.lookup_mods;
933                 }
934                 else {
935                     state = xkbi->state.grab_mods;
936                     group = xkbi->state.base_group + xkbi->state.latched_group;
937                     if (group < 0 || group >= xkbi->desc->ctrls->num_groups)
938                         group = XkbAdjustGroup(group, xkbi->desc->ctrls);
939                 }
940                 state = XkbBuildCoreState(state, group);
941             }
942             else if (flags & XkbPCF_LookupStateWhenGrabbed) {
943                 state = xkbi->state.compat_lookup_mods;
944             }
945             xE[0].u.keyButtonPointer.state = state;
946         }
947     }
948     else {
949         if ((xkbDebugFlags & 0x4) &&
950             (xE[0].u.u.type == KeyPress || xE[0].u.u.type == KeyRelease ||
951              xE[0].u.u.type == DeviceKeyPress ||
952              xE[0].u.u.type == DeviceKeyRelease)) {
953             DebugF("[xkb] XKbFilterWriteEvents (non-XKB):\n");
954             DebugF("[xkb] event= 0x%04x\n", xE[0].u.keyButtonPointer.state);
955             DebugF("[xkb] lookup= 0x%02x, grab= 0x%02x\n",
956                    xkbi->state.lookup_mods, xkbi->state.grab_mods);
957             DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n",
958                    xkbi->state.compat_lookup_mods,
959                    xkbi->state.compat_grab_mods);
960         }
961         if (type >= KeyPress && type <= MotionNotify) {
962             CARD16 old, new;
963 
964             old = xE[0].u.keyButtonPointer.state & ~0x1f00;
965             new = xE[0].u.keyButtonPointer.state & 0x1F00;
966 
967             if (old == XkbStateFieldFromRec(&xkbi->state))
968                 new |= xkbi->state.compat_lookup_mods;
969             else
970                 new |= xkbi->state.compat_grab_mods;
971             xE[0].u.keyButtonPointer.state = new;
972         }
973         else if (type == EnterNotify || type == LeaveNotify) {
974             xE[0].u.enterLeave.state &= 0x1F00;
975             xE[0].u.enterLeave.state |= xkbi->state.compat_grab_mods;
976         }
977         else if (type >= DeviceKeyPress && type <= DeviceMotionNotify) {
978             CARD16 old, new;
979             deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer *) &xE[0];
980 
981             old = kbp->state & ~0x1F00;
982             new = kbp->state & 0x1F00;
983             if (old == XkbStateFieldFromRec(&xkbi->state))
984                 new |= xkbi->state.compat_lookup_mods;
985             else
986                 new |= xkbi->state.compat_grab_mods;
987             kbp->state = new;
988         }
989     }
990 }
991 
992 /***====================================================================***/
993 
994 XkbInterestPtr
XkbFindClientResource(DevicePtr inDev,ClientPtr client)995 XkbFindClientResource(DevicePtr inDev, ClientPtr client)
996 {
997     DeviceIntPtr dev = (DeviceIntPtr) inDev;
998     XkbInterestPtr interest;
999 
1000     if (dev->xkb_interest) {
1001         interest = dev->xkb_interest;
1002         while (interest) {
1003             if (interest->client == client) {
1004                 return interest;
1005             }
1006             interest = interest->next;
1007         }
1008     }
1009     return NULL;
1010 }
1011 
1012 XkbInterestPtr
XkbAddClientResource(DevicePtr inDev,ClientPtr client,XID id)1013 XkbAddClientResource(DevicePtr inDev, ClientPtr client, XID id)
1014 {
1015     DeviceIntPtr dev = (DeviceIntPtr) inDev;
1016     XkbInterestPtr interest;
1017 
1018     interest = dev->xkb_interest;
1019     while (interest) {
1020         if (interest->client == client)
1021             return ((interest->resource == id) ? interest : NULL);
1022         interest = interest->next;
1023     }
1024     interest = calloc(1, sizeof(XkbInterestRec));
1025     if (interest) {
1026         interest->dev = dev;
1027         interest->client = client;
1028         interest->resource = id;
1029         interest->next = dev->xkb_interest;
1030         dev->xkb_interest = interest;
1031         return interest;
1032     }
1033     return NULL;
1034 }
1035 
1036 int
XkbRemoveResourceClient(DevicePtr inDev,XID id)1037 XkbRemoveResourceClient(DevicePtr inDev, XID id)
1038 {
1039     XkbSrvInfoPtr xkbi;
1040     DeviceIntPtr dev = (DeviceIntPtr) inDev;
1041     XkbInterestPtr interest;
1042     Bool found;
1043     unsigned long autoCtrls, autoValues;
1044     ClientPtr client = NULL;
1045 
1046     found = FALSE;
1047 
1048     if (!dev->key || !dev->key->xkbInfo)
1049         return found;
1050 
1051     autoCtrls = autoValues = 0;
1052     if (dev->xkb_interest) {
1053         interest = dev->xkb_interest;
1054         if (interest && (interest->resource == id)) {
1055             dev->xkb_interest = interest->next;
1056             autoCtrls = interest->autoCtrls;
1057             autoValues = interest->autoCtrlValues;
1058             client = interest->client;
1059             free(interest);
1060             found = TRUE;
1061         }
1062         while ((!found) && (interest->next)) {
1063             if (interest->next->resource == id) {
1064                 XkbInterestPtr victim = interest->next;
1065 
1066                 interest->next = victim->next;
1067                 autoCtrls = victim->autoCtrls;
1068                 autoValues = victim->autoCtrlValues;
1069                 client = victim->client;
1070                 free(victim);
1071                 found = TRUE;
1072             }
1073             interest = interest->next;
1074         }
1075     }
1076     if (found && autoCtrls && dev->key && dev->key->xkbInfo) {
1077         XkbEventCauseRec cause;
1078 
1079         xkbi = dev->key->xkbInfo;
1080         XkbSetCauseXkbReq(&cause, X_kbPerClientFlags, client);
1081         XkbEnableDisableControls(xkbi, autoCtrls, autoValues, NULL, &cause);
1082     }
1083     return found;
1084 }
1085