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