XKBUse.c revision 1ab64890
1/* $Xorg: XKBUse.c,v 1.3 2000/08/17 19:45:03 cpqbld Exp $ */
2/************************************************************
3Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
4
5Permission to use, copy, modify, and distribute this
6software and its documentation for any purpose and without
7fee is hereby granted, provided that the above copyright
8notice appear in all copies and that both that copyright
9notice and this permission notice appear in supporting
10documentation, and that the name of Silicon Graphics not be
11used in advertising or publicity pertaining to distribution
12of the software without specific prior written permission.
13Silicon Graphics makes no representation about the suitability
14of this software for any purpose. It is provided "as is"
15without any express or implied warranty.
16
17SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
24THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
26********************************************************/
27/* $XFree86: xc/lib/X11/XKBUse.c,v 3.7 2003/07/07 15:34:21 eich Exp $ */
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <stdio.h>
33#include <ctype.h>
34#define NEED_REPLIES
35#define NEED_EVENTS
36#include "Xlibint.h"
37#include <X11/extensions/XKBproto.h>
38#include "XKBlibint.h"
39
40static Bool	_XkbIgnoreExtension = False;
41
42void
43XkbNoteMapChanges(XkbMapChangesPtr old,XkbMapNotifyEvent *new,unsigned wanted)
44{
45    int first,oldLast,newLast;
46    wanted&= new->changed;
47
48    if (wanted&XkbKeyTypesMask) {
49	if (old->changed&XkbKeyTypesMask) {
50	    first = old->first_type;
51	    oldLast = old->first_type+old->num_types-1;
52	    newLast = new->first_type+new->num_types-1;
53
54	    if (new->first_type<first)
55		first = new->first_type;
56	    if (oldLast>newLast)
57		newLast= oldLast;
58	    old->first_type = first;
59	    old->num_types = newLast-first+1;
60	}
61	else {
62	    old->first_type= new->first_type;
63	    old->num_types = new->num_types;
64	}
65    }
66    if (wanted&XkbKeySymsMask) {
67	if (old->changed&XkbKeySymsMask) {
68	    first = old->first_key_sym;
69	    oldLast = old->first_key_sym+old->num_key_syms-1;
70	    newLast = new->first_key_sym+new->num_key_syms-1;
71
72	    if (new->first_key_sym<first)
73		first = new->first_key_sym;
74	    if (oldLast>newLast)
75		newLast= oldLast;
76	    old->first_key_sym = first;
77	    old->num_key_syms = newLast-first+1;
78	}
79	else {
80	    old->first_key_sym = new->first_key_sym;
81	    old->num_key_syms = new->num_key_syms;
82	}
83    }
84    if (wanted&XkbKeyActionsMask) {
85	if (old->changed&XkbKeyActionsMask) {
86	    first = old->first_key_act;
87	    oldLast = old->first_key_act+old->num_key_acts-1;
88	    newLast = new->first_key_act+new->num_key_acts-1;
89
90	    if (new->first_key_act<first)
91		first = new->first_key_act;
92	    if (oldLast>newLast)
93		newLast= oldLast;
94	    old->first_key_act = first;
95	    old->num_key_acts = newLast-first+1;
96	}
97	else {
98	    old->first_key_act = new->first_key_act;
99	    old->num_key_acts = new->num_key_acts;
100	}
101    }
102    if (wanted&XkbKeyBehaviorsMask) {
103	if (old->changed&XkbKeyBehaviorsMask) {
104	    first = old->first_key_behavior;
105	    oldLast = old->first_key_behavior+old->num_key_behaviors-1;
106	    newLast = new->first_key_behavior+new->num_key_behaviors-1;
107
108	    if (new->first_key_behavior<first)
109		first = new->first_key_behavior;
110	    if (oldLast>newLast)
111		newLast= oldLast;
112	    old->first_key_behavior = first;
113	    old->num_key_behaviors = newLast-first+1;
114	}
115	else {
116	    old->first_key_behavior = new->first_key_behavior;
117	    old->num_key_behaviors = new->num_key_behaviors;
118	}
119    }
120    if (wanted&XkbVirtualModsMask) {
121	old->vmods|= new->vmods;
122    }
123    if (wanted&XkbExplicitComponentsMask) {
124	if (old->changed&XkbExplicitComponentsMask) {
125	    first = old->first_key_explicit;
126	    oldLast = old->first_key_explicit+old->num_key_explicit-1;
127	    newLast = new->first_key_explicit+new->num_key_explicit-1;
128
129	    if (new->first_key_explicit<first)
130		first = new->first_key_explicit;
131	    if (oldLast>newLast)
132		newLast= oldLast;
133	    old->first_key_explicit = first;
134	    old->num_key_explicit = newLast-first+1;
135	}
136	else {
137	    old->first_key_explicit = new->first_key_explicit;
138	    old->num_key_explicit = new->num_key_explicit;
139	}
140    }
141    if (wanted&XkbModifierMapMask) {
142	if (old->changed&XkbModifierMapMask) {
143	    first = old->first_modmap_key;
144	    oldLast = old->first_modmap_key+old->num_modmap_keys-1;
145	    newLast = new->first_modmap_key+new->num_modmap_keys-1;
146
147	    if (new->first_modmap_key<first)
148		first = new->first_modmap_key;
149	    if (oldLast>newLast)
150		newLast= oldLast;
151	    old->first_modmap_key = first;
152	    old->num_modmap_keys = newLast-first+1;
153	}
154	else {
155	    old->first_modmap_key = new->first_modmap_key;
156	    old->num_modmap_keys = new->num_modmap_keys;
157	}
158    }
159    if (wanted&XkbVirtualModMapMask) {
160	if (old->changed&XkbVirtualModMapMask) {
161	    first = old->first_vmodmap_key;
162	    oldLast = old->first_vmodmap_key+old->num_vmodmap_keys-1;
163	    newLast = new->first_vmodmap_key+new->num_vmodmap_keys-1;
164
165	    if (new->first_vmodmap_key<first)
166		first = new->first_vmodmap_key;
167	    if (oldLast>newLast)
168		newLast= oldLast;
169	    old->first_vmodmap_key = first;
170	    old->num_vmodmap_keys = newLast-first+1;
171	}
172	else {
173	    old->first_vmodmap_key = new->first_vmodmap_key;
174	    old->num_vmodmap_keys = new->num_vmodmap_keys;
175	}
176    }
177    old->changed|= wanted;
178    return;
179}
180
181void
182_XkbNoteCoreMapChanges(	XkbMapChangesPtr	 old,
183			XMappingEvent * 	new,
184			unsigned int 		wanted)
185{
186    int first,oldLast,newLast;
187
188    if ((new->request==MappingKeyboard)&&(wanted&XkbKeySymsMask)) {
189	if (old->changed&XkbKeySymsMask) {
190	    first = old->first_key_sym;
191	    oldLast = old->first_key_sym+old->num_key_syms-1;
192	    newLast = new->first_keycode+new->count-1;
193
194	    if (new->first_keycode<first)
195		first = new->first_keycode;
196	    if (oldLast>newLast)
197		newLast= oldLast;
198	    old->first_key_sym = first;
199	    old->num_key_syms = newLast-first+1;
200	}
201	else {
202	    old->changed|= XkbKeySymsMask;
203	    old->first_key_sym = new->first_keycode;
204	    old->num_key_syms = new->count;
205	}
206    }
207    return;
208}
209
210static Bool
211wire_to_event(Display *dpy,XEvent *re,xEvent *event)
212{
213    xkbEvent *xkbevent= (xkbEvent *)event;
214    XkbInfoPtr xkbi;
215
216    if ((dpy->flags & XlibDisplayNoXkb) ||
217	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
218	return False;
219    xkbi = dpy->xkb_info;
220    if (((event->u.u.type&0x7f)-xkbi->codes->first_event)!=XkbEventCode)
221	return False;
222
223    switch (xkbevent->u.any.xkbType) {
224	case XkbStateNotify:
225	    {
226		xkbStateNotify *sn = (xkbStateNotify *)event;
227		if ( xkbi->selected_events&XkbStateNotifyMask ) {
228		    XkbStateNotifyEvent *sev=(XkbStateNotifyEvent *)re;
229		    sev->type = XkbEventCode+xkbi->codes->first_event;
230		    sev->xkb_type = XkbStateNotify;
231		    sev->serial = _XSetLastRequestRead(dpy,
232					(xGenericReply *)event);
233		    sev->send_event = ((event->u.u.type & 0x80) != 0);
234		    sev->display = dpy;
235		    sev->time = sn->time;
236		    sev->device = sn->deviceID;
237		    sev->keycode = sn->keycode;
238		    sev->event_type = sn->eventType;
239		    sev->req_major = sn->requestMajor;
240		    sev->req_minor = sn->requestMinor;
241		    sev->changed = sn->changed;
242		    sev->group = sn->group;
243		    sev->base_group = sn->baseGroup;
244		    sev->latched_group = sn->latchedGroup;
245		    sev->locked_group = sn->lockedGroup;
246		    sev->mods = sn->mods;
247		    sev->base_mods = sn->baseMods;
248		    sev->latched_mods = sn->latchedMods;
249		    sev->locked_mods = sn->lockedMods;
250		    sev->compat_state = sn->compatState;
251		    sev->grab_mods = sn->grabMods;
252		    sev->compat_grab_mods = sn->compatGrabMods;
253		    sev->lookup_mods = sn->lookupMods;
254		    sev->compat_lookup_mods = sn->compatLookupMods;
255		    sev->ptr_buttons = sn->ptrBtnState;
256		    return True;
257		}
258	    }
259	    break;
260	case XkbMapNotify:
261	    {
262		xkbMapNotify *mn = (xkbMapNotify *)event;
263		if ((xkbi->selected_events&XkbMapNotifyMask)&&
264				(xkbi->selected_map_details&mn->changed)) {
265		    XkbMapNotifyEvent *mev;
266		    mev =(XkbMapNotifyEvent *)re;
267		    mev->type = XkbEventCode+xkbi->codes->first_event;
268		    mev->xkb_type = XkbMapNotify;
269		    mev->serial = _XSetLastRequestRead(dpy,
270						(xGenericReply *)event);
271		    mev->send_event = ((event->u.u.type&0x80)!=0);
272		    mev->display = dpy;
273		    mev->time = mn->time;
274		    mev->device = mn->deviceID;
275		    mev->changed =  mn->changed;
276		    mev->min_key_code = mn->minKeyCode;
277		    mev->max_key_code = mn->maxKeyCode;
278		    mev->first_type = mn->firstType;
279		    mev->num_types = mn->nTypes;
280		    mev->first_key_sym = mn->firstKeySym;
281		    mev->num_key_syms = mn->nKeySyms;
282		    mev->first_key_act = mn->firstKeyAct;
283		    mev->num_key_acts = mn->nKeyActs;
284		    mev->first_key_behavior = mn->firstKeyBehavior;
285		    mev->num_key_behaviors = mn->nKeyBehaviors;
286		    mev->vmods = mn->virtualMods;
287		    mev->first_key_explicit = mn->firstKeyExplicit;
288		    mev->num_key_explicit = mn->nKeyExplicit;
289		    mev->first_modmap_key = mn->firstModMapKey;
290		    mev->num_modmap_keys = mn->nModMapKeys;
291		    mev->first_vmodmap_key = mn->firstVModMapKey;
292		    mev->num_vmodmap_keys = mn->nVModMapKeys;
293		    XkbNoteMapChanges(&xkbi->changes,mev,XKB_XLIB_MAP_MASK);
294		    if (xkbi->changes.changed)
295			xkbi->flags|= XkbMapPending;
296		    return True;
297		}
298		else if (mn->nKeySyms>0) {
299		    register XMappingEvent *ev = (XMappingEvent *)re;
300		    ev->type = MappingNotify;
301		    ev->serial = _XSetLastRequestRead(dpy,
302						(xGenericReply *)event);
303		    ev->send_event = ((event->u.u.type&0x80)!=0);
304		    ev->display = dpy;
305		    ev->window = 0;
306		    ev->first_keycode = mn->firstKeySym;
307		    ev->request = MappingKeyboard;
308		    ev->count = mn->nKeySyms;
309		    _XkbNoteCoreMapChanges(&xkbi->changes,ev,XKB_XLIB_MAP_MASK);
310		    if (xkbi->changes.changed)
311			xkbi->flags|= XkbMapPending;
312		    return True;
313		}
314	    }
315	    break;
316	case XkbControlsNotify:
317	    {
318		if (xkbi->selected_events&XkbControlsNotifyMask) {
319		    xkbControlsNotify *cn =(xkbControlsNotify *)event;
320		    XkbControlsNotifyEvent *cev;
321		    cev =(XkbControlsNotifyEvent *)re;
322		    cev->type = XkbEventCode+xkbi->codes->first_event;
323		    cev->xkb_type = XkbControlsNotify;
324		    cev->serial = _XSetLastRequestRead(dpy,
325						(xGenericReply *)event);
326		    cev->send_event = ((event->u.u.type&0x80)!=0);
327		    cev->display = dpy;
328		    cev->time = cn->time;
329		    cev->device = cn->deviceID;
330		    cev->changed_ctrls =  cn->changedControls;
331		    cev->enabled_ctrls =  cn->enabledControls;
332		    cev->enabled_ctrl_changes = cn->enabledControlChanges;
333		    cev->keycode = cn->keycode;
334		    cev->num_groups = cn->numGroups;
335		    cev->event_type = cn->eventType;
336		    cev->req_major = cn->requestMajor;
337		    cev->req_minor = cn->requestMinor;
338		    return True;
339		}
340	    }
341	    break;
342	case XkbIndicatorMapNotify:
343	    {
344		if (xkbi->selected_events&XkbIndicatorMapNotifyMask) {
345		    xkbIndicatorNotify *in =(xkbIndicatorNotify *)event;
346		    XkbIndicatorNotifyEvent *iev;
347		    iev =(XkbIndicatorNotifyEvent *)re;
348		    iev->type = XkbEventCode+xkbi->codes->first_event;
349		    iev->xkb_type = XkbIndicatorMapNotify;
350		    iev->serial = _XSetLastRequestRead(dpy,
351						(xGenericReply *)event);
352		    iev->send_event = ((event->u.u.type&0x80)!=0);
353		    iev->display = dpy;
354		    iev->time = in->time;
355		    iev->device = in->deviceID;
356		    iev->changed =  in->changed;
357		    iev->state=  in->state;
358		    return True;
359		}
360	    }
361	    break;
362	case XkbIndicatorStateNotify:
363	    {
364		if (xkbi->selected_events&XkbIndicatorStateNotifyMask) {
365		    xkbIndicatorNotify *in =(xkbIndicatorNotify *)event;
366		    XkbIndicatorNotifyEvent *iev;
367		    iev =(XkbIndicatorNotifyEvent *)re;
368		    iev->type = XkbEventCode+xkbi->codes->first_event;
369		    iev->xkb_type = XkbIndicatorStateNotify;
370		    iev->serial = _XSetLastRequestRead(dpy,
371						(xGenericReply *)event);
372		    iev->send_event = ((event->u.u.type&0x80)!=0);
373		    iev->display = dpy;
374		    iev->time = in->time;
375		    iev->device = in->deviceID;
376		    iev->changed =  in->changed;
377		    iev->state=  in->state;
378		    return True;
379		}
380	    }
381	    break;
382	case XkbBellNotify:
383	    {
384		if (xkbi->selected_events&XkbBellNotifyMask) {
385		    xkbBellNotify *bn =(xkbBellNotify *)event;
386		    XkbBellNotifyEvent *bev;
387		    bev =(XkbBellNotifyEvent *)re;
388		    bev->type = XkbEventCode+xkbi->codes->first_event;
389		    bev->xkb_type = XkbBellNotify;
390		    bev->serial = _XSetLastRequestRead(dpy,
391						(xGenericReply *)event);
392		    bev->send_event = ((event->u.u.type&0x80)!=0);
393		    bev->display = dpy;
394		    bev->time = bn->time;
395		    bev->device = bn->deviceID;
396		    bev->percent = bn->percent;
397		    bev->pitch = bn->pitch;
398		    bev->duration = bn->duration;
399		    bev->bell_class = bn->bellClass;
400		    bev->bell_id = bn->bellID;
401		    bev->name = bn->name;
402		    bev->window = bn->window;
403		    bev->event_only = bn->eventOnly;
404		    return True;
405		}
406	    }
407	    break;
408	case XkbAccessXNotify:
409	    {
410		if (xkbi->selected_events&XkbAccessXNotifyMask) {
411		    xkbAccessXNotify *axn =(xkbAccessXNotify *)event;
412		    XkbAccessXNotifyEvent *axev;
413		    axev =(XkbAccessXNotifyEvent *)re;
414		    axev->type = XkbEventCode+xkbi->codes->first_event;
415		    axev->xkb_type = XkbAccessXNotify;
416		    axev->serial = _XSetLastRequestRead(dpy,
417						(xGenericReply *)event);
418		    axev->send_event = ((event->u.u.type&0x80)!=0);
419		    axev->display = dpy;
420		    axev->time = axn->time;
421		    axev->device = axn->deviceID;
422		    axev->detail = axn->detail;
423		    axev->keycode = axn->keycode;
424		    axev->sk_delay = axn->slowKeysDelay;
425		    axev->debounce_delay = axn->debounceDelay;
426		    return True;
427		}
428	    }
429	    break;
430	case XkbNamesNotify:
431	    {
432		if (xkbi->selected_events&XkbNamesNotifyMask) {
433		    xkbNamesNotify *nn =(xkbNamesNotify *)event;
434		    XkbNamesNotifyEvent *nev;
435		    nev =(XkbNamesNotifyEvent *)re;
436		    nev->type = XkbEventCode+xkbi->codes->first_event;
437		    nev->xkb_type = XkbNamesNotify;
438		    nev->serial = _XSetLastRequestRead(dpy,
439						(xGenericReply *)event);
440		    nev->send_event = ((event->u.u.type&0x80)!=0);
441		    nev->display = dpy;
442		    nev->time = nn->time;
443		    nev->device = nn->deviceID;
444		    nev->changed = nn->changed;
445		    nev->first_type = nn->firstType;
446		    nev->num_types = nn->nTypes;
447		    nev->first_lvl = nn->firstLevelName;
448		    nev->num_lvls = nn->nLevelNames;
449		    nev->num_aliases = nn->nAliases;
450		    nev->num_radio_groups = nn->nRadioGroups;
451		    nev->changed_vmods = nn->changedVirtualMods;
452		    nev->changed_groups = nn->changedGroupNames;
453		    nev->changed_indicators = nn->changedIndicators;
454		    nev->first_key = nn->firstKey;
455		    nev->num_keys = nn->nKeys;
456		    return True;
457		}
458	    }
459	    break;
460	case XkbCompatMapNotify:
461	    {
462		if (xkbi->selected_events&XkbCompatMapNotifyMask) {
463		    xkbCompatMapNotify *cmn =(xkbCompatMapNotify *)event;
464		    XkbCompatMapNotifyEvent *cmev;
465		    cmev =(XkbCompatMapNotifyEvent *)re;
466		    cmev->type = XkbEventCode+xkbi->codes->first_event;
467		    cmev->xkb_type = XkbCompatMapNotify;
468		    cmev->serial = _XSetLastRequestRead(dpy,
469						(xGenericReply *)event);
470		    cmev->send_event = ((event->u.u.type&0x80)!=0);
471		    cmev->display = dpy;
472		    cmev->time = cmn->time;
473		    cmev->device = cmn->deviceID;
474		    cmev->changed_groups = cmn->changedGroups;
475		    cmev->first_si = cmn->firstSI;
476		    cmev->num_si = cmn->nSI;
477		    cmev->num_total_si = cmn->nTotalSI;
478		    return True;
479		}
480	    }
481	    break;
482	case XkbActionMessage:
483	    {
484		if (xkbi->selected_events&XkbActionMessageMask) {
485		    xkbActionMessage *am= (xkbActionMessage *)event;
486		    XkbActionMessageEvent *amev;
487		    amev= (XkbActionMessageEvent *)re;
488		    amev->type = XkbEventCode+xkbi->codes->first_event;
489		    amev->xkb_type = XkbActionMessage;
490		    amev->serial = _XSetLastRequestRead(dpy,
491						(xGenericReply *)event);
492		    amev->send_event = ((event->u.u.type&0x80)!=0);
493		    amev->display = dpy;
494		    amev->time = am->time;
495		    amev->device = am->deviceID;
496		    amev->keycode = am->keycode;
497		    amev->press = am->press;
498		    amev->key_event_follows = am->keyEventFollows;
499		    amev->group = am->group;
500		    amev->mods = am->mods;
501		    memcpy(amev->message,am->message,XkbActionMessageLength);
502		    amev->message[XkbActionMessageLength]= '\0';
503		    return True;
504		}
505	    }
506	    break;
507	case XkbExtensionDeviceNotify:
508	    {
509		if (xkbi->selected_events&XkbExtensionDeviceNotifyMask) {
510		    xkbExtensionDeviceNotify *ed=
511					(xkbExtensionDeviceNotify *)event;
512		    XkbExtensionDeviceNotifyEvent *edev;
513		    edev= (XkbExtensionDeviceNotifyEvent *)re;
514		    edev->type= XkbEventCode+xkbi->codes->first_event;
515		    edev->xkb_type= XkbExtensionDeviceNotify;
516		    edev->serial= _XSetLastRequestRead(dpy,
517						(xGenericReply *)event);
518		    edev->send_event= ((event->u.u.type&0x80)!=0);
519		    edev->display= dpy;
520		    edev->time= ed->time;
521		    edev->device= ed->deviceID;
522		    edev->led_class= ed->ledClass;
523		    edev->led_id= ed->ledID;
524		    edev->reason= ed->reason;
525		    edev->supported= ed->supported;
526		    edev->leds_defined= ed->ledsDefined;
527		    edev->led_state= ed->ledState;
528		    edev->first_btn= ed->firstBtn;
529		    edev->num_btns= ed->nBtns;
530		    edev->unsupported= ed->unsupported;
531		    return True;
532		}
533	    }
534	    break;
535	case XkbNewKeyboardNotify:
536	    {
537		xkbNewKeyboardNotify *nkn = (xkbNewKeyboardNotify *)event;
538		if ((xkbi->selected_events&XkbNewKeyboardNotifyMask)&&
539				    (xkbi->selected_nkn_details&nkn->changed)) {
540		    XkbNewKeyboardNotifyEvent *nkev;
541		    nkev =(XkbNewKeyboardNotifyEvent *)re;
542		    nkev->type = XkbEventCode+xkbi->codes->first_event;
543		    nkev->xkb_type = XkbNewKeyboardNotify;
544		    nkev->serial = _XSetLastRequestRead(dpy,
545						(xGenericReply *)event);
546		    nkev->send_event = ((event->u.u.type&0x80)!=0);
547		    nkev->display = dpy;
548		    nkev->time = nkn->time;
549		    nkev->device = nkn->deviceID;
550		    nkev->old_device = nkn->oldDeviceID;
551		    nkev->min_key_code = nkn->minKeyCode;
552		    nkev->max_key_code = nkn->maxKeyCode;
553		    nkev->old_min_key_code = nkn->oldMinKeyCode;
554		    nkev->old_max_key_code = nkn->oldMaxKeyCode;
555		    nkev->req_major = nkn->requestMajor;
556		    nkev->req_minor = nkn->requestMinor;
557		    nkev->changed = nkn->changed;
558		    if ((xkbi->desc)&&(nkev->send_event==0)&&
559			((xkbi->desc->device_spec==nkev->old_device)||
560			 (nkev->device!=nkev->old_device))) {
561			xkbi->flags= XkbMapPending|XkbXlibNewKeyboard;
562		    }
563		    return True;
564		}
565		else if(nkn->changed&(XkbNKN_KeycodesMask|XkbNKN_DeviceIDMask)){
566		    register XMappingEvent *ev = (XMappingEvent *)re;
567		    ev->type = MappingNotify;
568		    ev->serial = _XSetLastRequestRead(dpy,
569						(xGenericReply *)event);
570		    ev->send_event = ((event->u.u.type&0x80)!=0);
571		    ev->display = dpy;
572		    ev->window = 0;
573		    ev->first_keycode = dpy->min_keycode;
574		    ev->request = MappingKeyboard;
575		    ev->count = (dpy->max_keycode-dpy->min_keycode)+1;
576		    if ((xkbi->desc)&&(ev->send_event==0)&&
577			((xkbi->desc->device_spec==nkn->oldDeviceID)||
578			 (nkn->deviceID!=nkn->oldDeviceID))) {
579			xkbi->flags|= XkbMapPending|XkbXlibNewKeyboard;
580		    }
581		    return True;
582		}
583	    }
584	    break;
585	default:
586#ifdef DEBUG
587	    fprintf(stderr,"Got unknown XKEYBOARD event (%d, base=%d)\n",
588						re->type,
589						xkbi->codes->first_event);
590#endif
591	    break;
592    }
593    return False;
594}
595
596Bool
597XkbIgnoreExtension(Bool ignore)
598{
599    if (getenv("XKB_FORCE")!=NULL) {
600#ifdef DEBUG
601	fprintf(stderr,"Forcing use of XKEYBOARD (overriding an IgnoreExtensions)\n");
602#endif
603	return False;
604    }
605#ifdef DEBUG
606    else if (getenv("XKB_DEBUG")!=NULL) {
607	fprintf(stderr,"Explicitly %signoring XKEYBOARD\n",ignore?"":"not ");
608    }
609#endif
610    _XkbIgnoreExtension = ignore;
611    return True;
612}
613
614static void
615_XkbFreeInfo(Display *dpy)
616{
617    XkbInfoPtr xkbi = dpy->xkb_info;
618    if (xkbi) {
619	if (xkbi->desc)
620	    XkbFreeKeyboard(xkbi->desc,XkbAllComponentsMask,True);
621	Xfree(xkbi);
622      }
623}
624
625Bool
626XkbUseExtension(Display *dpy,int *major_rtrn,int *minor_rtrn)
627{
628    xkbUseExtensionReply rep;
629    register xkbUseExtensionReq *req;
630    XExtCodes		*codes;
631    int	ev_base,forceIgnore;
632    XkbInfoPtr xkbi;
633    char *	str;
634    static int debugMsg;
635    static int been_here= 0;
636
637    if ( dpy->xkb_info && !(dpy->flags & XlibDisplayNoXkb)) {
638	if (major_rtrn)	*major_rtrn= dpy->xkb_info->srv_major;
639	if (minor_rtrn)	*minor_rtrn= dpy->xkb_info->srv_minor;
640	return True;
641    }
642    if (!been_here) {
643	debugMsg= (getenv("XKB_DEBUG")!=NULL);
644	been_here= 1;
645    }
646
647    if (major_rtrn)	*major_rtrn= 0;
648    if (minor_rtrn)	*minor_rtrn= 0;
649
650    if (!dpy->xkb_info) {
651        xkbi = _XkbTypedCalloc(1, XkbInfoRec);
652        if ( !xkbi )
653	    return False;
654        dpy->xkb_info = xkbi;
655        dpy->free_funcs->xkb = _XkbFreeInfo;
656
657        xkbi->xlib_ctrls|= (XkbLC_ControlFallback|XkbLC_ConsumeLookupMods);
658        if ((str=getenv("_XKB_OPTIONS_ENABLE"))!=NULL) {
659	    if ((str=getenv("_XKB_LATIN1_LOOKUP"))!=NULL) {
660	        if ((strcmp(str,"off")==0)||(strcmp(str,"0")==0))
661		     xkbi->xlib_ctrls&= ~XkbLC_ForceLatin1Lookup;
662	        else xkbi->xlib_ctrls|= XkbLC_ForceLatin1Lookup;
663	    }
664	    if ((str=getenv("_XKB_CONSUME_LOOKUP_MODS"))!=NULL) {
665	        if ((strcmp(str,"off")==0)||(strcmp(str,"0")==0))
666		     xkbi->xlib_ctrls&= ~XkbLC_ConsumeLookupMods;
667	        else xkbi->xlib_ctrls|= XkbLC_ConsumeLookupMods;
668	    }
669	    if ((str=getenv("_XKB_CONSUME_SHIFT_AND_LOCK"))!=NULL) {
670	        if ((strcmp(str,"off")==0)||(strcmp(str,"0")==0))
671		     xkbi->xlib_ctrls&= ~XkbLC_AlwaysConsumeShiftAndLock;
672	        else xkbi->xlib_ctrls|= XkbLC_AlwaysConsumeShiftAndLock;
673	    }
674	    if ((str=getenv("_XKB_IGNORE_NEW_KEYBOARDS"))!=NULL) {
675	        if ((strcmp(str,"off")==0)||(strcmp(str,"0")==0))
676		     xkbi->xlib_ctrls&= ~XkbLC_IgnoreNewKeyboards;
677	        else xkbi->xlib_ctrls|= XkbLC_IgnoreNewKeyboards;
678	    }
679	    if ((str=getenv("_XKB_CONTROL_FALLBACK"))!=NULL) {
680	        if ((strcmp(str,"off")==0)||(strcmp(str,"0")==0))
681		     xkbi->xlib_ctrls&= ~XkbLC_ControlFallback;
682	        else xkbi->xlib_ctrls|= XkbLC_ControlFallback;
683	    }
684	    if ((str=getenv("_XKB_COMP_LED"))!=NULL) {
685	        if ((strcmp(str,"off")==0)||(strcmp(str,"0")==0))
686		    xkbi->xlib_ctrls&= ~XkbLC_ComposeLED;
687	        else {
688		    xkbi->xlib_ctrls|= XkbLC_ComposeLED;
689		    if (strlen(str)>0)
690		        xkbi->composeLED= XInternAtom(dpy,str,False);
691	        }
692	    }
693	    if ((str=getenv("_XKB_COMP_FAIL_BEEP"))!=NULL) {
694	        if ((strcmp(str,"off")==0)||(strcmp(str,"0")==0))
695		     xkbi->xlib_ctrls&= ~XkbLC_BeepOnComposeFail;
696	        else xkbi->xlib_ctrls|= XkbLC_BeepOnComposeFail;
697	    }
698        }
699        if ((xkbi->composeLED==None)&&((xkbi->xlib_ctrls&XkbLC_ComposeLED)!=0))
700	    xkbi->composeLED= XInternAtom(dpy,"Compose",False);
701#ifdef DEBUG
702        if (debugMsg) {
703	    register unsigned c= xkbi->xlib_ctrls;
704	    fprintf(stderr,"XKEYBOARD compose: beep on failure is %s, LED is %s\n",
705		((c&XkbLC_BeepOnComposeFail)?"on":"off"),
706		((c&XkbLC_ComposeLED)?"on":"off"));
707	    fprintf(stderr,"XKEYBOARD XLookupString: %slatin-1, %s lookup modifiers\n",
708		((c&XkbLC_ForceLatin1Lookup)?"allow non-":"force "),
709		((c&XkbLC_ConsumeLookupMods)?"consume":"re-use"));
710	    fprintf(stderr,
711	        "XKEYBOARD XLookupString: %sconsume shift and lock, %scontrol fallback\n",
712	        ((c&XkbLC_AlwaysConsumeShiftAndLock)?"always ":"don't "),
713	        ((c&XkbLC_ControlFallback)?"":"no "));
714
715        }
716#endif
717    } else
718        xkbi = dpy->xkb_info;
719
720    forceIgnore= (dpy->flags&XlibDisplayNoXkb)||dpy->keysyms;
721    forceIgnore= forceIgnore&&(major_rtrn==NULL)&&(minor_rtrn==NULL);
722    if ( forceIgnore || _XkbIgnoreExtension || getenv("XKB_DISABLE")) {
723	LockDisplay(dpy);
724	dpy->flags |= XlibDisplayNoXkb;
725	UnlockDisplay(dpy);
726	if (debugMsg)
727	    fprintf(stderr,"XKEYBOARD extension disabled or missing\n");
728	return False;
729    }
730
731    if ( (codes=XInitExtension(dpy,XkbName))==NULL ) {
732	LockDisplay(dpy);
733	dpy->flags |= XlibDisplayNoXkb;
734	UnlockDisplay(dpy);
735	if (debugMsg)
736	    fprintf(stderr,"XKEYBOARD extension not present\n");
737	return False;
738    }
739    xkbi->codes = codes;
740    LockDisplay(dpy);
741
742    GetReq(kbUseExtension, req);
743    req->reqType = xkbi->codes->major_opcode;
744    req->xkbReqType = X_kbUseExtension;
745    req->wantedMajor = XkbMajorVersion;
746    req->wantedMinor = XkbMinorVersion;
747    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.supported ) {
748	Bool	fail;
749	fail= True;
750	if (debugMsg)
751	    fprintf(stderr,
752		"XKEYBOARD version mismatch (want %d.%02d, got %d.%02d)\n",
753		XkbMajorVersion,XkbMinorVersion,
754		rep.serverMajor, rep.serverMinor);
755
756	/* pre-release 0.65 is very close to 1.00 */
757	if ((rep.serverMajor==0)&&(rep.serverMinor==65)) {
758	    if (debugMsg)
759		fprintf(stderr,"Trying to fall back to version 0.65...");
760	    GetReq(kbUseExtension, req);
761	    req->reqType = xkbi->codes->major_opcode;
762	    req->xkbReqType = X_kbUseExtension;
763	    req->wantedMajor = 0;
764	    req->wantedMinor = 65;
765	    if ( _XReply(dpy, (xReply *)&rep, 0, xFalse) && rep.supported ) {
766		if (debugMsg)
767		    fprintf(stderr,"succeeded\n");
768		fail= False;
769	    }
770	    else if (debugMsg) fprintf(stderr,"failed\n");
771	}
772	if (fail) {
773	    dpy->flags |= XlibDisplayNoXkb;
774	    UnlockDisplay(dpy);
775	    SyncHandle();
776	    if (major_rtrn) *major_rtrn= rep.serverMajor;
777	    if (minor_rtrn) *minor_rtrn= rep.serverMinor;
778	    return False;
779	}
780    }
781#ifdef DEBUG
782    else if ( forceIgnore ) {
783	fprintf(stderr,"Internal Error!  XkbUseExtension succeeded with forceIgnore set\n");
784    }
785#endif
786    UnlockDisplay(dpy);
787    xkbi->srv_major= rep.serverMajor;
788    xkbi->srv_minor= rep.serverMinor;
789    if (major_rtrn)	*major_rtrn= rep.serverMajor;
790    if (minor_rtrn)	*minor_rtrn= rep.serverMinor;
791    if (debugMsg)
792	fprintf(stderr,"XKEYBOARD (version %d.%02d/%d.%02d) OK!\n",
793				XkbMajorVersion,XkbMinorVersion,
794				rep.serverMajor,rep.serverMinor);
795
796    ev_base = codes->first_event;
797    XESetWireToEvent(dpy,ev_base+XkbEventCode,wire_to_event);
798    SyncHandle();
799    return True;
800}
801
802