unsigned XkbKeysymToModifiers(Display *dpy,KeySym ks) { XkbDescRec *xkb; register int i,j; register KeySym *pSyms; CARD8 mods; if (_XkbUnavailable(dpy)) return _XKeysymToModifiers(dpy,ks); _XkbCheckPendingRefresh(dpy,dpy->xkb_info); if (_XkbNeedModmap(dpy->xkb_info)&&(!_XkbComputeModmap(dpy))) return _XKeysymToModifiers(dpy,ks); xkb= dpy->xkb_info->desc; mods= 0; for (i = xkb->min_key_code; i <= (int)xkb->max_key_code; i++) { pSyms= XkbKeySymsPtr(xkb,i); for (j=XkbKeyNumSyms(xkb,i)-1;j>=0;j--) { if (pSyms[j]==ks) { mods|= xkb->map->modmap[i]; break; } } } return mods; }
static int check_modmap_change_slave(ClientPtr client, DeviceIntPtr master, DeviceIntPtr slave, CARD8 *modmap) { XkbDescPtr master_xkb, slave_xkb; int i, j; if (!slave->key || !master->key) return 0; master_xkb = master->key->xkbInfo->desc; slave_xkb = slave->key->xkbInfo->desc; /* Ignore devices with a clearly different keymap. */ if (slave_xkb->min_key_code != master_xkb->min_key_code || slave_xkb->max_key_code != master_xkb->max_key_code) return 0; for (i = 0; i < MAP_LENGTH; i++) { if (!modmap[i]) continue; /* If we have different symbols for any modifier on an * extended keyboard, ignore the whole remap request. */ for (j = 0; j < XkbKeyNumSyms(slave_xkb, i) && j < XkbKeyNumSyms(master_xkb, i); j++) if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j]) return 0; } if (check_modmap_change(client, slave, modmap) != Success) return 0; return 1; }
static CARD32 AccessXSlowKeyExpire(OsTimerPtr timer,CARD32 now,pointer arg) { DeviceIntPtr keybd; XkbSrvInfoPtr xkbi; XkbDescPtr xkb; XkbControlsPtr ctrls; keybd= (DeviceIntPtr)arg; xkbi= keybd->key->xkbInfo; xkb= xkbi->desc; ctrls= xkb->ctrls; if (xkbi->slowKey!=0) { xkbAccessXNotify ev; KeySym *sym= XkbKeySymsPtr(xkb,xkbi->slowKey); ev.detail= XkbAXN_SKAccept; ev.keycode= xkbi->slowKey; ev.slowKeysDelay= ctrls->slow_keys_delay; ev.debounceDelay= ctrls->debounce_delay; XkbSendAccessXNotify(keybd,&ev); if (XkbAX_NeedFeedback(ctrls,XkbAX_SKAcceptFBMask)) XkbDDXAccessXBeep(keybd,_BEEP_SLOW_ACCEPT,XkbSlowKeysMask); AccessXKeyboardEvent(keybd,KeyPress,xkbi->slowKey,False); /* check for magic sequences */ if ((ctrls->enabled_ctrls&XkbAccessXKeysMask) && ((sym[0]==XK_Shift_R)||(sym[0]==XK_Shift_L))) xkbi->shiftKeyCount++; /* Start repeating if necessary. Stop autorepeating if the user * presses a non-modifier key that doesn't autorepeat. */ if (keybd->kbdfeed->ctrl.autoRepeat && ((xkbi->slowKey != xkbi->mouseKey) || (!xkbi->mouseKeysAccel)) && (ctrls->enabled_ctrls&XkbRepeatKeysMask)) { if (BitIsOn(keybd->kbdfeed->ctrl.autoRepeats,xkbi->slowKey)) { xkbi->repeatKey = xkbi->slowKey; xkbi->repeatKeyTimer= TimerSet(xkbi->repeatKeyTimer, 0, ctrls->repeat_delay, AccessXRepeatKeyExpire, (pointer)keybd); } } } return 0; }
/* 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); }
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; }
Bool AccessXFilterReleaseEvent( register xEvent * xE, register DeviceIntPtr keybd, int count) { XkbSrvInfoPtr xkbi = keybd->key->xkbInfo; XkbControlsPtr ctrls = xkbi->desc->ctrls; KeyCode key = xE->u.u.detail; Bool ignoreKeyEvent = FALSE; /* Don't transmit the KeyRelease if BounceKeys is on and * this is the release of a key that was ignored due to * BounceKeys. */ if (ctrls->enabled_ctrls & XkbBounceKeysMask) { if ((key!=xkbi->mouseKey)&&(!BitIsOn(keybd->key->down,key))) ignoreKeyEvent = TRUE; xkbi->inactiveKey= key; xkbi->bounceKeysTimer= TimerSet(xkbi->bounceKeysTimer, 0, ctrls->debounce_delay, AccessXBounceKeyExpire, (pointer)keybd); } /* Don't transmit the KeyRelease if SlowKeys is turned on and * the user didn't hold the key long enough. We know we passed * the key if the down bit was set by CoreProcessKeyboadEvent. */ if (ctrls->enabled_ctrls & XkbSlowKeysMask) { xkbAccessXNotify ev; unsigned beep_type; ev.keycode= key; ev.slowKeysDelay= ctrls->slow_keys_delay; ev.debounceDelay= ctrls->debounce_delay; if (BitIsOn(keybd->key->down,key) | (xkbi->mouseKey == key)) { ev.detail= XkbAXN_SKRelease; beep_type= _BEEP_SLOW_RELEASE; } else { ev.detail= XkbAXN_SKReject; beep_type= _BEEP_SLOW_REJECT; ignoreKeyEvent = TRUE; } XkbSendAccessXNotify(keybd,&ev); if (XkbAX_NeedFeedback(ctrls,XkbAX_SKRejectFBMask)) { XkbDDXAccessXBeep(keybd,beep_type,XkbSlowKeysMask); } if (xkbi->slowKey==key) xkbi->slowKey= 0; } /* Stop Repeating if the user releases the key that is currently * repeating. */ if (xkbi->repeatKey==key) { xkbi->repeatKey= 0; } if ((ctrls->enabled_ctrls&XkbAccessXTimeoutMask)&&(ctrls->ax_timeout>0)) { xkbi->lastPtrEventTime= 0; xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0, ctrls->ax_timeout*1000, AccessXTimeoutExpire, (pointer)keybd); xkbi->krgTimerActive= _ALL_TIMEOUT_TIMER; } else if (xkbi->krgTimerActive!=_OFF_TIMER) { xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0, 0, NULL, NULL); xkbi->krgTimerActive= _OFF_TIMER; } /* Keep track of how many times the Shift key has been pressed. * If it has been pressed and released 5 times in a row, toggle * the state of StickyKeys. */ if ((!ignoreKeyEvent)&&(xkbi->shiftKeyCount)) { KeySym *pSym= XkbKeySymsPtr(xkbi->desc,key); if ((pSym[0]!=XK_Shift_L)&&(pSym[0]!=XK_Shift_R)) { xkbi->shiftKeyCount= 0; } else if (xkbi->shiftKeyCount>=5) { xkbControlsNotify cn; cn.keycode = key; cn.eventType = KeyPress; cn.requestMajor = 0; cn.requestMinor = 0; if (ctrls->enabled_ctrls & XkbStickyKeysMask) AccessXStickyKeysTurnOff(keybd,&cn); else AccessXStickyKeysTurnOn(keybd,&cn); xkbi->shiftKeyCount= 0; } } if (!ignoreKeyEvent) XkbProcessKeyboardEvent(xE,keybd,count); return ignoreKeyEvent; } /* AccessXFilterReleaseEvent */
Bool AccessXFilterPressEvent( register xEvent * xE, register DeviceIntPtr keybd, int count) { XkbSrvInfoPtr xkbi = keybd->key->xkbInfo; XkbControlsPtr ctrls = xkbi->desc->ctrls; Bool ignoreKeyEvent = FALSE; KeyCode key = xE->u.u.detail; KeySym * sym = XkbKeySymsPtr(xkbi->desc,key); if (ctrls->enabled_ctrls&XkbAccessXKeysMask) { /* check for magic sequences */ if ((sym[0]==XK_Shift_R)||(sym[0]==XK_Shift_L)) { if (XkbAX_NeedFeedback(ctrls,XkbAX_SlowWarnFBMask)) { xkbi->krgTimerActive = _KRG_WARN_TIMER; xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0, 4000, AccessXKRGExpire, (pointer)keybd); } else { xkbi->krgTimerActive = _KRG_TIMER; xkbi->krgTimer= TimerSet(xkbi->krgTimer, 0, 8000, AccessXKRGExpire, (pointer)keybd); } if (!(ctrls->enabled_ctrls & XkbSlowKeysMask)) { CARD32 now= GetTimeInMillis(); if ((now-xkbi->lastShiftEventTime)>15000) xkbi->shiftKeyCount= 1; else xkbi->shiftKeyCount++; xkbi->lastShiftEventTime= now; } } else { if (xkbi->krgTimerActive) { xkbi->krgTimer= TimerSet(xkbi->krgTimer,0, 0, NULL, NULL); xkbi->krgTimerActive= _OFF_TIMER; } } } /* Don't transmit the KeyPress if SlowKeys is turned on; * The wakeup handler will synthesize one for us if the user * has held the key long enough. */ if (ctrls->enabled_ctrls & XkbSlowKeysMask) { xkbAccessXNotify ev; /* If key was already pressed, ignore subsequent press events * from the server's autorepeat */ if(xkbi->slowKey == key) return TRUE; ev.detail= XkbAXN_SKPress; ev.keycode= key; ev.slowKeysDelay= ctrls->slow_keys_delay; ev.debounceDelay= ctrls->debounce_delay; XkbSendAccessXNotify(keybd,&ev); if (XkbAX_NeedFeedback(ctrls,XkbAX_SKPressFBMask)) XkbDDXAccessXBeep(keybd,_BEEP_SLOW_PRESS,XkbSlowKeysMask); xkbi->slowKey= key; xkbi->slowKeysTimer = TimerSet(xkbi->slowKeysTimer, 0, ctrls->slow_keys_delay, AccessXSlowKeyExpire, (pointer)keybd); ignoreKeyEvent = TRUE; } /* Don't transmit the KeyPress if BounceKeys is turned on * and the user pressed the same key within a given time period * from the last release. */ else if ((ctrls->enabled_ctrls & XkbBounceKeysMask) && (key == xkbi->inactiveKey)) { if (XkbAX_NeedFeedback(ctrls,XkbAX_BKRejectFBMask)) XkbDDXAccessXBeep(keybd,_BEEP_BOUNCE_REJECT,XkbBounceKeysMask); ignoreKeyEvent = TRUE; } /* Start repeating if necessary. Stop autorepeating if the user * presses a non-modifier key that doesn't autorepeat. */ if (XkbDDXUsesSoftRepeat(keybd)) { if ((keybd->kbdfeed->ctrl.autoRepeat) && ((ctrls->enabled_ctrls&(XkbSlowKeysMask|XkbRepeatKeysMask))== XkbRepeatKeysMask)) { if (BitIsOn(keybd->kbdfeed->ctrl.autoRepeats,key) && !keybd->key->modifierMap[key]) { #ifdef DEBUG if (xkbDebugFlags&0x10) ErrorF("Starting software autorepeat...\n"); #endif xkbi->repeatKey = key; xkbi->repeatKeyTimer= TimerSet(xkbi->repeatKeyTimer, 0, ctrls->repeat_delay, AccessXRepeatKeyExpire, (pointer)keybd); } } } /* Check for two keys being pressed at the same time. This section * essentially says the following: * * If StickyKeys is on, and a modifier is currently being held down, * and one of the following is true: the current key is not a modifier * or the currentKey is a modifier, but not the only modifier being * held down, turn StickyKeys off if the TwoKeys off ctrl is set. */ if ((ctrls->enabled_ctrls & XkbStickyKeysMask) && (xkbi->state.base_mods!=0) && (XkbAX_NeedOption(ctrls,XkbAX_TwoKeysMask))) { xkbControlsNotify cn; cn.keycode = key; cn.eventType = KeyPress; cn.requestMajor = 0; cn.requestMinor = 0; AccessXStickyKeysTurnOff(keybd,&cn); } if (!ignoreKeyEvent) XkbProcessKeyboardEvent(xE,keybd,count); return ignoreKeyEvent; } /* AccessXFilterPressEvent */
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); }