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