XKBBind.c revision b4ee4795
1/*
2
3Copyright 1985, 1987, 1994, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29	/* the new monsters ate the old ones */
30
31#define NEED_EVENTS
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35#include "XKBlib.h"
36#include <X11/Xlibint.h>
37#include <X11/Xutil.h>
38#include <X11/keysym.h>
39#include <stdio.h>
40#include <ctype.h>
41
42#include <X11/extensions/XKBproto.h>
43#include "XKBlibint.h"
44
45#ifdef USE_OWN_COMPOSE
46#define	COMPOSE_NO_CONST_MEMBERS
47#include "imComp.h"
48#endif
49
50#define AllMods (ShiftMask|LockMask|ControlMask| \
51		 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
52
53static int _XkbLoadDpy(
54    Display *dpy
55);
56
57struct _XKeytrans {
58	struct _XKeytrans *next;/* next on list */
59	char *string;		/* string to return when the time comes */
60	int len;		/* length of string (since NULL is legit)*/
61	KeySym key;		/* keysym rebound */
62	unsigned int state;	/* modifier state */
63	KeySym *modifiers;	/* modifier keysyms you want */
64	int mlen;		/* length of modifier list */
65};
66
67KeySym
68XkbKeycodeToKeysym(Display *dpy,
69#if NeedWidePrototypes
70		 unsigned int kc,
71#else
72		 KeyCode kc,
73#endif
74		 int 	group,
75		 int	level)
76{
77    XkbDescRec	*xkb;
78
79    if (_XkbUnavailable(dpy))
80	return NoSymbol;
81
82    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
83
84    xkb = dpy->xkb_info->desc;
85    if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
86	return NoSymbol;
87
88    if ((group<0)||(level<0)||(group>=XkbKeyNumGroups(xkb,kc)))
89	return NoSymbol;
90    if (level>=XkbKeyGroupWidth(xkb,kc,group)) {
91	/* for compatibility with the core protocol, _always_ allow  */
92	/* two symbols in the first two groups.   If either of the   */
93	/* two is of type ONE_LEVEL, just replicate the first symbol */
94	if ((group>XkbGroup2Index)||(XkbKeyGroupWidth(xkb,kc,group)!=1)||
95								(level!=1)) {
96	    return NoSymbol;
97	}
98	level= 0;
99    }
100    return XkbKeySymEntry(xkb,kc,level,group);
101}
102
103KeySym
104XKeycodeToKeysym(Display *dpy,
105#if NeedWidePrototypes
106		 unsigned int kc,
107#else
108		 KeyCode kc,
109#endif
110		 int col)
111{
112    XkbDescRec	*xkb;
113
114    if (_XkbUnavailable(dpy))
115	return _XKeycodeToKeysym(dpy, kc, col);
116
117    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
118
119    xkb = dpy->xkb_info->desc;
120    if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
121	return NoSymbol;
122
123    if (col>3) {
124	int lastSym,tmp,nGrp;
125
126	lastSym= 3;
127	nGrp= XkbKeyNumGroups(xkb,kc);
128	if ((nGrp>0)&&((tmp=XkbKeyGroupWidth(xkb,kc,XkbGroup1Index))>2)) {
129	    if (col<=(lastSym+tmp-2))
130		return XkbKeycodeToKeysym(dpy,kc,XkbGroup1Index,col-lastSym+2);
131	    lastSym+= tmp-2;
132	}
133	if ((nGrp>1)&&((tmp=XkbKeyGroupWidth(xkb,kc,XkbGroup2Index))>2)) {
134	    if (col<=(lastSym+tmp-2))
135		return XkbKeycodeToKeysym(dpy,kc,XkbGroup2Index,col-lastSym+2);
136	    lastSym+= tmp-2;
137	}
138	if (nGrp>2) {
139	    tmp= XkbKeyGroupWidth(xkb,kc,XkbGroup3Index);
140	    if (col<=lastSym+tmp)
141		return XkbKeycodeToKeysym(dpy,kc,XkbGroup3Index,col-lastSym);
142	    lastSym+= tmp;
143	}
144	if (nGrp>3) {
145	    tmp= XkbKeyGroupWidth(xkb,kc,XkbGroup4Index);
146	    if (col<=lastSym+tmp)
147		return XkbKeycodeToKeysym(dpy,kc,XkbGroup4Index,col-lastSym);
148	}
149	return NoSymbol;
150    }
151    return XkbKeycodeToKeysym(dpy,kc,(col>>1),(col&1));
152}
153
154KeyCode
155XKeysymToKeycode(Display *dpy, KeySym ks)
156{
157    register int i, j, gotOne;
158
159    if (_XkbUnavailable(dpy))
160	return _XKeysymToKeycode(dpy,ks);
161    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
162
163    j= 0;
164    do {
165	register XkbDescRec *xkb = dpy->xkb_info->desc;
166	gotOne= 0;
167	for (i = dpy->min_keycode; i <= dpy->max_keycode; i++) {
168	    if ( j<(int)XkbKeyNumSyms(xkb,i) ) {
169		gotOne = 1;
170		if ((XkbKeySym(xkb,i,j)==ks))
171		    return i;
172	    }
173	}
174	j++;
175    } while (gotOne);
176    return 0;
177}
178
179static int
180_XkbComputeModmap(Display *dpy)
181{
182register XkbDescPtr xkb;
183
184    xkb= dpy->xkb_info->desc;
185    if (XkbGetUpdatedMap(dpy,XkbModifierMapMask,xkb)==Success)
186	return 1;
187    return 0;
188}
189
190unsigned
191XkbKeysymToModifiers(Display *dpy,KeySym ks)
192{
193    XkbDescRec *xkb;
194    register int i,j;
195    register KeySym *pSyms;
196    CARD8 mods;
197
198    if (_XkbUnavailable(dpy))
199	return _XKeysymToModifiers(dpy,ks);
200    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
201
202    if (_XkbNeedModmap(dpy->xkb_info)&&(!_XkbComputeModmap(dpy)))
203	return _XKeysymToModifiers(dpy,ks);
204
205    xkb= dpy->xkb_info->desc;
206    mods= 0;
207    for (i = xkb->min_key_code; i <= (int)xkb->max_key_code; i++) {
208	pSyms= XkbKeySymsPtr(xkb,i);
209	for (j=XkbKeyNumSyms(xkb,i)-1;j>=0;j--) {
210	    if (pSyms[j]==ks) {
211		mods|= xkb->map->modmap[i];
212		break;
213	    }
214	}
215    }
216    return mods;
217}
218
219KeySym
220XLookupKeysym(register XKeyEvent *event, int col)
221{
222    Display *dpy = event->display;
223    if (_XkbUnavailable(dpy))
224	return _XLookupKeysym(event, col);
225    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
226    return XKeycodeToKeysym(dpy, event->keycode, col);
227}
228
229   /*
230    * Not a public entry point -- XkbTranslateKey is an obsolete name
231    * that is preserved here so that functions linked against the old
232    * version will continue to work in a shared library environment.
233    */
234int
235XkbTranslateKey(	register Display *	dpy,
236			KeyCode 		key,
237			register unsigned int 	mods,
238			unsigned int *		mods_rtrn,
239			KeySym *		keysym_rtrn);
240int
241XkbTranslateKey(	register Display *	dpy,
242			KeyCode 		key,
243			register unsigned int 	mods,
244			unsigned int *		mods_rtrn,
245			KeySym *		keysym_rtrn)
246{
247    return XkbLookupKeySym(dpy,key,mods,mods_rtrn,keysym_rtrn);
248}
249
250Bool
251XkbLookupKeySym(	register Display *	dpy,
252			KeyCode 		key,
253			register unsigned int 	mods,
254			unsigned int *		mods_rtrn,
255			KeySym *		keysym_rtrn)
256{
257    if (_XkbUnavailable(dpy))
258	return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
259    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
260    return XkbTranslateKeyCode(dpy->xkb_info->desc,key,mods,mods_rtrn,
261								keysym_rtrn);
262}
263
264Bool
265XkbTranslateKeyCode(	register XkbDescPtr	xkb,
266			KeyCode 		key,
267			register unsigned int 	mods,
268			unsigned int *		mods_rtrn,
269			KeySym *		keysym_rtrn)
270{
271    XkbKeyTypeRec *type;
272    int col,nKeyGroups;
273    unsigned preserve,effectiveGroup;
274    KeySym *syms;
275
276    if (mods_rtrn!=NULL)
277	*mods_rtrn = 0;
278
279    nKeyGroups= XkbKeyNumGroups(xkb,key);
280    if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
281	if (keysym_rtrn!=NULL)
282	    *keysym_rtrn = NoSymbol;
283	return False;
284    }
285
286    syms = XkbKeySymsPtr(xkb,key);
287
288    /* find the offset of the effective group */
289    col = 0;
290    effectiveGroup= XkbGroupForCoreState(mods);
291    if ( effectiveGroup>=nKeyGroups ) {
292	unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
293	switch (XkbOutOfRangeGroupAction(groupInfo)) {
294	    default:
295		effectiveGroup %= nKeyGroups;
296		break;
297	    case XkbClampIntoRange:
298		effectiveGroup = nKeyGroups-1;
299		break;
300	    case XkbRedirectIntoRange:
301		effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
302		if (effectiveGroup>=nKeyGroups)
303		    effectiveGroup= 0;
304		break;
305	}
306    }
307    col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
308    type = XkbKeyKeyType(xkb,key,effectiveGroup);
309
310    preserve= 0;
311    if (type->map) { /* find the column (shift level) within the group */
312	register int i;
313	register XkbKTMapEntryPtr entry;
314	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
315	    if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
316		col+= entry->level;
317		if (type->preserve)
318		    preserve= type->preserve[i].mask;
319		break;
320	    }
321	}
322    }
323
324    if (keysym_rtrn!=NULL)
325	*keysym_rtrn= syms[col];
326    if (mods_rtrn) {
327	*mods_rtrn= type->mods.mask&(~preserve);
328	/* The Motif VTS doesn't get the help callback called if help
329	 * is bound to Shift+<whatever>, and it appears as though it
330	 * is XkbTranslateKeyCode that is causing the problem.  The
331	 * core X version of XTranslateKey always OR's in ShiftMask
332	 * and LockMask for mods_rtrn, so this "fix" keeps this behavior
333	 * and solves the VTS problem.
334	 */
335	if ((xkb->dpy)&&(xkb->dpy->xkb_info)&&
336	    (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) {
337	    *mods_rtrn|= (ShiftMask|LockMask);
338	}
339    }
340    return (syms[col]!=NoSymbol);
341}
342
343Status
344XkbRefreshKeyboardMapping(register XkbMapNotifyEvent *event)
345{
346    Display *dpy = event->display;
347    XkbInfoPtr xkbi;
348
349    if (_XkbUnavailable(dpy)) {
350	_XRefreshKeyboardMapping((XMappingEvent *)event);
351	return Success;
352    }
353    xkbi= dpy->xkb_info;
354
355    if (((event->type&0x7f)-xkbi->codes->first_event)!=XkbEventCode)
356	return BadMatch;
357    if (event->xkb_type==XkbNewKeyboardNotify) {
358	_XkbReloadDpy(dpy);
359	return Success;
360    }
361    if (event->xkb_type==XkbMapNotify) {
362	XkbMapChangesRec	changes;
363	Status			rtrn;
364
365	if (xkbi->flags&XkbMapPending)
366	     changes= xkbi->changes;
367	else bzero(&changes,sizeof(changes));
368	XkbNoteMapChanges(&changes,event,XKB_XLIB_MAP_MASK);
369	if ((rtrn=XkbGetMapChanges(dpy,xkbi->desc,&changes))!=Success) {
370#ifdef DEBUG
371	    fprintf(stderr,"Internal Error! XkbGetMapChanges failed:\n");
372#endif
373	    xkbi->changes= changes;
374	}
375	else if (xkbi->flags&XkbMapPending) {
376	    xkbi->flags&= ~XkbMapPending;
377	    bzero(&xkbi->changes,sizeof(XkbMapChangesRec));
378	}
379	return rtrn;
380    }
381    return BadMatch;
382}
383
384int
385XRefreshKeyboardMapping(register XMappingEvent *event)
386{
387    XkbEvent	*xkbevent = (XkbEvent *)event;
388    Display *dpy = event->display;
389    XkbMapChangesRec changes;
390    XkbInfoPtr xkbi;
391
392    /* always do this for input methods, which still use the old keymap */
393    (void) _XRefreshKeyboardMapping(event);
394
395    if (_XkbUnavailable(dpy))
396	return 1;
397
398    xkbi = dpy->xkb_info;
399
400    if (((event->type&0x7f)-xkbi->codes->first_event)==XkbEventCode)
401	return XkbRefreshKeyboardMapping(&xkbevent->map);
402
403    if (xkbi->flags&XkbXlibNewKeyboard) {
404	_XkbReloadDpy(dpy);
405	return 1;
406    }
407
408    if ((xkbi->flags&XkbMapPending)||(event->request==MappingKeyboard)) {
409	if (xkbi->flags&XkbMapPending) {
410	    changes= xkbi->changes;
411	    _XkbNoteCoreMapChanges(&changes,event,XKB_XLIB_MAP_MASK);
412	}
413	else {
414	    bzero(&changes,sizeof(changes));
415	    changes.changed= XkbKeySymsMask;
416	    if (xkbi->desc->min_key_code<xkbi->desc->max_key_code) {
417		changes.first_key_sym= xkbi->desc->min_key_code;
418		changes.num_key_syms= xkbi->desc->max_key_code-
419						xkbi->desc->min_key_code+1;
420	    }
421	    else {
422		changes.first_key_sym= event->first_keycode;
423		changes.num_key_syms= event->count;
424	    }
425	}
426
427	if (XkbGetMapChanges(dpy,xkbi->desc, &changes)!=Success) {
428#ifdef DEBUG
429		fprintf(stderr,"Internal Error! XkbGetMapChanges failed:\n");
430		if (changes.changed&XkbKeyTypesMask) {
431		    int first= changes.first_type;
432		    int last= changes.first_type+changes.num_types-1;
433		    fprintf(stderr,"       types:  %d..%d\n",first,last);
434		}
435		if (changes.changed&XkbKeySymsMask) {
436		    int first= changes.first_key_sym;
437		    int last= changes.first_key_sym+changes.num_key_syms-1;
438		    fprintf(stderr,"     symbols:  %d..%d\n",first,last);
439		}
440		if (changes.changed&XkbKeyActionsMask) {
441		    int last,first= changes.first_key_act;
442		    last= changes.first_key_act+changes.num_key_acts-1;
443		    fprintf(stderr,"     acts:  %d..%d\n",first,last);
444		}
445		if (changes.changed&XkbKeyBehaviorsMask) {
446		    int last,first= changes.first_key_behavior;
447		    last= first+changes.num_key_behaviors-1;
448		    fprintf(stderr,"   behaviors:  %d..%d\n",first,last);
449		}
450		if (changes.changed&XkbVirtualModsMask) {
451		    fprintf(stderr,"virtual mods: 0x%04x\n",
452					changes.vmods);
453		}
454		if (changes.changed&XkbExplicitComponentsMask) {
455		    int last,first= changes.first_key_explicit;
456		    last= first+changes.num_key_explicit-1;
457		    fprintf(stderr,"    explicit:  %d..%d\n",first,last);
458		}
459#endif
460	}
461	LockDisplay(dpy);
462	if (xkbi->flags&XkbMapPending) {
463	    xkbi->flags&= ~XkbMapPending;
464	    bzero(&xkbi->changes,sizeof(XkbMapChangesRec));
465	}
466	UnlockDisplay(dpy);
467    }
468    if (event->request==MappingModifier) {
469	LockDisplay(dpy);
470	if (xkbi->desc->map->modmap) {
471	    _XkbFree(xkbi->desc->map->modmap);
472	    xkbi->desc->map->modmap= NULL;
473	}
474	if (dpy->key_bindings) {
475	    register struct _XKeytrans *p;
476	    for (p = dpy->key_bindings; p; p = p->next) {
477		register int i;
478		p->state= 0;
479	  	if (p->mlen>0) {
480		    for (i = 0; i < p->mlen; i++) {
481			p->state|= XkbKeysymToModifiers(dpy,p->modifiers[i]);
482		    }
483		    if (p->state)	p->state &= AllMods;
484		    else		p->state = AnyModifier;
485		}
486	    }
487	}
488	UnlockDisplay(dpy);
489    }
490    return 1;
491}
492
493static int
494_XkbLoadDpy(Display *dpy)
495{
496    XkbInfoPtr xkbi;
497    unsigned query,oldEvents;
498    XkbDescRec *desc;
499
500    if (!XkbUseExtension(dpy,NULL,NULL))
501	return 0;
502
503    xkbi = dpy->xkb_info;
504    query = XkbAllClientInfoMask;
505    desc = XkbGetMap(dpy,query,XkbUseCoreKbd);
506    if (!desc) {
507#ifdef DEBUG
508	fprintf(stderr,"Warning! XkbGetMap failed!\n");
509#endif
510	return 0;
511    }
512    LockDisplay(dpy);
513    xkbi->desc = desc;
514
515    UnlockDisplay(dpy);
516    oldEvents= xkbi->selected_events;
517    if (!(xkbi->xlib_ctrls&XkbLC_IgnoreNewKeyboards)) {
518	XkbSelectEventDetails(dpy,xkbi->desc->device_spec,XkbNewKeyboardNotify,
519				XkbNKN_KeycodesMask|XkbNKN_DeviceIDMask,
520				XkbNKN_KeycodesMask|XkbNKN_DeviceIDMask);
521    }
522    XkbSelectEventDetails(dpy,xkbi->desc->device_spec,XkbMapNotify,
523				XkbAllClientInfoMask,XkbAllClientInfoMask);
524    LockDisplay(dpy);
525    xkbi->selected_events= oldEvents;
526    UnlockDisplay(dpy);
527    return 1;
528}
529
530void
531_XkbReloadDpy(Display *dpy)
532{
533    XkbInfoPtr xkbi;
534    XkbDescRec *desc;
535    unsigned	oldDeviceID;
536
537    if (_XkbUnavailable(dpy))
538	return;
539
540    xkbi = dpy->xkb_info;
541    LockDisplay(dpy);
542    if (xkbi->desc) {
543	oldDeviceID= xkbi->desc->device_spec;
544	XkbFreeKeyboard(xkbi->desc,XkbAllComponentsMask,True);
545	xkbi->desc= NULL;
546	xkbi->flags&= ~(XkbMapPending|XkbXlibNewKeyboard);
547	xkbi->changes.changed= 0;
548    }
549    else oldDeviceID= XkbUseCoreKbd;
550    UnlockDisplay(dpy);
551    desc = XkbGetMap(dpy,XkbAllClientInfoMask,XkbUseCoreKbd);
552    if (!desc)
553	return;
554    LockDisplay(dpy);
555    xkbi->desc = desc;
556    UnlockDisplay(dpy);
557
558    if (desc->device_spec!=oldDeviceID) {
559	/* transfer(?) event masks here */
560#ifdef NOTYET
561	unsigned oldEvents;
562	oldEvents= xkbi->selected_events;
563	XkbSelectEventDetails(dpy,xkbi->desc->device_spec,XkbMapNotify,
564				XkbAllMapComponentsMask,XkbAllClientInfoMask);
565	LockDisplay(dpy);
566	xkbi->selected_events= oldEvents;
567	UnlockDisplay(dpy);
568#endif
569    }
570    return;
571}
572
573int
574XkbTranslateKeySym(	register Display *	dpy,
575			register KeySym *	sym_rtrn,
576			unsigned int 		mods,
577			char *			buffer,
578			int 			nbytes,
579			int *			extra_rtrn)
580{
581    register XkbInfoPtr	xkb;
582    XkbKSToMBFunc cvtr;
583    XPointer priv;
584    char tmp[4];
585    int n;
586
587    xkb= dpy->xkb_info;
588    if (!xkb->cvt.KSToMB) {
589        _XkbGetConverters(_XkbGetCharset(),&xkb->cvt);
590        _XkbGetConverters("ISO8859-1",&xkb->latin1cvt);
591    }
592
593    if (extra_rtrn)
594	*extra_rtrn= 0;
595
596    if ((buffer==NULL)||(nbytes==0)) {
597	buffer= tmp;
598	nbytes= 4;
599    }
600
601    /* see if symbol rebound, if so, return that string. */
602    n = XkbLookupKeyBinding(dpy,*sym_rtrn,mods,buffer,nbytes,extra_rtrn);
603    if (n)
604        return n;
605
606    if ( nbytes>0 )
607	buffer[0]= '\0';
608
609    if ( xkb->cvt.KSToUpper && (mods&LockMask) ) {
610	*sym_rtrn = (*xkb->cvt.KSToUpper)(*sym_rtrn);
611    }
612    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
613	cvtr = xkb->latin1cvt.KSToMB;
614	priv = xkb->latin1cvt.KSToMBPriv;
615    } else {
616	cvtr = xkb->cvt.KSToMB;
617	priv = xkb->cvt.KSToMBPriv;
618    }
619
620    n = (*cvtr)(priv,*sym_rtrn,buffer,nbytes,extra_rtrn);
621
622    if ((!xkb->cvt.KSToUpper)&&( mods&LockMask )) {
623	register int i;
624	int change;
625	char ch;
626	for (i=change=0;i<n;i++) {
627	    ch= toupper(buffer[i]);
628	    change= (change||(buffer[i]!=ch));
629	    buffer[i] = ch;
630	}
631	if (change) {
632	    if (n==1)
633	        *sym_rtrn=(*xkb->cvt.MBToKS)(xkb->cvt.MBToKSPriv,buffer,n,NULL);
634	    else *sym_rtrn= NoSymbol;
635	}
636    }
637
638    if ( mods&ControlMask ) {
639	if ( n==1 ) {
640	    buffer[0]= XkbToControl(buffer[0]);
641	    if ( nbytes>1 )
642		buffer[1]= '\0';
643	    return 1;
644	}
645	if ( nbytes > 0 )
646	    buffer[0]= '\0';
647	return 0;
648    }
649    return n;
650}
651
652int
653XLookupString (	register XKeyEvent *	event,
654		char *			buffer,
655		int 			nbytes,
656		KeySym *		keysym,
657		XComposeStatus *	status)
658{
659    KeySym	dummy;
660    int rtrnLen;
661    unsigned int new_mods;
662    Display *dpy = event->display;
663
664    if (keysym==NULL)
665	keysym= &dummy;
666    if (!XkbLookupKeySym(dpy,event->keycode,event->state, &new_mods,keysym))
667	return 0;
668    new_mods= (event->state&(~new_mods));
669
670    /* find the group where a symbol can be converted to control one */
671    if (new_mods&ControlMask && *keysym > 0x7F &&
672	(dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
673	XKeyEvent tmp_ev = *event;
674	KeySym tmp_keysym;
675	unsigned int tmp_new_mods;
676	if (_XkbUnavailable(dpy)) {
677            tmp_ev.state= event->state ^ dpy->mode_switch;
678            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
679                                &tmp_new_mods, &tmp_keysym) &&
680                tmp_keysym != NoSymbol && tmp_keysym < 0x80 ) {
681                *keysym = tmp_keysym;
682            }
683        } else {
684            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
685            int i;
686            for (i = 0; i < n; i++) {
687                if (XkbGroupForCoreState(event->state) == i)
688                    continue;
689                tmp_ev.state= XkbBuildCoreState(tmp_ev.state, i);
690                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
691                                     &tmp_new_mods, &tmp_keysym) &&
692                    tmp_keysym != NoSymbol && tmp_keysym < 0x80 ) {
693                    *keysym = tmp_keysym;
694                    new_mods= (event->state&(~tmp_new_mods));
695                    break;
696                }
697            }
698        }
699    }
700
701#ifdef USE_OWN_COMPOSE
702    if ( status ) {
703	static int been_here= 0;
704	if ( !been_here ) {
705	    XimCompInitTables();
706	    been_here = 1;
707	}
708	if ( !XimCompLegalStatus(status) ) {
709	    status->compose_ptr = NULL;
710	    status->chars_matched = 0;
711	}
712	if ( ((status->chars_matched>0)&&(status->compose_ptr!=NULL)) ||
713		XimCompIsComposeKey(*keysym,event->keycode,status) ) {
714	    XimCompRtrn rtrn;
715
716	    switch (XimCompProcessSym(status,*keysym,&rtrn)) {
717		case XIM_COMP_IGNORE:
718		    break;
719		case XIM_COMP_IN_PROGRESS:
720		    if ( keysym!=NULL )
721			*keysym = NoSymbol;
722#ifndef NO_COMPOSE_LED
723		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
724			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
725						True,True,False,NULL);
726		    }
727#endif
728		    return 0;
729		case XIM_COMP_FAIL:
730		{
731		    static Atom _ComposeFail= None;
732		    int n = 0, len= 0;
733#ifndef NO_COMPOSE_LED
734		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
735			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
736						True,False,False,NULL);
737		    }
738#endif
739#ifndef NO_BELL_ON_COMPOSE_FAIL
740		    if (dpy->xkb_info->xlib_ctrls&XkbLC_BeepOnComposeFail) {
741			if (_ComposeFail==None)
742			    _ComposeFail= XInternAtom(dpy,"ComposeFail",0);
743			XkbBell(dpy,event->window,0,_ComposeFail);
744		    }
745#endif
746		    for (n=len=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
747			if ( nbytes-len > 0 ) {
748			    len+= XkbTranslateKeySym(dpy,&rtrn.sym[n],new_mods,
749							buffer+len,nbytes-len,
750							NULL);
751			}
752		    }
753		    if ( keysym!=NULL ) {
754			if ( n==1 )	*keysym = rtrn.sym[0];
755			else		*keysym = NoSymbol;
756		    }
757		    return len;
758		}
759		case XIM_COMP_SUCCEED:
760		{
761		    int len,n = 0;
762
763#ifndef NO_COMPOSE_LED
764		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
765			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
766						True,False,False,NULL);
767		    }
768#endif
769		    *keysym = rtrn.matchSym;
770		    if ( rtrn.str[0]!='\0' ) {
771			strncpy(buffer,rtrn.str,nbytes-1);
772			buffer[nbytes-1]= '\0';
773			len = (int)strlen(buffer);
774		    }
775		    else {
776			len = XkbTranslateKeySym(dpy,keysym,new_mods,
777							buffer,nbytes,
778							NULL);
779		    }
780		    for (n=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
781			if ( nbytes-len > 0 ) {
782			    len+= XkbTranslateKeySym(dpy,&rtrn.sym[n],
783							event->state,
784							buffer+len,nbytes-len,
785							NULL);
786			}
787		    }
788		    return len;
789		}
790	    }
791	}
792    }
793#endif
794
795    /* We *should* use the new_mods (which does not contain any modifiers */
796    /* that were used to compute the symbol here, but pre-XKB XLookupString */
797    /* did not and we have to remain compatible.  Sigh. */
798    if (_XkbUnavailable(dpy) ||
799	(dpy->xkb_info->xlib_ctrls&XkbLC_ConsumeLookupMods)==0)
800	new_mods= event->state;
801
802    rtrnLen= XkbLookupKeyBinding(dpy,*keysym,new_mods,buffer,nbytes,NULL);
803    if (rtrnLen>0)
804	return rtrnLen;
805
806    return XkbTranslateKeySym(dpy,keysym,new_mods,buffer,nbytes,NULL);
807}
808
809
810int
811XkbLookupKeyBinding(	Display *		dpy,
812			register KeySym 	sym,
813			unsigned int 		mods,
814			char *			buffer,
815			int 			nbytes,
816			int * 			extra_rtrn)
817{
818    register struct _XKeytrans *p;
819
820    if (extra_rtrn)
821	*extra_rtrn= 0;
822    for (p = dpy->key_bindings; p; p = p->next) {
823	if (((mods & AllMods) == p->state) && (sym == p->key)) {
824	    int tmp = p->len;
825	    if (tmp > nbytes) {
826		if (extra_rtrn)
827		    *extra_rtrn= (tmp-nbytes);
828		tmp = nbytes;
829	    }
830	    memcpy (buffer, p->string, tmp);
831	    if (tmp < nbytes)	buffer[tmp]= '\0';
832	    return tmp;
833	}
834    }
835    return 0;
836}
837
838char
839XkbToControl( char ch )
840{
841    register char c = ch;
842
843    if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
844    else if (c == '2') c = '\000';
845    else if (c >= '3' && c <= '7') c -= ('3' - '\033');
846    else if (c == '8') c = '\177';
847    else if (c == '/') c = '_' & 0x1F;
848    return c;
849}
850