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