コード例 #1
0
ファイル: SDL_x11keyboard.c プロジェクト: abakobo/monkey2
KeySym
X11_KeyCodeToSym(_THIS, KeyCode keycode, unsigned char group)
{
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    KeySym keysym;

#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    if (data->xkb) {
        int num_groups     = XkbKeyNumGroups(data->xkb, keycode);
        unsigned char info = XkbKeyGroupInfo(data->xkb, keycode);
        
        if (num_groups && group >= num_groups) {
        
            int action = XkbOutOfRangeGroupAction(info);
            
            if (action == XkbRedirectIntoRange) {
                if ((group = XkbOutOfRangeGroupNumber(info)) >= num_groups) {
                    group = 0;
                }
            } else if (action == XkbClampIntoRange) {
                group = num_groups - 1;
            } else {
                group %= num_groups;
            }
        }
        keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0);
    } else {
        keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
    }
#else
    keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
#endif

    return keysym;
}
コード例 #2
0
ファイル: XKBBind.c プロジェクト: sheldonrobinson/VcXsrv
KeySym
XkbKeycodeToKeysym(Display *dpy,
#if NeedWidePrototypes
		 unsigned int kc,
#else
		 KeyCode kc,
#endif
		 int 	group,
		 int	level)
{
    XkbDescRec	*xkb;

    if (_XkbUnavailable(dpy))
	return NoSymbol;

    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);

    xkb = dpy->xkb_info->desc;
    if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
	return NoSymbol;

    if ((group<0)||(level<0)||(group>=XkbKeyNumGroups(xkb,kc)))
	return NoSymbol;
    if (level>=XkbKeyGroupWidth(xkb,kc,group)) {
	/* for compatibility with the core protocol, _always_ allow  */
	/* two symbols in the first two groups.   If either of the   */
	/* two is of type ONE_LEVEL, just replicate the first symbol */
	if ((group>XkbGroup2Index)||(XkbKeyGroupWidth(xkb,kc,group)!=1)||
								(level!=1)) {
	    return NoSymbol;
	}
	level= 0;
    }
    return XkbKeySymEntry(xkb,kc,level,group);
}
コード例 #3
0
ファイル: InputXKB.c プロジェクト: CendioOssman/tigervnc
static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods)
{
	int nKeyGroups;
	unsigned effectiveGroup;

	nKeyGroups= XkbKeyNumGroups(xkb,key);
	if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
		return 0;

	effectiveGroup= XkbGroupForCoreState(mods);
	if ( effectiveGroup>=nKeyGroups ) {
		unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
		switch (XkbOutOfRangeGroupAction(groupInfo)) {
		default:
			effectiveGroup %= nKeyGroups;
			break;
		case XkbClampIntoRange:
			effectiveGroup = nKeyGroups-1;
			break;
		case XkbRedirectIntoRange:
			effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
			if (effectiveGroup>=nKeyGroups)
				effectiveGroup= 0;
			break;
		}
	}

	return effectiveGroup;
}
コード例 #4
0
ファイル: InputXKB.c プロジェクト: CendioOssman/tigervnc
static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods)
{
	XkbKeyTypeRec *type;
	int col,nKeyGroups;
	unsigned effectiveGroup;
	XkbAction *acts;

	if (!XkbKeyHasActions(xkb, key))
		return NULL;

	nKeyGroups= XkbKeyNumGroups(xkb,key);
	if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
		return NULL;

	acts = XkbKeyActionsPtr(xkb,key);

	/* find the offset of the effective group */
	col = 0;
	effectiveGroup= XkbGroupForCoreState(mods);
	if ( effectiveGroup>=nKeyGroups ) {
		unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
		switch (XkbOutOfRangeGroupAction(groupInfo)) {
		default:
			effectiveGroup %= nKeyGroups;
			break;
		case XkbClampIntoRange:
			effectiveGroup = nKeyGroups-1;
			break;
		case XkbRedirectIntoRange:
			effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
			if (effectiveGroup>=nKeyGroups)
				effectiveGroup= 0;
			break;
		}
	}
	col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
	type = XkbKeyKeyType(xkb,key,effectiveGroup);

	if (type->map) { /* find the column (shift level) within the group */
		register int i;
		register XkbKTMapEntryPtr entry;
		for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
			if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
				col+= entry->level;
				break;
			}
		}
	}

	return &acts[col];
}
コード例 #5
0
ファイル: XKBBind.c プロジェクト: sheldonrobinson/VcXsrv
KeySym
XKeycodeToKeysym(Display *dpy,
#if NeedWidePrototypes
		 unsigned int kc,
#else
		 KeyCode kc,
#endif
		 int col)
{
    XkbDescRec	*xkb;

    if (_XkbUnavailable(dpy))
	return _XKeycodeToKeysym(dpy, kc, col);

    _XkbCheckPendingRefresh(dpy,dpy->xkb_info);

    xkb = dpy->xkb_info->desc;
    if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
	return NoSymbol;

    if (col>3) {
	int lastSym,tmp,nGrp;

	lastSym= 3;
	nGrp= XkbKeyNumGroups(xkb,kc);
	if ((nGrp>0)&&((tmp=XkbKeyGroupWidth(xkb,kc,XkbGroup1Index))>2)) {
	    if (col<=(lastSym+tmp-2))
		return XkbKeycodeToKeysym(dpy,kc,XkbGroup1Index,col-lastSym+2);
	    lastSym+= tmp-2;
	}
	if ((nGrp>1)&&((tmp=XkbKeyGroupWidth(xkb,kc,XkbGroup2Index))>2)) {
	    if (col<=(lastSym+tmp-2))
		return XkbKeycodeToKeysym(dpy,kc,XkbGroup2Index,col-lastSym+2);
	    lastSym+= tmp-2;
	}
	if (nGrp>2) {
	    tmp= XkbKeyGroupWidth(xkb,kc,XkbGroup3Index);
	    if (col<=lastSym+tmp)
		return XkbKeycodeToKeysym(dpy,kc,XkbGroup3Index,col-lastSym);
	    lastSym+= tmp;
	}
	if (nGrp>3) {
	    tmp= XkbKeyGroupWidth(xkb,kc,XkbGroup4Index);
	    if (col<=lastSym+tmp)
		return XkbKeycodeToKeysym(dpy,kc,XkbGroup4Index,col-lastSym);
	}
	return NoSymbol;
    }
    return XkbKeycodeToKeysym(dpy,kc,(col>>1),(col&1));
}
コード例 #6
0
ファイル: bind.c プロジェクト: Sixdsn/terra-terminal
/* Return the modifier mask that needs to be pressed to produce key in the
 * given group (keyboard layout) and level ("shift level").
 */
static GdkModifierType
FinallyGetModifiersForKeycode (XkbDescPtr xkb,
                               KeyCode    key,
                               uint     group,
                               uint     level)
{
	int nKeyGroups;
	int effectiveGroup;
	XkbKeyTypeRec *type;
	int k;

	nKeyGroups = XkbKeyNumGroups(xkb, key);
	if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) {
		return MODIFIERS_ERROR;
	}

	/* Taken from GDK's MyEnhancedXkbTranslateKeyCode */
	/* find the offset of the effective group */
	effectiveGroup = group;
	if (effectiveGroup >= nKeyGroups) {
		unsigned groupInfo = XkbKeyGroupInfo(xkb,key);
		switch (XkbOutOfRangeGroupAction(groupInfo)) {
			default:
				effectiveGroup %= nKeyGroups;
				break;
			case XkbClampIntoRange:
				effectiveGroup = nKeyGroups-1;
				break;
			case XkbRedirectIntoRange:
				effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
				if (effectiveGroup >= nKeyGroups)
					effectiveGroup = 0;
				break;
		}
	}
	type = XkbKeyKeyType(xkb, key, effectiveGroup);
	for (k = 0; k < type->map_count; k++) {
		if (type->map[k].active && type->map[k].level == level) {
			if (type->preserve) {
				return (type->map[k].mods.mask &
				        ~type->preserve[k].mask);
			} else {
				return type->map[k].mods.mask;
			}
		}
	}
	return MODIFIERS_NONE;
}
コード例 #7
0
void KeyboardLayoutWidget::drawKeyLabel(QPainter* painter, uint keycode, int angle, int xkb_origin_x, int xkb_origin_y, int xkb_width, int xkb_height, bool is_pressed)
{
    int x, y, width, height;
    int padding;
    int g, l, glp;

    if (!xkb)
        return;

    padding = 23 * ratio;   /* 2.3mm */

    x = xkbToPixmapCoord (xkb_origin_x);
    y = xkbToPixmapCoord (xkb_origin_y);
    width = xkbToPixmapCoord (xkb_origin_x + xkb_width) - x;
    height = xkbToPixmapCoord (xkb_origin_y + xkb_height) - y;

    for (glp = KEYBOARD_DRAWING_POS_TOPLEFT;
         glp < KEYBOARD_DRAWING_POS_TOTAL; glp++) {
        if (groupLevels[glp] == NULL)
            continue;
        g = groupLevels[glp]->group;
        l = groupLevels[glp]->level;

        if (g < 0 || g >= XkbKeyNumGroups (xkb, keycode))
            continue;
        if (l < 0
            || l >= XkbKeyGroupWidth (xkb, keycode, g))
            continue;

        /* Skip "exotic" levels like the "Ctrl" level in PC_SYSREQ */
        if (l > 0) {
            uint mods = XkbKeyKeyType (xkb, keycode,
                            g)->mods.mask;
            if ((mods & (ShiftMask | l3mod)) == 0)
                continue;
        }

        if (trackModifiers) {
            uint mods_rtrn;
            KeySym keysym;

            if (XkbTranslateKeyCode (xkb, keycode,
                         XkbBuildCoreState(mods, g),
                         &mods_rtrn, &keysym)) {
                drawKeyLabelHelper (painter, keysym, angle, glp,
                               x, y, width, height,
                               padding,
                               is_pressed);
                /* reverse y order */
            }
        } else {
            KeySym keysym;

            keysym =
                XkbKeySymEntry (xkb, keycode, l, g);

            drawKeyLabelHelper (painter, keysym,
                           angle, glp, x, y, width,
                           height, padding,
                           is_pressed);
            /* reverse y order */
        }
    }
}
コード例 #8
0
Bool
XkbLookupGroupAndLevel(	XkbDescPtr 	xkb,
                        int 		key,
                        int *		mods_inout,
                        int *		grp_inout,
                        int *		lvl_rtrn)
{
    int		nG,eG;

    if ((!xkb)||(!XkbKeycodeInRange(xkb,key))||(!grp_inout))
        return False;

    nG= XkbKeyNumGroups(xkb,key);
    eG= *grp_inout;

    if ( nG==0 ) {
        *grp_inout= 0;
        if (lvl_rtrn!=NULL)
            *lvl_rtrn= 0;
        return False;
    }
    else if ( nG==1 ) {
        eG= 0;
    }
    else if ( eG>=nG ) {
        unsigned gI= XkbKeyGroupInfo(xkb,key);
        switch (XkbOutOfRangeGroupAction(gI)) {
        default:
            eG %= nG;
            break;
        case XkbClampIntoRange:
            eG = nG-1;
            break;
        case XkbRedirectIntoRange:
            eG = XkbOutOfRangeGroupNumber(gI);
            if (eG>=nG)
                eG= 0;
            break;
        }
    }
    *grp_inout= eG;
    if (mods_inout!=NULL) {
        XkbKeyTypePtr	type;
        int		preserve;

        type = XkbKeyKeyType(xkb,key,eG);
        if (lvl_rtrn!=NULL)
            *lvl_rtrn= 0;
        preserve= 0;
        if (type->map) { /* find the shift level */
            register int i;
            register XkbKTMapEntryPtr entry;
            for (i=0,entry=type->map; i<type->map_count; i++,entry++) {
                if ((entry->active)&&
                        (((*mods_inout)&type->mods.mask)==entry->mods.mask)) {
                    if (lvl_rtrn!=NULL)
                        *lvl_rtrn= entry->level;
                    if (type->preserve)
                        preserve= type->preserve[i].mask;
                    break;
                }
            }
        }
        (*mods_inout)&= ~(type->mods.mask&(~preserve));
    }
    return True;
}
コード例 #9
0
ファイル: InputXKB.c プロジェクト: CendioOssman/tigervnc
/* Stolen from libX11 */
static Bool
XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key,
                    register unsigned int mods, unsigned int *mods_rtrn,
                    KeySym *keysym_rtrn)
{
	XkbKeyTypeRec *type;
	int col,nKeyGroups;
	unsigned preserve,effectiveGroup;
	KeySym *syms;

	if (mods_rtrn!=NULL)
		*mods_rtrn = 0;

	nKeyGroups= XkbKeyNumGroups(xkb,key);
	if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
		if (keysym_rtrn!=NULL)
			*keysym_rtrn = NoSymbol;
		return False;
	}

	syms = XkbKeySymsPtr(xkb,key);

	/* find the offset of the effective group */
	col = 0;
	effectiveGroup= XkbGroupForCoreState(mods);
	if ( effectiveGroup>=nKeyGroups ) {
		unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
		switch (XkbOutOfRangeGroupAction(groupInfo)) {
		default:
			effectiveGroup %= nKeyGroups;
			break;
		case XkbClampIntoRange:
			effectiveGroup = nKeyGroups-1;
			break;
		case XkbRedirectIntoRange:
			effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
			if (effectiveGroup>=nKeyGroups)
				effectiveGroup= 0;
			break;
		}
	}
	col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
	type = XkbKeyKeyType(xkb,key,effectiveGroup);

	preserve= 0;
	if (type->map) { /* find the column (shift level) within the group */
		register int i;
		register XkbKTMapEntryPtr entry;
		for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
			if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
				col+= entry->level;
				if (type->preserve)
					preserve= type->preserve[i].mask;
				break;
			}
		}
	}

	if (keysym_rtrn!=NULL)
		*keysym_rtrn= syms[col];
	if (mods_rtrn)
		*mods_rtrn= type->mods.mask&(~preserve);

	return (syms[col]!=NoSymbol);
}
コード例 #10
0
ファイル: InputXKB.c プロジェクト: CendioOssman/tigervnc
KeyCode vncAddKeysym(KeySym keysym, unsigned state)
{
	DeviceIntPtr master;
	XkbDescPtr xkb;
	unsigned int key;

	XkbEventCauseRec cause;
	XkbChangesRec changes;

	int types[1];
	KeySym *syms;
	KeySym upper, lower;

	master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
	xkb = master->key->xkbInfo->desc;
	for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
		if (XkbKeyNumGroups(xkb, key) == 0)
			break;
	}

	if (key < xkb->min_key_code)
		return 0;

	memset(&changes, 0, sizeof(changes));
	memset(&cause, 0, sizeof(cause));

	XkbSetCauseUnknown(&cause);

	/*
	 * Tools like xkbcomp get confused if there isn't a name
	 * assigned to the keycode we're trying to use.
	 */
	if (xkb->names && xkb->names->keys &&
	    (xkb->names->keys[key].name[0] == '\0')) {
		xkb->names->keys[key].name[0] = 'I';
		xkb->names->keys[key].name[1] = '0' + (key / 100) % 10;
		xkb->names->keys[key].name[2] = '0' + (key /  10) % 10;
		xkb->names->keys[key].name[3] = '0' + (key /   1) % 10;

		changes.names.changed |= XkbKeyNamesMask;
		changes.names.first_key = key;
		changes.names.num_keys = 1;
	}

	/* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */

	/*
	 * For keysyms that are affected by Lock, we are better off
	 * using ALPHABETIC rather than ONE_LEVEL as the latter
	 * generally cannot produce lower case when Lock is active.
	 */
	XkbConvertCase(keysym, &lower, &upper);
	if (upper == lower)
		types[XkbGroup1Index] = XkbOneLevelIndex;
	else
		types[XkbGroup1Index] = XkbAlphabeticIndex;

	XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map);

	syms = XkbKeySymsPtr(xkb,key);
	if (upper == lower)
		syms[0] = keysym;
	else {
		syms[0] = lower;
		syms[1] = upper;
	}

	changes.map.changed |= XkbKeySymsMask;
	changes.map.first_key_sym = key;
	changes.map.num_key_syms = 1;

	XkbSendNotification(master, &changes, &cause);

	return key;
}
コード例 #11
0
ファイル: XKBBind.c プロジェクト: sheldonrobinson/VcXsrv
int
XLookupString (	register XKeyEvent *	event,
		char *			buffer,
		int 			nbytes,
		KeySym *		keysym,
		XComposeStatus *	status)
{
    KeySym	dummy;
    int rtrnLen;
    unsigned int new_mods;
    Display *dpy = event->display;

    if (keysym==NULL)
	keysym= &dummy;
    if (!XkbLookupKeySym(dpy,event->keycode,event->state, &new_mods,keysym))
	return 0;
    new_mods= (event->state&(~new_mods));

    /* find the group where a symbol can be converted to control one */
    if (new_mods&ControlMask && *keysym > 0x7F &&
	(dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
	XKeyEvent tmp_ev = *event;
	KeySym tmp_keysym;
	unsigned int tmp_new_mods;
	if (_XkbUnavailable(dpy)) {
            tmp_ev.state= event->state ^ dpy->mode_switch;
            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
                                &tmp_new_mods, &tmp_keysym) &&
                tmp_keysym != NoSymbol && tmp_keysym < 0x80 ) {
                *keysym = tmp_keysym;
            }
        } else {
            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
            int i;
            for (i = 0; i < n; i++) {
                if (XkbGroupForCoreState(event->state) == i)
                    continue;
                tmp_ev.state= XkbBuildCoreState(tmp_ev.state, i);
                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
                                     &tmp_new_mods, &tmp_keysym) &&
                    tmp_keysym != NoSymbol && tmp_keysym < 0x80 ) {
                    *keysym = tmp_keysym;
                    new_mods= (event->state&(~tmp_new_mods));
                    break;
                }
            }
        }
    }

#ifdef USE_OWN_COMPOSE
    if ( status ) {
	static int been_here= 0;
	if ( !been_here ) {
	    XimCompInitTables();
	    been_here = 1;
	}
	if ( !XimCompLegalStatus(status) ) {
	    status->compose_ptr = NULL;
	    status->chars_matched = 0;
	}
	if ( ((status->chars_matched>0)&&(status->compose_ptr!=NULL)) ||
		XimCompIsComposeKey(*keysym,event->keycode,status) ) {
	    XimCompRtrn rtrn;

	    switch (XimCompProcessSym(status,*keysym,&rtrn)) {
		case XIM_COMP_IGNORE:
		    break;
		case XIM_COMP_IN_PROGRESS:
		    if ( keysym!=NULL )
			*keysym = NoSymbol;
#ifndef NO_COMPOSE_LED
		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
						True,True,False,NULL);
		    }
#endif
		    return 0;
		case XIM_COMP_FAIL:
		{
		    static Atom _ComposeFail= None;
		    int n = 0, len= 0;
#ifndef NO_COMPOSE_LED
		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
						True,False,False,NULL);
		    }
#endif
#ifndef NO_BELL_ON_COMPOSE_FAIL
		    if (dpy->xkb_info->xlib_ctrls&XkbLC_BeepOnComposeFail) {
			if (_ComposeFail==None)
			    _ComposeFail= XInternAtom(dpy,"ComposeFail",0);
			XkbBell(dpy,event->window,0,_ComposeFail);
		    }
#endif
		    for (n=len=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
			if ( nbytes-len > 0 ) {
			    len+= XkbTranslateKeySym(dpy,&rtrn.sym[n],new_mods,
							buffer+len,nbytes-len,
							NULL);
			}
		    }
		    if ( keysym!=NULL ) {
			if ( n==1 )	*keysym = rtrn.sym[0];
			else		*keysym = NoSymbol;
		    }
		    return len;
		}
		case XIM_COMP_SUCCEED:
		{
		    int len,n = 0;

#ifndef NO_COMPOSE_LED
		    if ( dpy->xkb_info->xlib_ctrls&XkbLC_ComposeLED ) {
			XkbSetNamedIndicator(dpy,dpy->xkb_info->composeLED,
						True,False,False,NULL);
		    }
#endif
		    *keysym = rtrn.matchSym;
		    if ( rtrn.str[0]!='\0' ) {
			strncpy(buffer,rtrn.str,nbytes-1);
			buffer[nbytes-1]= '\0';
			len = (int)strlen(buffer);
		    }
		    else {
			len = XkbTranslateKeySym(dpy,keysym,new_mods,
							buffer,nbytes,
							NULL);
		    }
		    for (n=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
			if ( nbytes-len > 0 ) {
			    len+= XkbTranslateKeySym(dpy,&rtrn.sym[n],
							event->state,
							buffer+len,nbytes-len,
							NULL);
			}
		    }
		    return len;
		}
	    }
	}
    }
#endif

    /* We *should* use the new_mods (which does not contain any modifiers */
    /* that were used to compute the symbol here, but pre-XKB XLookupString */
    /* did not and we have to remain compatible.  Sigh. */
    if (_XkbUnavailable(dpy) ||
	(dpy->xkb_info->xlib_ctrls&XkbLC_ConsumeLookupMods)==0)
	new_mods= event->state;

    rtrnLen= XkbLookupKeyBinding(dpy,*keysym,new_mods,buffer,nbytes,NULL);
    if (rtrnLen>0)
	return rtrnLen;

    return XkbTranslateKeySym(dpy,keysym,new_mods,buffer,nbytes,NULL);
}
コード例 #12
0
ファイル: XKBBind.c プロジェクト: sheldonrobinson/VcXsrv
Bool
XkbTranslateKeyCode(	register XkbDescPtr	xkb,
			KeyCode 		key,
			register unsigned int 	mods,
			unsigned int *		mods_rtrn,
			KeySym *		keysym_rtrn)
{
    XkbKeyTypeRec *type;
    int col,nKeyGroups;
    unsigned preserve,effectiveGroup;
    KeySym *syms;

    if (mods_rtrn!=NULL)
	*mods_rtrn = 0;

    nKeyGroups= XkbKeyNumGroups(xkb,key);
    if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
	if (keysym_rtrn!=NULL)
	    *keysym_rtrn = NoSymbol;
	return False;
    }

    syms = XkbKeySymsPtr(xkb,key);

    /* find the offset of the effective group */
    col = 0;
    effectiveGroup= XkbGroupForCoreState(mods);
    if ( effectiveGroup>=nKeyGroups ) {
	unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
	switch (XkbOutOfRangeGroupAction(groupInfo)) {
	    default:
		effectiveGroup %= nKeyGroups;
		break;
	    case XkbClampIntoRange:
		effectiveGroup = nKeyGroups-1;
		break;
	    case XkbRedirectIntoRange:
		effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
		if (effectiveGroup>=nKeyGroups)
		    effectiveGroup= 0;
		break;
	}
    }
    col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
    type = XkbKeyKeyType(xkb,key,effectiveGroup);

    preserve= 0;
    if (type->map) { /* find the column (shift level) within the group */
	register int i;
	register XkbKTMapEntryPtr entry;
	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
	    if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
		col+= entry->level;
		if (type->preserve)
		    preserve= type->preserve[i].mask;
		break;
	    }
	}
    }

    if (keysym_rtrn!=NULL)
	*keysym_rtrn= syms[col];
    if (mods_rtrn) {
	*mods_rtrn= type->mods.mask&(~preserve);
	/* The Motif VTS doesn't get the help callback called if help
	 * is bound to Shift+<whatever>, and it appears as though it
	 * is XkbTranslateKeyCode that is causing the problem.  The
	 * core X version of XTranslateKey always OR's in ShiftMask
	 * and LockMask for mods_rtrn, so this "fix" keeps this behavior
	 * and solves the VTS problem.
	 */
	if ((xkb->dpy)&&(xkb->dpy->xkb_info)&&
	    (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) {
	    *mods_rtrn|= (ShiftMask|LockMask);
	}
    }
    return (syms[col]!=NoSymbol);
}