XKBBind.c revision 61b2299d
11ab64890Smrg/* $Xorg: XKBBind.c,v 1.4 2001/02/09 02:03:37 xorgcvs Exp $ */
21ab64890Smrg/*
31ab64890Smrg
41ab64890SmrgCopyright 1985, 1987, 1994, 1998  The Open Group
51ab64890Smrg
61ab64890SmrgPermission to use, copy, modify, distribute, and sell this software and its
71ab64890Smrgdocumentation for any purpose is hereby granted without fee, provided that
81ab64890Smrgthe above copyright notice appear in all copies and that both that
91ab64890Smrgcopyright notice and this permission notice appear in supporting
101ab64890Smrgdocumentation.
111ab64890Smrg
121ab64890SmrgThe above copyright notice and this permission notice shall be included
131ab64890Smrgin all copies or substantial portions of the Software.
141ab64890Smrg
151ab64890SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
161ab64890SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
171ab64890SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
181ab64890SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
191ab64890SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
201ab64890SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
211ab64890SmrgOTHER DEALINGS IN THE SOFTWARE.
221ab64890Smrg
231ab64890SmrgExcept as contained in this notice, the name of The Open Group shall
241ab64890Smrgnot be used in advertising or otherwise to promote the sale, use or
251ab64890Smrgother dealings in this Software without prior written authorization
261ab64890Smrgfrom The Open Group.
271ab64890Smrg
281ab64890Smrg*/
291ab64890Smrg/* $XFree86: xc/lib/X11/XKBBind.c,v 3.19 2003/05/27 22:26:25 tsi Exp $ */
301ab64890Smrg
311ab64890Smrg	/* the new monsters ate the old ones */
321ab64890Smrg
331ab64890Smrg#define NEED_EVENTS
341ab64890Smrg#ifdef HAVE_CONFIG_H
351ab64890Smrg#include <config.h>
361ab64890Smrg#endif
371ab64890Smrg#include "XKBlib.h"
381ab64890Smrg#include <X11/Xlibint.h>
391ab64890Smrg#include <X11/Xutil.h>
401ab64890Smrg#include <X11/keysym.h>
411ab64890Smrg#include <stdio.h>
421ab64890Smrg#include <ctype.h>
431ab64890Smrg
441ab64890Smrg#include <X11/extensions/XKBproto.h>
451ab64890Smrg#include "XKBlibint.h"
461ab64890Smrg
471ab64890Smrg#ifdef USE_OWN_COMPOSE
481ab64890Smrg#define	COMPOSE_NO_CONST_MEMBERS
491ab64890Smrg#include "imComp.h"
501ab64890Smrg#endif
511ab64890Smrg
521ab64890Smrg#define AllMods (ShiftMask|LockMask|ControlMask| \
531ab64890Smrg		 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
541ab64890Smrg
551ab64890Smrgstatic int _XkbLoadDpy(
561ab64890Smrg    Display *dpy
571ab64890Smrg);
581ab64890Smrg
591ab64890Smrgstruct _XKeytrans {
601ab64890Smrg	struct _XKeytrans *next;/* next on list */
611ab64890Smrg	char *string;		/* string to return when the time comes */
621ab64890Smrg	int len;		/* length of string (since NULL is legit)*/
631ab64890Smrg	KeySym key;		/* keysym rebound */
641ab64890Smrg	unsigned int state;	/* modifier state */
651ab64890Smrg	KeySym *modifiers;	/* modifier keysyms you want */
661ab64890Smrg	int mlen;		/* length of modifier list */
671ab64890Smrg};
681ab64890Smrg
691ab64890SmrgKeySym
701ab64890SmrgXkbKeycodeToKeysym(Display *dpy,
711ab64890Smrg#if NeedWidePrototypes
721ab64890Smrg		 unsigned int kc,
731ab64890Smrg#else
741ab64890Smrg		 KeyCode kc,
751ab64890Smrg#endif
761ab64890Smrg		 int 	group,
771ab64890Smrg		 int	level)
781ab64890Smrg{
791ab64890Smrg    XkbDescRec	*xkb;
8061b2299dSmrg
811ab64890Smrg    if (_XkbUnavailable(dpy))
821ab64890Smrg	return NoSymbol;
831ab64890Smrg
841ab64890Smrg    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
851ab64890Smrg
861ab64890Smrg    xkb = dpy->xkb_info->desc;
871ab64890Smrg    if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
881ab64890Smrg	return NoSymbol;
891ab64890Smrg
901ab64890Smrg    if ((group<0)||(level<0)||(group>=XkbKeyNumGroups(xkb,kc)))
911ab64890Smrg	return NoSymbol;
921ab64890Smrg    if (level>=XkbKeyGroupWidth(xkb,kc,group)) {
931ab64890Smrg	/* for compatibility with the core protocol, _always_ allow  */
941ab64890Smrg	/* two symbols in the first two groups.   If either of the   */
951ab64890Smrg	/* two is of type ONE_LEVEL, just replicate the first symbol */
961ab64890Smrg	if ((group>XkbGroup2Index)||(XkbKeyGroupWidth(xkb,kc,group)!=1)||
971ab64890Smrg								(level!=1)) {
981ab64890Smrg	    return NoSymbol;
991ab64890Smrg	}
1001ab64890Smrg	level= 0;
1011ab64890Smrg    }
1021ab64890Smrg    return XkbKeySymEntry(xkb,kc,level,group);
1031ab64890Smrg}
1041ab64890Smrg
1051ab64890SmrgKeySym
1061ab64890SmrgXKeycodeToKeysym(Display *dpy,
1071ab64890Smrg#if NeedWidePrototypes
1081ab64890Smrg		 unsigned int kc,
1091ab64890Smrg#else
1101ab64890Smrg		 KeyCode kc,
1111ab64890Smrg#endif
1121ab64890Smrg		 int col)
1131ab64890Smrg{
1141ab64890Smrg    XkbDescRec	*xkb;
11561b2299dSmrg
1161ab64890Smrg    if (_XkbUnavailable(dpy))
1171ab64890Smrg	return _XKeycodeToKeysym(dpy, kc, col);
1181ab64890Smrg
1191ab64890Smrg    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
1201ab64890Smrg
1211ab64890Smrg    xkb = dpy->xkb_info->desc;
1221ab64890Smrg    if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
1231ab64890Smrg	return NoSymbol;
12461b2299dSmrg
1251ab64890Smrg    if (col>3) {
1261ab64890Smrg	int lastSym,tmp,nGrp;
1271ab64890Smrg
1281ab64890Smrg	lastSym= 3;
1291ab64890Smrg	nGrp= XkbKeyNumGroups(xkb,kc);
1301ab64890Smrg	if ((nGrp>0)&&((tmp=XkbKeyGroupWidth(xkb,kc,XkbGroup1Index))>2)) {
1311ab64890Smrg	    if (col<=(lastSym+tmp-2))
1321ab64890Smrg		return XkbKeycodeToKeysym(dpy,kc,XkbGroup1Index,col-lastSym+2);
1331ab64890Smrg	    lastSym+= tmp-2;
1341ab64890Smrg	}
1351ab64890Smrg	if ((nGrp>1)&&((tmp=XkbKeyGroupWidth(xkb,kc,XkbGroup2Index))>2)) {
1361ab64890Smrg	    if (col<=(lastSym+tmp-2))
1371ab64890Smrg		return XkbKeycodeToKeysym(dpy,kc,XkbGroup2Index,col-lastSym+2);
1381ab64890Smrg	    lastSym+= tmp-2;
1391ab64890Smrg	}
1401ab64890Smrg	if (nGrp>2) {
1411ab64890Smrg	    tmp= XkbKeyGroupWidth(xkb,kc,XkbGroup3Index);
1421ab64890Smrg	    if (col<=lastSym+tmp)
1431ab64890Smrg		return XkbKeycodeToKeysym(dpy,kc,XkbGroup3Index,col-lastSym);
1441ab64890Smrg	    lastSym+= tmp;
1451ab64890Smrg	}
1461ab64890Smrg	if (nGrp>3) {
1471ab64890Smrg	    tmp= XkbKeyGroupWidth(xkb,kc,XkbGroup4Index);
1481ab64890Smrg	    if (col<=lastSym+tmp)
1491ab64890Smrg		return XkbKeycodeToKeysym(dpy,kc,XkbGroup4Index,col-lastSym);
1501ab64890Smrg	}
1511ab64890Smrg	return NoSymbol;
1521ab64890Smrg    }
1531ab64890Smrg    return XkbKeycodeToKeysym(dpy,kc,(col>>1),(col&1));
1541ab64890Smrg}
1551ab64890Smrg
1561ab64890SmrgKeyCode
1571ab64890SmrgXKeysymToKeycode(Display *dpy, KeySym ks)
1581ab64890Smrg{
1591ab64890Smrg    register int i, j, gotOne;
1601ab64890Smrg
1611ab64890Smrg    if (_XkbUnavailable(dpy))
1621ab64890Smrg	return _XKeysymToKeycode(dpy,ks);
1631ab64890Smrg    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
1641ab64890Smrg
1651ab64890Smrg    j= 0;
1661ab64890Smrg    do {
1671ab64890Smrg	register XkbDescRec *xkb = dpy->xkb_info->desc;
1681ab64890Smrg	gotOne= 0;
1691ab64890Smrg	for (i = dpy->min_keycode; i <= dpy->max_keycode; i++) {
1701ab64890Smrg	    if ( j<(int)XkbKeyNumSyms(xkb,i) ) {
1711ab64890Smrg		gotOne = 1;
1721ab64890Smrg		if ((XkbKeySym(xkb,i,j)==ks))
1731ab64890Smrg		    return i;
1741ab64890Smrg	    }
1751ab64890Smrg	}
1761ab64890Smrg	j++;
1771ab64890Smrg    } while (gotOne);
1781ab64890Smrg    return 0;
1791ab64890Smrg}
1801ab64890Smrg
1811ab64890Smrgstatic int
1821ab64890Smrg_XkbComputeModmap(Display *dpy)
1831ab64890Smrg{
1841ab64890Smrgregister XkbDescPtr xkb;
1851ab64890Smrg
1861ab64890Smrg    xkb= dpy->xkb_info->desc;
1871ab64890Smrg    if (XkbGetUpdatedMap(dpy,XkbModifierMapMask,xkb)==Success)
1881ab64890Smrg	return 1;
1891ab64890Smrg    return 0;
1901ab64890Smrg}
1911ab64890Smrg
1921ab64890Smrgunsigned
1931ab64890SmrgXkbKeysymToModifiers(Display *dpy,KeySym ks)
1941ab64890Smrg{
1951ab64890Smrg    XkbDescRec *xkb;
1961ab64890Smrg    register int i,j;
1971ab64890Smrg    register KeySym *pSyms;
1981ab64890Smrg    CARD8 mods;
1991ab64890Smrg
2001ab64890Smrg    if (_XkbUnavailable(dpy))
2011ab64890Smrg	return _XKeysymToModifiers(dpy,ks);
2021ab64890Smrg    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
2031ab64890Smrg
2041ab64890Smrg    if (_XkbNeedModmap(dpy->xkb_info)&&(!_XkbComputeModmap(dpy)))
2051ab64890Smrg	return _XKeysymToModifiers(dpy,ks);
2061ab64890Smrg
2071ab64890Smrg    xkb= dpy->xkb_info->desc;
2081ab64890Smrg    mods= 0;
2091ab64890Smrg    for (i = xkb->min_key_code; i <= (int)xkb->max_key_code; i++) {
2101ab64890Smrg	pSyms= XkbKeySymsPtr(xkb,i);
2111ab64890Smrg	for (j=XkbKeyNumSyms(xkb,i)-1;j>=0;j--) {
2121ab64890Smrg	    if (pSyms[j]==ks) {
2131ab64890Smrg		mods|= xkb->map->modmap[i];
2141ab64890Smrg		break;
2151ab64890Smrg	    }
2161ab64890Smrg	}
2171ab64890Smrg    }
2181ab64890Smrg    return mods;
2191ab64890Smrg}
2201ab64890Smrg
2211ab64890SmrgKeySym
2221ab64890SmrgXLookupKeysym(register XKeyEvent *event, int col)
2231ab64890Smrg{
2241ab64890Smrg    Display *dpy = event->display;
2251ab64890Smrg    if (_XkbUnavailable(dpy))
2261ab64890Smrg	return _XLookupKeysym(event, col);
2271ab64890Smrg    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
2281ab64890Smrg    return XKeycodeToKeysym(dpy, event->keycode, col);
2291ab64890Smrg}
2301ab64890Smrg
2311ab64890Smrg   /*
23261b2299dSmrg    * Not a public entry point -- XkbTranslateKey is an obsolete name
23361b2299dSmrg    * that is preserved here so that functions linked against the old
2341ab64890Smrg    * version will continue to work in a shared library environment.
2351ab64890Smrg    */
2361ab64890Smrgint
2371ab64890SmrgXkbTranslateKey(	register Display *	dpy,
2381ab64890Smrg			KeyCode 		key,
2391ab64890Smrg			register unsigned int 	mods,
2401ab64890Smrg			unsigned int *		mods_rtrn,
2411ab64890Smrg			KeySym *		keysym_rtrn);
2421ab64890Smrgint
2431ab64890SmrgXkbTranslateKey(	register Display *	dpy,
2441ab64890Smrg			KeyCode 		key,
2451ab64890Smrg			register unsigned int 	mods,
2461ab64890Smrg			unsigned int *		mods_rtrn,
2471ab64890Smrg			KeySym *		keysym_rtrn)
2481ab64890Smrg{
2491ab64890Smrg    return XkbLookupKeySym(dpy,key,mods,mods_rtrn,keysym_rtrn);
2501ab64890Smrg}
2511ab64890Smrg
2521ab64890SmrgBool
2531ab64890SmrgXkbLookupKeySym(	register Display *	dpy,
2541ab64890Smrg			KeyCode 		key,
2551ab64890Smrg			register unsigned int 	mods,
2561ab64890Smrg			unsigned int *		mods_rtrn,
2571ab64890Smrg			KeySym *		keysym_rtrn)
2581ab64890Smrg{
2591ab64890Smrg    if (_XkbUnavailable(dpy))
2601ab64890Smrg	return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
2611ab64890Smrg    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);
2621ab64890Smrg    return XkbTranslateKeyCode(dpy->xkb_info->desc,key,mods,mods_rtrn,
2631ab64890Smrg								keysym_rtrn);
2641ab64890Smrg}
2651ab64890Smrg
2661ab64890SmrgBool
2671ab64890SmrgXkbTranslateKeyCode(	register XkbDescPtr	xkb,
2681ab64890Smrg			KeyCode 		key,
2691ab64890Smrg			register unsigned int 	mods,
2701ab64890Smrg			unsigned int *		mods_rtrn,
2711ab64890Smrg			KeySym *		keysym_rtrn)
2721ab64890Smrg{
2731ab64890Smrg    XkbKeyTypeRec *type;
2741ab64890Smrg    int col,nKeyGroups;
2751ab64890Smrg    unsigned preserve,effectiveGroup;
2761ab64890Smrg    KeySym *syms;
2771ab64890Smrg
2781ab64890Smrg    if (mods_rtrn!=NULL)
2791ab64890Smrg	*mods_rtrn = 0;
2801ab64890Smrg
2811ab64890Smrg    nKeyGroups= XkbKeyNumGroups(xkb,key);
2821ab64890Smrg    if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
2831ab64890Smrg	if (keysym_rtrn!=NULL)
2841ab64890Smrg	    *keysym_rtrn = NoSymbol;
2851ab64890Smrg	return False;
2861ab64890Smrg    }
2871ab64890Smrg
2881ab64890Smrg    syms = XkbKeySymsPtr(xkb,key);
2891ab64890Smrg
2901ab64890Smrg    /* find the offset of the effective group */
2911ab64890Smrg    col = 0;
2921ab64890Smrg    effectiveGroup= XkbGroupForCoreState(mods);
2931ab64890Smrg    if ( effectiveGroup>=nKeyGroups ) {
2941ab64890Smrg	unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
2951ab64890Smrg	switch (XkbOutOfRangeGroupAction(groupInfo)) {
2961ab64890Smrg	    default:
2971ab64890Smrg		effectiveGroup %= nKeyGroups;
2981ab64890Smrg		break;
2991ab64890Smrg	    case XkbClampIntoRange:
3001ab64890Smrg		effectiveGroup = nKeyGroups-1;
3011ab64890Smrg		break;
3021ab64890Smrg	    case XkbRedirectIntoRange:
3031ab64890Smrg		effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
3041ab64890Smrg		if (effectiveGroup>=nKeyGroups)
3051ab64890Smrg		    effectiveGroup= 0;
3061ab64890Smrg		break;
3071ab64890Smrg	}
3081ab64890Smrg    }
3091ab64890Smrg    col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
3101ab64890Smrg    type = XkbKeyKeyType(xkb,key,effectiveGroup);
3111ab64890Smrg
3121ab64890Smrg    preserve= 0;
3131ab64890Smrg    if (type->map) { /* find the column (shift level) within the group */
3141ab64890Smrg	register int i;
3151ab64890Smrg	register XkbKTMapEntryPtr entry;
3161ab64890Smrg	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
3171ab64890Smrg	    if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
3181ab64890Smrg		col+= entry->level;
3191ab64890Smrg		if (type->preserve)
3201ab64890Smrg		    preserve= type->preserve[i].mask;
3211ab64890Smrg		break;
3221ab64890Smrg	    }
3231ab64890Smrg	}
3241ab64890Smrg    }
3251ab64890Smrg
3261ab64890Smrg    if (keysym_rtrn!=NULL)
3271ab64890Smrg	*keysym_rtrn= syms[col];
3281ab64890Smrg    if (mods_rtrn) {
3291ab64890Smrg	*mods_rtrn= type->mods.mask&(~preserve);
3301ab64890Smrg	/* The Motif VTS doesn't get the help callback called if help
33161b2299dSmrg	 * is bound to Shift+<whatever>, and it appears as though it
33261b2299dSmrg	 * is XkbTranslateKeyCode that is causing the problem.  The
33361b2299dSmrg	 * core X version of XTranslateKey always OR's in ShiftMask
33461b2299dSmrg	 * and LockMask for mods_rtrn, so this "fix" keeps this behavior
3351ab64890Smrg	 * and solves the VTS problem.
3361ab64890Smrg	 */
3371ab64890Smrg	if ((xkb->dpy)&&(xkb->dpy->xkb_info)&&
3381ab64890Smrg	    (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) {
3391ab64890Smrg	    *mods_rtrn|= (ShiftMask|LockMask);
3401ab64890Smrg	}
3411ab64890Smrg    }
3421ab64890Smrg    return (syms[col]!=NoSymbol);
3431ab64890Smrg}
3441ab64890Smrg
3451ab64890SmrgStatus
3461ab64890SmrgXkbRefreshKeyboardMapping(register XkbMapNotifyEvent *event)
3471ab64890Smrg{
3481ab64890Smrg    Display *dpy = event->display;
3491ab64890Smrg    XkbInfoPtr xkbi;
3501ab64890Smrg
3511ab64890Smrg    if (_XkbUnavailable(dpy)) {
3521ab64890Smrg	_XRefreshKeyboardMapping((XMappingEvent *)event);
3531ab64890Smrg	return Success;
3541ab64890Smrg    }
3551ab64890Smrg    xkbi= dpy->xkb_info;
3561ab64890Smrg
3571ab64890Smrg    if (((event->type&0x7f)-xkbi->codes->first_event)!=XkbEventCode)
3581ab64890Smrg	return BadMatch;
3591ab64890Smrg    if (event->xkb_type==XkbNewKeyboardNotify) {
3601ab64890Smrg	_XkbReloadDpy(dpy);
3611ab64890Smrg	return Success;
3621ab64890Smrg    }
3631ab64890Smrg    if (event->xkb_type==XkbMapNotify) {
3641ab64890Smrg	XkbMapChangesRec	changes;
3651ab64890Smrg	Status			rtrn;
3661ab64890Smrg
3671ab64890Smrg	if (xkbi->flags&XkbMapPending)
3681ab64890Smrg	     changes= xkbi->changes;
3691ab64890Smrg	else bzero(&changes,sizeof(changes));
3701ab64890Smrg	XkbNoteMapChanges(&changes,event,XKB_XLIB_MAP_MASK);
3711ab64890Smrg	if ((rtrn=XkbGetMapChanges(dpy,xkbi->desc,&changes))!=Success) {
3721ab64890Smrg#ifdef DEBUG
3731ab64890Smrg	    fprintf(stderr,"Internal Error! XkbGetMapChanges failed:\n");
3741ab64890Smrg#endif
3751ab64890Smrg	    xkbi->changes= changes;
3761ab64890Smrg	}
3771ab64890Smrg	else if (xkbi->flags&XkbMapPending) {
3781ab64890Smrg	    xkbi->flags&= ~XkbMapPending;
3791ab64890Smrg	    bzero(&xkbi->changes,sizeof(XkbMapChangesRec));
3801ab64890Smrg	}
3811ab64890Smrg	return rtrn;
3821ab64890Smrg    }
3831ab64890Smrg    return BadMatch;
3841ab64890Smrg}
3851ab64890Smrg
3861ab64890Smrgint
3871ab64890SmrgXRefreshKeyboardMapping(register XMappingEvent *event)
3881ab64890Smrg{
3891ab64890Smrg    XkbEvent	*xkbevent = (XkbEvent *)event;
3901ab64890Smrg    Display *dpy = event->display;
3911ab64890Smrg    XkbMapChangesRec changes;
3921ab64890Smrg    XkbInfoPtr xkbi;
3931ab64890Smrg
3941ab64890Smrg    /* always do this for input methods, which still use the old keymap */
3951ab64890Smrg    (void) _XRefreshKeyboardMapping(event);
3961ab64890Smrg
3971ab64890Smrg    if (_XkbUnavailable(dpy))
3981ab64890Smrg	return 1;
3991ab64890Smrg
4001ab64890Smrg    xkbi = dpy->xkb_info;
4011ab64890Smrg
4021ab64890Smrg    if (((event->type&0x7f)-xkbi->codes->first_event)==XkbEventCode)
4031ab64890Smrg	return XkbRefreshKeyboardMapping(&xkbevent->map);
4041ab64890Smrg
4051ab64890Smrg    if (xkbi->flags&XkbXlibNewKeyboard) {
4061ab64890Smrg	_XkbReloadDpy(dpy);
4071ab64890Smrg	return 1;
4081ab64890Smrg    }
4091ab64890Smrg
4101ab64890Smrg    if ((xkbi->flags&XkbMapPending)||(event->request==MappingKeyboard)) {
4111ab64890Smrg	if (xkbi->flags&XkbMapPending) {
4121ab64890Smrg	    changes= xkbi->changes;
4131ab64890Smrg	    _XkbNoteCoreMapChanges(&changes,event,XKB_XLIB_MAP_MASK);
4141ab64890Smrg	}
4151ab64890Smrg	else {
4161ab64890Smrg	    bzero(&changes,sizeof(changes));
4171ab64890Smrg	    changes.changed= XkbKeySymsMask;
4181ab64890Smrg	    if (xkbi->desc->min_key_code<xkbi->desc->max_key_code) {
4191ab64890Smrg		changes.first_key_sym= xkbi->desc->min_key_code;
4201ab64890Smrg		changes.num_key_syms= xkbi->desc->max_key_code-
4211ab64890Smrg						xkbi->desc->min_key_code+1;
4221ab64890Smrg	    }
4231ab64890Smrg	    else {
4241ab64890Smrg		changes.first_key_sym= event->first_keycode;
4251ab64890Smrg		changes.num_key_syms= event->count;
4261ab64890Smrg	    }
4271ab64890Smrg	}
4281ab64890Smrg
4291ab64890Smrg	if (XkbGetMapChanges(dpy,xkbi->desc, &changes)!=Success) {
4301ab64890Smrg#ifdef DEBUG
4311ab64890Smrg		fprintf(stderr,"Internal Error! XkbGetMapChanges failed:\n");
4321ab64890Smrg		if (changes.changed&XkbKeyTypesMask) {
4331ab64890Smrg		    int first= changes.first_type;
4341ab64890Smrg		    int last= changes.first_type+changes.num_types-1;
4351ab64890Smrg		    fprintf(stderr,"       types:  %d..%d\n",first,last);
4361ab64890Smrg		}
4371ab64890Smrg		if (changes.changed&XkbKeySymsMask) {
4381ab64890Smrg		    int first= changes.first_key_sym;
4391ab64890Smrg		    int last= changes.first_key_sym+changes.num_key_syms-1;
4401ab64890Smrg		    fprintf(stderr,"     symbols:  %d..%d\n",first,last);
4411ab64890Smrg		}
4421ab64890Smrg		if (changes.changed&XkbKeyActionsMask) {
4431ab64890Smrg		    int last,first= changes.first_key_act;
4441ab64890Smrg		    last= changes.first_key_act+changes.num_key_acts-1;
4451ab64890Smrg		    fprintf(stderr,"     acts:  %d..%d\n",first,last);
4461ab64890Smrg		}
4471ab64890Smrg		if (changes.changed&XkbKeyBehaviorsMask) {
4481ab64890Smrg		    int last,first= changes.first_key_behavior;
4491ab64890Smrg		    last= first+changes.num_key_behaviors-1;
4501ab64890Smrg		    fprintf(stderr,"   behaviors:  %d..%d\n",first,last);
4511ab64890Smrg		}
4521ab64890Smrg		if (changes.changed&XkbVirtualModsMask) {
4531ab64890Smrg		    fprintf(stderr,"virtual mods: 0x%04x\n",
4541ab64890Smrg					changes.vmods);
4551ab64890Smrg		}
4561ab64890Smrg		if (changes.changed&XkbExplicitComponentsMask) {
4571ab64890Smrg		    int last,first= changes.first_key_explicit;
4581ab64890Smrg		    last= first+changes.num_key_explicit-1;
4591ab64890Smrg		    fprintf(stderr,"    explicit:  %d..%d\n",first,last);
4601ab64890Smrg		}
4611ab64890Smrg#endif
4621ab64890Smrg	}
4631ab64890Smrg	LockDisplay(dpy);
4641ab64890Smrg	if (xkbi->flags&XkbMapPending) {
4651ab64890Smrg	    xkbi->flags&= ~XkbMapPending;
4661ab64890Smrg	    bzero(&xkbi->changes,sizeof(XkbMapChangesRec));
4671ab64890Smrg	}
4681ab64890Smrg	UnlockDisplay(dpy);
4691ab64890Smrg    }
4701ab64890Smrg    if (event->request==MappingModifier) {
4711ab64890Smrg	LockDisplay(dpy);
4721ab64890Smrg	if (xkbi->desc->map->modmap) {
4731ab64890Smrg	    _XkbFree(xkbi->desc->map->modmap);
4741ab64890Smrg	    xkbi->desc->map->modmap= NULL;
4751ab64890Smrg	}
4761ab64890Smrg	if (dpy->key_bindings) {
4771ab64890Smrg	    register struct _XKeytrans *p;
4781ab64890Smrg	    for (p = dpy->key_bindings; p; p = p->next) {
4791ab64890Smrg		register int i;
4801ab64890Smrg		p->state= 0;
4811ab64890Smrg	  	if (p->mlen>0) {
4821ab64890Smrg		    for (i = 0; i < p->mlen; i++) {
4831ab64890Smrg			p->state|= XkbKeysymToModifiers(dpy,p->modifiers[i]);
4841ab64890Smrg		    }
4851ab64890Smrg		    if (p->state)	p->state &= AllMods;
4861ab64890Smrg		    else		p->state = AnyModifier;
4871ab64890Smrg		}
4881ab64890Smrg	    }
4891ab64890Smrg	}
4901ab64890Smrg	UnlockDisplay(dpy);
4911ab64890Smrg    }
4921ab64890Smrg    return 1;
4931ab64890Smrg}
4941ab64890Smrg
4951ab64890Smrgstatic int
4961ab64890Smrg_XkbLoadDpy(Display *dpy)
4971ab64890Smrg{
4981ab64890Smrg    XkbInfoPtr xkbi;
4991ab64890Smrg    unsigned query,oldEvents;
5001ab64890Smrg    XkbDescRec *desc;
5011ab64890Smrg
5021ab64890Smrg    if (!XkbUseExtension(dpy,NULL,NULL))
5031ab64890Smrg	return 0;
5041ab64890Smrg
5051ab64890Smrg    xkbi = dpy->xkb_info;
5061ab64890Smrg    query = XkbAllClientInfoMask;
5071ab64890Smrg    desc = XkbGetMap(dpy,query,XkbUseCoreKbd);
5081ab64890Smrg    if (!desc) {
5091ab64890Smrg#ifdef DEBUG
5101ab64890Smrg	fprintf(stderr,"Warning! XkbGetMap failed!\n");
5111ab64890Smrg#endif
5121ab64890Smrg	return 0;
5131ab64890Smrg    }
5141ab64890Smrg    LockDisplay(dpy);
5151ab64890Smrg    xkbi->desc = desc;
5161ab64890Smrg
5171ab64890Smrg    UnlockDisplay(dpy);
5181ab64890Smrg    oldEvents= xkbi->selected_events;
5191ab64890Smrg    if (!(xkbi->xlib_ctrls&XkbLC_IgnoreNewKeyboards)) {
5201ab64890Smrg	XkbSelectEventDetails(dpy,xkbi->desc->device_spec,XkbNewKeyboardNotify,
5211ab64890Smrg				XkbNKN_KeycodesMask|XkbNKN_DeviceIDMask,
5221ab64890Smrg				XkbNKN_KeycodesMask|XkbNKN_DeviceIDMask);
5231ab64890Smrg    }
5241ab64890Smrg    XkbSelectEventDetails(dpy,xkbi->desc->device_spec,XkbMapNotify,
5251ab64890Smrg				XkbAllClientInfoMask,XkbAllClientInfoMask);
5261ab64890Smrg    LockDisplay(dpy);
5271ab64890Smrg    xkbi->selected_events= oldEvents;
5281ab64890Smrg    UnlockDisplay(dpy);
5291ab64890Smrg    return 1;
5301ab64890Smrg}
5311ab64890Smrg
5321ab64890Smrgvoid
5331ab64890Smrg_XkbReloadDpy(Display *dpy)
5341ab64890Smrg{
5351ab64890Smrg    XkbInfoPtr xkbi;
5361ab64890Smrg    XkbDescRec *desc;
5371ab64890Smrg    unsigned	oldDeviceID;
5381ab64890Smrg
5391ab64890Smrg    if (_XkbUnavailable(dpy))
5401ab64890Smrg	return;
5411ab64890Smrg
5421ab64890Smrg    xkbi = dpy->xkb_info;
5431ab64890Smrg    LockDisplay(dpy);
5441ab64890Smrg    if (xkbi->desc) {
5451ab64890Smrg	oldDeviceID= xkbi->desc->device_spec;
5461ab64890Smrg	XkbFreeKeyboard(xkbi->desc,XkbAllComponentsMask,True);
5471ab64890Smrg	xkbi->desc= NULL;
5481ab64890Smrg	xkbi->flags&= ~(XkbMapPending|XkbXlibNewKeyboard);
5491ab64890Smrg	xkbi->changes.changed= 0;
5501ab64890Smrg    }
5511ab64890Smrg    else oldDeviceID= XkbUseCoreKbd;
5521ab64890Smrg    UnlockDisplay(dpy);
5531ab64890Smrg    desc = XkbGetMap(dpy,XkbAllClientInfoMask,XkbUseCoreKbd);
5541ab64890Smrg    if (!desc)
5551ab64890Smrg	return;
5561ab64890Smrg    LockDisplay(dpy);
5571ab64890Smrg    xkbi->desc = desc;
5581ab64890Smrg    UnlockDisplay(dpy);
5591ab64890Smrg
5601ab64890Smrg    if (desc->device_spec!=oldDeviceID) {
5611ab64890Smrg	/* transfer(?) event masks here */
5621ab64890Smrg#ifdef NOTYET
5631ab64890Smrg	unsigned oldEvents;
5641ab64890Smrg	oldEvents= xkbi->selected_events;
5651ab64890Smrg	XkbSelectEventDetails(dpy,xkbi->desc->device_spec,XkbMapNotify,
5661ab64890Smrg				XkbAllMapComponentsMask,XkbAllClientInfoMask);
5671ab64890Smrg	LockDisplay(dpy);
5681ab64890Smrg	xkbi->selected_events= oldEvents;
5691ab64890Smrg	UnlockDisplay(dpy);
5701ab64890Smrg#endif
5711ab64890Smrg    }
5721ab64890Smrg    return;
5731ab64890Smrg}
5741ab64890Smrg
5751ab64890Smrgint
5761ab64890SmrgXkbTranslateKeySym(	register Display *	dpy,
5771ab64890Smrg			register KeySym *	sym_rtrn,
5781ab64890Smrg			unsigned int 		mods,
5791ab64890Smrg			char *			buffer,
5801ab64890Smrg			int 			nbytes,
5811ab64890Smrg			int *			extra_rtrn)
5821ab64890Smrg{
5831ab64890Smrg    register XkbInfoPtr	xkb;
5841ab64890Smrg    XkbKSToMBFunc cvtr;
5851ab64890Smrg    XPointer priv;
5861ab64890Smrg    char tmp[4];
5871ab64890Smrg    int n;
5881ab64890Smrg
5891ab64890Smrg    xkb= dpy->xkb_info;
5901ab64890Smrg    if (!xkb->cvt.KSToMB) {
5911ab64890Smrg        _XkbGetConverters(_XkbGetCharset(),&xkb->cvt);
5921ab64890Smrg        _XkbGetConverters("ISO8859-1",&xkb->latin1cvt);
5931ab64890Smrg    }
5941ab64890Smrg
5951ab64890Smrg    if (extra_rtrn)
5961ab64890Smrg	*extra_rtrn= 0;
5971ab64890Smrg
5981ab64890Smrg    if ((buffer==NULL)||(nbytes==0)) {
5991ab64890Smrg	buffer= tmp;
6001ab64890Smrg	nbytes= 4;
6011ab64890Smrg    }
6021ab64890Smrg
6031ab64890Smrg    /* see if symbol rebound, if so, return that string. */
6041ab64890Smrg    n = XkbLookupKeyBinding(dpy,*sym_rtrn,mods,buffer,nbytes,extra_rtrn);
6051ab64890Smrg    if (n)
6061ab64890Smrg        return n;
6071ab64890Smrg
6081ab64890Smrg    if ( nbytes>0 )
6091ab64890Smrg	buffer[0]= '\0';
6101ab64890Smrg
6111ab64890Smrg    if ( xkb->cvt.KSToUpper && (mods&LockMask) ) {
6121ab64890Smrg	*sym_rtrn = (*xkb->cvt.KSToUpper)(*sym_rtrn);
6131ab64890Smrg    }
6141ab64890Smrg    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
6151ab64890Smrg	cvtr = xkb->latin1cvt.KSToMB;
6161ab64890Smrg	priv = xkb->latin1cvt.KSToMBPriv;
6171ab64890Smrg    } else {
6181ab64890Smrg	cvtr = xkb->cvt.KSToMB;
6191ab64890Smrg	priv = xkb->cvt.KSToMBPriv;
6201ab64890Smrg    }
6211ab64890Smrg
6221ab64890Smrg    n = (*cvtr)(priv,*sym_rtrn,buffer,nbytes,extra_rtrn);
6231ab64890Smrg
6241ab64890Smrg    if ((!xkb->cvt.KSToUpper)&&( mods&LockMask )) {
6251ab64890Smrg	register int i;
6261ab64890Smrg	int change;
6271ab64890Smrg	char ch;
6281ab64890Smrg	for (i=change=0;i<n;i++) {
6291ab64890Smrg	    ch= toupper(buffer[i]);
6301ab64890Smrg	    change= (change||(buffer[i]!=ch));
6311ab64890Smrg	    buffer[i] = ch;
6321ab64890Smrg	}
6331ab64890Smrg	if (change) {
6341ab64890Smrg	    if (n==1)
6351ab64890Smrg	        *sym_rtrn=(*xkb->cvt.MBToKS)(xkb->cvt.MBToKSPriv,buffer,n,0);
6361ab64890Smrg	    else *sym_rtrn= NoSymbol;
6371ab64890Smrg	}
6381ab64890Smrg    }
6391ab64890Smrg
6401ab64890Smrg    if ( mods&ControlMask ) {
6411ab64890Smrg	if ( n==1 ) {
6421ab64890Smrg	    buffer[0]= XkbToControl(buffer[0]);
6431ab64890Smrg	    if ( nbytes>1 )
6441ab64890Smrg		buffer[1]= '\0';
6451ab64890Smrg	    return 1;
6461ab64890Smrg	}
6471ab64890Smrg	if ( nbytes > 0 )
6481ab64890Smrg	    buffer[0]= '\0';
6491ab64890Smrg	return 0;
6501ab64890Smrg    }
6511ab64890Smrg    return n;
6521ab64890Smrg}
6531ab64890Smrg
6541ab64890Smrgint
6551ab64890SmrgXLookupString (	register XKeyEvent *	event,
6561ab64890Smrg		char *			buffer,
6571ab64890Smrg		int 			nbytes,
6581ab64890Smrg		KeySym *		keysym,
6591ab64890Smrg		XComposeStatus *	status)
6601ab64890Smrg{
6611ab64890Smrg    KeySym	dummy;
6621ab64890Smrg    int rtrnLen;
6631ab64890Smrg    unsigned int new_mods;
6641ab64890Smrg    Display *dpy = event->display;
6651ab64890Smrg
6661ab64890Smrg    if (keysym==NULL)
6671ab64890Smrg	keysym= &dummy;
6681ab64890Smrg    if (!XkbLookupKeySym(dpy,event->keycode,event->state, &new_mods,keysym))
6691ab64890Smrg	return 0;
6701ab64890Smrg    new_mods= (event->state&(~new_mods));
6711ab64890Smrg
6721ab64890Smrg    /* find the group where a symbol can be converted to control one */
6731ab64890Smrg    if (new_mods&ControlMask && *keysym > 0x7F &&
6741ab64890Smrg	(dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
6751ab64890Smrg	XKeyEvent tmp_ev = *event;
6761ab64890Smrg	KeySym tmp_keysym;
6771ab64890Smrg	unsigned int tmp_new_mods;
6781ab64890Smrg	if (_XkbUnavailable(dpy)) {
6791ab64890Smrg            tmp_ev.state= event->state ^ dpy->mode_switch;
6801ab64890Smrg            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
6811ab64890Smrg                                &tmp_new_mods, &tmp_keysym) &&
6821ab64890Smrg                tmp_keysym != NoSymbol && tmp_keysym < 0x80 ) {
6831ab64890Smrg                *keysym = tmp_keysym;
6841ab64890Smrg            }
6851ab64890Smrg        } else {
6861ab64890Smrg            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
6871ab64890Smrg            int i;
6881ab64890Smrg            for (i = 0; i < n; i++) {
6891ab64890Smrg                if (XkbGroupForCoreState(event->state) == i)
6901ab64890Smrg                    continue;
6911ab64890Smrg                tmp_ev.state= XkbBuildCoreState(tmp_ev.state, i);
6921ab64890Smrg                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
6931ab64890Smrg                                     &tmp_new_mods, &tmp_keysym) &&
6941ab64890Smrg                    tmp_keysym != NoSymbol && tmp_keysym < 0x80 ) {
6951ab64890Smrg                    *keysym = tmp_keysym;
6961ab64890Smrg                    new_mods= (event->state&(~tmp_new_mods));
6971ab64890Smrg                    break;
6981ab64890Smrg                }
6991ab64890Smrg            }
7001ab64890Smrg        }
70161b2299dSmrg    }
7021ab64890Smrg
7031ab64890Smrg#ifdef USE_OWN_COMPOSE
7041ab64890Smrg    if ( status ) {
7051ab64890Smrg	static int been_here= 0;
7061ab64890Smrg	if ( !been_here ) {
7071ab64890Smrg	    XimCompInitTables();
7081ab64890Smrg	    been_here = 1;
7091ab64890Smrg	}
7101ab64890Smrg	if ( !XimCompLegalStatus(status) ) {
7111ab64890Smrg	    status->compose_ptr = NULL;
7121ab64890Smrg	    status->chars_matched = 0;
7131ab64890Smrg	}
71461b2299dSmrg	if ( ((status->chars_matched>0)&&(status->compose_ptr!=NULL)) ||
7151ab64890Smrg		XimCompIsComposeKey(*keysym,event->keycode,status) ) {
7161ab64890Smrg	    XimCompRtrn rtrn;
7171ab64890Smrg
7181ab64890Smrg	    switch (XimCompProcessSym(status,*keysym,&rtrn)) {
7191ab64890Smrg		case XIM_COMP_IGNORE:
7201ab64890Smrg		    break;
7211ab64890Smrg		case XIM_COMP_IN_PROGRESS:
7221ab64890Smrg		    if ( keysym!=NULL )
7231ab64890Smrg			*keysym = NoSymbol;
7241ab64890Smrg#ifndef NO_COMPOSE_LED
7251ab64890Smrg		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
7261ab64890Smrg			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
7271ab64890Smrg						True,True,False,NULL);
7281ab64890Smrg		    }
7291ab64890Smrg#endif
7301ab64890Smrg		    return 0;
7311ab64890Smrg		case XIM_COMP_FAIL:
7321ab64890Smrg		{
7331ab64890Smrg		    static Atom _ComposeFail= None;
7341ab64890Smrg		    int n = 0, len= 0;
7351ab64890Smrg#ifndef NO_COMPOSE_LED
7361ab64890Smrg		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
7371ab64890Smrg			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
7381ab64890Smrg						True,False,False,NULL);
7391ab64890Smrg		    }
7401ab64890Smrg#endif
7411ab64890Smrg#ifndef NO_BELL_ON_COMPOSE_FAIL
7421ab64890Smrg		    if (dpy->xkb_info->xlib_ctrls&XkbLC_BeepOnComposeFail) {
7431ab64890Smrg			if (_ComposeFail==None)
7441ab64890Smrg			    _ComposeFail= XInternAtom(dpy,"ComposeFail",0);
7451ab64890Smrg			XkbBell(dpy,event->window,0,_ComposeFail);
7461ab64890Smrg		    }
7471ab64890Smrg#endif
7481ab64890Smrg		    for (n=len=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
7491ab64890Smrg			if ( nbytes-len > 0 ) {
7501ab64890Smrg			    len+= XkbTranslateKeySym(dpy,&rtrn.sym[n],new_mods,
7511ab64890Smrg							buffer+len,nbytes-len,
7521ab64890Smrg							NULL);
7531ab64890Smrg			}
7541ab64890Smrg		    }
7551ab64890Smrg		    if ( keysym!=NULL ) {
7561ab64890Smrg			if ( n==1 )	*keysym = rtrn.sym[0];
7571ab64890Smrg			else		*keysym = NoSymbol;
7581ab64890Smrg		    }
7591ab64890Smrg		    return len;
7601ab64890Smrg		}
7611ab64890Smrg		case XIM_COMP_SUCCEED:
7621ab64890Smrg		{
7631ab64890Smrg		    int len,n = 0;
7641ab64890Smrg
7651ab64890Smrg#ifndef NO_COMPOSE_LED
7661ab64890Smrg		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
7671ab64890Smrg			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
7681ab64890Smrg						True,False,False,NULL);
7691ab64890Smrg		    }
7701ab64890Smrg#endif
7711ab64890Smrg		    *keysym = rtrn.matchSym;
7721ab64890Smrg		    if ( rtrn.str[0]!='\0' ) {
7731ab64890Smrg			strncpy(buffer,rtrn.str,nbytes-1);
7741ab64890Smrg			buffer[nbytes-1]= '\0';
7751ab64890Smrg			len = (int)strlen(buffer);
7761ab64890Smrg		    }
7771ab64890Smrg		    else {
7781ab64890Smrg			len = XkbTranslateKeySym(dpy,keysym,new_mods,
7791ab64890Smrg							buffer,nbytes,
7801ab64890Smrg							NULL);
7811ab64890Smrg		    }
7821ab64890Smrg		    for (n=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
7831ab64890Smrg			if ( nbytes-len > 0 ) {
7841ab64890Smrg			    len+= XkbTranslateKeySym(dpy,&rtrn.sym[n],
7851ab64890Smrg							event->state,
7861ab64890Smrg							buffer+len,nbytes-len,
7871ab64890Smrg							NULL);
7881ab64890Smrg			}
7891ab64890Smrg		    }
7901ab64890Smrg		    return len;
7911ab64890Smrg		}
7921ab64890Smrg	    }
7931ab64890Smrg	}
7941ab64890Smrg    }
7951ab64890Smrg#endif
7961ab64890Smrg
7971ab64890Smrg    /* We *should* use the new_mods (which does not contain any modifiers */
7981ab64890Smrg    /* that were used to compute the symbol here, but pre-XKB XLookupString */
7991ab64890Smrg    /* did not and we have to remain compatible.  Sigh. */
8001ab64890Smrg    if (_XkbUnavailable(dpy) ||
8011ab64890Smrg	(dpy->xkb_info->xlib_ctrls&XkbLC_ConsumeLookupMods)==0)
8021ab64890Smrg	new_mods= event->state;
8031ab64890Smrg
8041ab64890Smrg    rtrnLen= XkbLookupKeyBinding(dpy,*keysym,new_mods,buffer,nbytes,NULL);
8051ab64890Smrg    if (rtrnLen>0)
8061ab64890Smrg	return rtrnLen;
8071ab64890Smrg
8081ab64890Smrg    return XkbTranslateKeySym(dpy,keysym,new_mods,buffer,nbytes,NULL);
8091ab64890Smrg}
8101ab64890Smrg
8111ab64890Smrg
8121ab64890Smrgint
8131ab64890SmrgXkbLookupKeyBinding(	Display *		dpy,
8141ab64890Smrg			register KeySym 	sym,
8151ab64890Smrg			unsigned int 		mods,
8161ab64890Smrg			char *			buffer,
8171ab64890Smrg			int 			nbytes,
8181ab64890Smrg			int * 			extra_rtrn)
8191ab64890Smrg{
82061b2299dSmrg    register struct _XKeytrans *p;
8211ab64890Smrg
8221ab64890Smrg    if (extra_rtrn)
8231ab64890Smrg	*extra_rtrn= 0;
8241ab64890Smrg    for (p = dpy->key_bindings; p; p = p->next) {
8251ab64890Smrg	if (((mods & AllMods) == p->state) && (sym == p->key)) {
8261ab64890Smrg	    int tmp = p->len;
8271ab64890Smrg	    if (tmp > nbytes) {
8281ab64890Smrg		if (extra_rtrn)
8291ab64890Smrg		    *extra_rtrn= (tmp-nbytes);
8301ab64890Smrg		tmp = nbytes;
8311ab64890Smrg	    }
8321ab64890Smrg	    memcpy (buffer, p->string, tmp);
8331ab64890Smrg	    if (tmp < nbytes)	buffer[tmp]= '\0';
8341ab64890Smrg	    return tmp;
8351ab64890Smrg	}
8361ab64890Smrg    }
8371ab64890Smrg    return 0;
8381ab64890Smrg}
8391ab64890Smrg
8401ab64890Smrgchar
8411ab64890SmrgXkbToControl( char ch )
8421ab64890Smrg{
8431ab64890Smrg    register char c = ch;
84461b2299dSmrg
8451ab64890Smrg    if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
8461ab64890Smrg    else if (c == '2') c = '\000';
8471ab64890Smrg    else if (c >= '3' && c <= '7') c -= ('3' - '\033');
8481ab64890Smrg    else if (c == '8') c = '\177';
8491ab64890Smrg    else if (c == '/') c = '_' & 0x1F;
8501ab64890Smrg    return c;
8511ab64890Smrg}
852