#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdio.h>
#include <math.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include <X11/keysym.h>
#include "exglobals.h"
#include <X11/extensions/XIproto.h>
#include "inputstr.h"
#include "eventstr.h"
#include <xkbsrv.h>
#if !defined(WIN32)
#include <sys/time.h>
#endif
int XkbDfltRepeatDelay= 660;
int XkbDfltRepeatInterval= 40;
#define DFLT_TIMEOUT_CTRLS (XkbAX_KRGMask|XkbStickyKeysMask|XkbMouseKeysMask)
#define DFLT_TIMEOUT_OPTS (XkbAX_IndicatorFBMask)
unsigned short XkbDfltAccessXTimeout= 120;
unsigned int XkbDfltAccessXTimeoutMask= DFLT_TIMEOUT_CTRLS;
static unsigned int XkbDfltAccessXTimeoutValues= 0;
static unsigned int XkbDfltAccessXTimeoutOptionsMask= DFLT_TIMEOUT_OPTS;
static unsigned int XkbDfltAccessXTimeoutOptionsValues= 0;
unsigned int XkbDfltAccessXFeedback= XkbAccessXFeedbackMask;
unsigned short XkbDfltAccessXOptions= XkbAX_AllOptionsMask & ~(XkbAX_IndicatorFBMask|XkbAX_SKReleaseFBMask|XkbAX_SKRejectFBMask);
void
AccessXComputeCurveFactor(XkbSrvInfoPtr xkbi,XkbControlsPtr ctrls)
{
xkbi->mouseKeysCurve= 1.0+(((double)ctrls->mk_curve)*0.001);
xkbi->mouseKeysCurveFactor= ( ((double)ctrls->mk_max_speed)/
pow((double)ctrls->mk_time_to_max,xkbi->mouseKeysCurve));
return;
}
void
AccessXInit(DeviceIntPtr keybd)
{
XkbSrvInfoPtr xkbi = keybd->key->xkbInfo;
XkbControlsPtr ctrls = xkbi->desc->ctrls;
xkbi->shiftKeyCount= 0;
xkbi->mouseKeysCounter= 0;
xkbi->inactiveKey= 0;
xkbi->slowKey= 0;
xkbi->repeatKey= 0;
xkbi->krgTimerActive= _OFF_TIMER;
xkbi->beepType= _BEEP_NONE;
xkbi->beepCount= 0;
xkbi->mouseKeyTimer= NULL;
xkbi->slowKeysTimer= NULL;
xkbi->bounceKeysTimer= NULL;
xkbi->repeatKeyTimer= NULL;
xkbi->krgTimer= NULL;
xkbi->beepTimer= NULL;
ctrls->repeat_delay = XkbDfltRepeatDelay;
ctrls->repeat_interval = XkbDfltRepeatInterval;
ctrls->debounce_delay = 300;
ctrls->slow_keys_delay = 300;
ctrls->mk_delay = 160;
ctrls->mk_interval = 40;
ctrls->mk_time_to_max = 30;
ctrls->mk_max_speed = 30;
ctrls->mk_curve = 500;
ctrls->mk_dflt_btn = 1;
ctrls->ax_timeout = XkbDfltAccessXTimeout;
ctrls->axt_ctrls_mask = XkbDfltAccessXTimeoutMask;
ctrls->axt_ctrls_values = XkbDfltAccessXTimeoutValues;
ctrls->axt_opts_mask = XkbDfltAccessXTimeoutOptionsMask;
ctrls->axt_opts_values = XkbDfltAccessXTimeoutOptionsValues;
if (XkbDfltAccessXTimeout)
ctrls->enabled_ctrls |= XkbAccessXTimeoutMask;
else
ctrls->enabled_ctrls &= ~XkbAccessXTimeoutMask;
ctrls->enabled_ctrls |= XkbDfltAccessXFeedback;
ctrls->ax_options = XkbDfltAccessXOptions;
AccessXComputeCurveFactor(xkbi,ctrls);
return;
}
static void
AccessXKeyboardEvent(DeviceIntPtr keybd,
int type,
BYTE keyCode,
Bool isRepeat)
{
DeviceEvent event;
memset(&event, 0, sizeof(DeviceEvent));
event.header = ET_Internal;
event.type = type;
event.detail.key = keyCode;
event.time = GetTimeInMillis();
event.length = sizeof(DeviceEvent);
event.key_repeat = isRepeat;
event.sourceid = keybd->id;
event.deviceid = keybd->id;
if (xkbDebugFlags&0x8) {
DebugF("[xkb] AXKE: Key %d %s\n", keyCode,
(event.type == ET_KeyPress ? "down" : "up"));
}
XkbProcessKeyboardEvent(&event, keybd);
return;
}
static void
AccessXKRGTurnOn(DeviceIntPtr dev,CARD16 KRGControl,xkbControlsNotify *pCN)
{
XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
XkbControlsPtr ctrls = xkbi->desc->ctrls;
XkbControlsRec old;
XkbEventCauseRec cause;
XkbSrvLedInfoPtr sli;
old= *ctrls;
ctrls->enabled_ctrls |= (KRGControl&XkbAX_KRGMask);
if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
XkbSendControlsNotify(dev,pCN);
cause.kc= pCN->keycode;
cause.event= pCN->eventType;
cause.mjr= pCN->requestMajor;
cause.mnr= pCN->requestMinor;
sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
XkbDDXAccessXBeep(dev,_BEEP_FEATURE_ON,KRGControl);
return;
}
static void
AccessXKRGTurnOff(DeviceIntPtr dev,xkbControlsNotify *pCN)
{
XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
XkbControlsPtr ctrls = xkbi->desc->ctrls;
XkbControlsRec old;
XkbEventCauseRec cause;
XkbSrvLedInfoPtr sli;
old = *ctrls;
ctrls->enabled_ctrls &= ~XkbAX_KRGMask;
if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
XkbSendControlsNotify(dev,pCN);
cause.kc= pCN->keycode;
cause.event= pCN->eventType;
cause.mjr= pCN->requestMajor;
cause.mnr= pCN->requestMinor;
sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) {
unsigned changes= old.enabled_ctrls^ctrls->enabled_ctrls;
XkbDDXAccessXBeep(dev,_BEEP_FEATURE_OFF,changes);
}
return;
}
static void
AccessXStickyKeysTurnOn(DeviceIntPtr dev,xkbControlsNotify *pCN)
{
XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
XkbControlsPtr ctrls = xkbi->desc->ctrls;
XkbControlsRec old;
XkbEventCauseRec cause;
XkbSrvLedInfoPtr sli;
old = *ctrls;
ctrls->enabled_ctrls |= XkbStickyKeysMask;
xkbi->shiftKeyCount = 0;
if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
XkbSendControlsNotify(dev,pCN);
cause.kc= pCN->keycode;
cause.event= pCN->eventType;
cause.mjr= pCN->requestMajor;
cause.mnr= pCN->requestMinor;
sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) {
XkbDDXAccessXBeep(dev,_BEEP_FEATURE_ON,XkbStickyKeysMask);
}
return;
}
static void
AccessXStickyKeysTurnOff(DeviceIntPtr dev,xkbControlsNotify *pCN)
{
XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
XkbControlsPtr ctrls = xkbi->desc->ctrls;
XkbControlsRec old;
XkbEventCauseRec cause;
XkbSrvLedInfoPtr sli;
old = *ctrls;
ctrls->enabled_ctrls &= ~XkbStickyKeysMask;
xkbi->shiftKeyCount = 0;
if (XkbComputeControlsNotify(dev,&old,ctrls,pCN,FALSE))
XkbSendControlsNotify(dev,pCN);
cause.kc= pCN->keycode;
cause.event= pCN->eventType;
cause.mjr= pCN->requestMajor;
cause.mnr= pCN->requestMinor;
sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) {
XkbDDXAccessXBeep(dev,_BEEP_FEATURE_OFF,XkbStickyKeysMask);
}
#ifndef NO_CLEAR_LATCHES_FOR_STICKY_KEYS_OFF
XkbClearAllLatchesAndLocks(dev,xkbi,FALSE,&cause);
#endif
return;
}
static CARD32
AccessXKRGExpire(OsTimerPtr timer,CARD32 now,pointer arg)
{
XkbSrvInfoPtr xkbi= ((DeviceIntPtr)arg)->key->xkbInfo;
xkbControlsNotify cn;
if (xkbi->krgTimerActive==_KRG_WARN_TIMER) {
XkbDDXAccessXBeep((DeviceIntPtr)arg,_BEEP_SLOW_WARN,XkbStickyKeysMask);
xkbi->krgTimerActive= _KRG_TIMER;
return 4000;
}
xkbi->krgTimerActive= _OFF_TIMER;
cn.keycode = 0;
cn.eventType = 0;
cn.requestMajor = 0;
cn.requestMinor = 0;
if (xkbi->desc->ctrls->enabled_ctrls&XkbSlowKeysMask)
AccessXKRGTurnOff((DeviceIntPtr)arg,&cn);
else AccessXKRGTurnOn((DeviceIntPtr)arg,XkbSlowKeysMask,&cn);
return 0;
}
static CARD32
AccessXRepeatKeyExpire(OsTimerPtr timer,CARD32 now,pointer arg)
{
DeviceIntPtr dev = (DeviceIntPtr) arg;
XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
if (xkbi->repeatKey == 0)
return 0;
AccessXKeyboardEvent(dev, ET_KeyPress, xkbi->repeatKey, TRUE);
return xkbi->desc->ctrls->repeat_interval;
}
void
AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi,KeyCode key)
{
if (xkbi->repeatKey==key)
xkbi->repeatKey= 0;
return;
}
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, ET_KeyPress,xkbi->slowKey,FALSE);
if ((ctrls->enabled_ctrls&XkbAccessXKeysMask) &&
((sym[0]==XK_Shift_R)||(sym[0]==XK_Shift_L)))
xkbi->shiftKeyCount++;
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;
}
static CARD32
AccessXBounceKeyExpire(OsTimerPtr timer,CARD32 now,pointer arg)
{
XkbSrvInfoPtr xkbi= ((DeviceIntPtr)arg)->key->xkbInfo;
xkbi->inactiveKey= 0;
return 0;
}
static CARD32
AccessXTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg)
{
DeviceIntPtr dev = (DeviceIntPtr)arg;
XkbSrvInfoPtr xkbi= dev->key->xkbInfo;
XkbControlsPtr ctrls= xkbi->desc->ctrls;
XkbControlsRec old;
xkbControlsNotify cn;
XkbEventCauseRec cause;
XkbSrvLedInfoPtr sli;
if (xkbi->lastPtrEventTime) {
unsigned timeToWait = (ctrls->ax_timeout*1000);
unsigned timeElapsed = (now-xkbi->lastPtrEventTime);
if (timeToWait > timeElapsed)
return timeToWait - timeElapsed;
}
old= *ctrls;
xkbi->shiftKeyCount= 0;
ctrls->enabled_ctrls&= ~ctrls->axt_ctrls_mask;
ctrls->enabled_ctrls|=
(ctrls->axt_ctrls_values&ctrls->axt_ctrls_mask);
if (ctrls->axt_opts_mask) {
ctrls->ax_options&= ~ctrls->axt_opts_mask;
ctrls->ax_options|= (ctrls->axt_opts_values&ctrls->axt_opts_mask);
}
if (XkbComputeControlsNotify(dev,&old,ctrls,&cn,FALSE)) {
cn.keycode = 0;
cn.eventType = 0;
cn.requestMajor = 0;
cn.requestMinor = 0;
XkbSendControlsNotify(dev,&cn);
}
XkbSetCauseUnknown(&cause);
sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(dev,sli->usesControls,TRUE,NULL,&cause);
if (ctrls->ax_options!=old.ax_options) {
unsigned set,cleared,bell;
set= ctrls->ax_options&(~old.ax_options);
cleared= (~ctrls->ax_options)&old.ax_options;
if (set && cleared) bell= _BEEP_FEATURE_CHANGE;
else if (set) bell= _BEEP_FEATURE_ON;
else bell= _BEEP_FEATURE_OFF;
XkbDDXAccessXBeep(dev,bell,XkbAccessXTimeoutMask);
}
xkbi->krgTimerActive= _OFF_TIMER;
return 0;
}
Bool
AccessXFilterPressEvent( DeviceEvent* event,
DeviceIntPtr keybd)
{
XkbSrvInfoPtr xkbi = keybd->key->xkbInfo;
XkbControlsPtr ctrls = xkbi->desc->ctrls;
Bool ignoreKeyEvent = FALSE;
KeyCode key = event->detail.key;
KeySym * sym = XkbKeySymsPtr(xkbi->desc,key);
if (ctrls->enabled_ctrls&XkbAccessXKeysMask) {
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;
}
}
}
if (ctrls->enabled_ctrls & XkbSlowKeysMask) {
xkbAccessXNotify ev;
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;
}
else if ((ctrls->enabled_ctrls & XkbBounceKeysMask) &&
(key == xkbi->inactiveKey)) {
if (XkbAX_NeedFeedback(ctrls,XkbAX_BKRejectFBMask))
XkbDDXAccessXBeep(keybd,_BEEP_BOUNCE_REJECT,XkbBounceKeysMask);
ignoreKeyEvent = TRUE;
}
if (XkbDDXUsesSoftRepeat(keybd)) {
if ((keybd->kbdfeed->ctrl.autoRepeat) &&
((ctrls->enabled_ctrls&(XkbSlowKeysMask|XkbRepeatKeysMask))==
XkbRepeatKeysMask)) {
if (BitIsOn(keybd->kbdfeed->ctrl.autoRepeats,key)) {
if (xkbDebugFlags&0x10)
DebugF("Starting software autorepeat...\n");
if (xkbi->repeatKey == key)
ignoreKeyEvent = TRUE;
else {
xkbi->repeatKey = key;
xkbi->repeatKeyTimer= TimerSet(xkbi->repeatKeyTimer,
0, ctrls->repeat_delay,
AccessXRepeatKeyExpire, (pointer)keybd);
}
}
}
}
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(event, keybd);
return ignoreKeyEvent;
}
Bool
AccessXFilterReleaseEvent( DeviceEvent* event,
DeviceIntPtr keybd)
{
XkbSrvInfoPtr xkbi = keybd->key->xkbInfo;
XkbControlsPtr ctrls = xkbi->desc->ctrls;
KeyCode key = event->detail.key;
Bool ignoreKeyEvent = FALSE;
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);
}
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;
}
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;
}
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(event, keybd);
return ignoreKeyEvent;
}
extern int xkbDevicePrivateIndex;
extern void xkbUnwrapProc(DeviceIntPtr, DeviceHandleProc, pointer);
void
ProcessPointerEvent( InternalEvent *ev,
DeviceIntPtr mouse)
{
DeviceIntPtr dev;
XkbSrvInfoPtr xkbi = NULL;
unsigned changed = 0;
ProcessInputProc backupproc;
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(mouse);
DeviceEvent *event = &ev->device_event;
dev = (IsMaster(mouse) || mouse->u.master) ? GetMaster(mouse, MASTER_KEYBOARD) : mouse;
if (dev && dev->key)
{
xkbi = dev->key->xkbInfo;
xkbi->shiftKeyCount = 0;
xkbi->lastPtrEventTime= event->time;
}
if (event->type == ET_ButtonPress) {
changed |= XkbPointerButtonMask;
}
else if (event->type == ET_ButtonRelease) {
if (xkbi) {
xkbi->lockedPtrButtons&= ~(1 << (event->detail.key & 0x7));
if (IsMaster(dev))
{
DeviceIntPtr source;
int rc;
rc = dixLookupDevice(&source, event->sourceid, serverClient, DixWriteAccess);
if (rc != Success)
ErrorF("[xkb] bad sourceid '%d' on button release event.\n", event->sourceid);
else if (!IsXTestDevice(source, GetMaster(dev, MASTER_POINTER)))
XkbFakeDeviceButton(dev, FALSE, event->detail.key);
}
}
changed |= XkbPointerButtonMask;
}
UNWRAP_PROCESS_INPUT_PROC(mouse, xkbPrivPtr, backupproc);
mouse->public.processInputProc(ev, mouse);
COND_WRAP_PROCESS_INPUT_PROC(mouse, xkbPrivPtr,
backupproc, xkbUnwrapProc);
if (!xkbi)
return;
xkbi->state.ptr_buttons = (mouse->button) ? mouse->button->state : 0;
if ( xkbi->state.latched_mods && (event->type == ET_ButtonRelease) ) {
unsigned changed_leds;
XkbStateRec oldState;
XkbSrvLedInfoPtr sli;
sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
oldState= xkbi->state;
XkbLatchModifiers(dev,0xFF,0x00);
XkbComputeDerivedState(xkbi);
changed |= XkbStateChangedFlags(&oldState,&xkbi->state);
if (changed&sli->usedComponents) {
changed_leds= XkbIndicatorsToUpdate(dev,changed,FALSE);
if (changed_leds) {
XkbEventCauseRec cause;
XkbSetCauseKey(&cause,(event->detail.key & 0x7), event->type);
XkbUpdateIndicators(dev,changed_leds,TRUE,NULL,&cause);
}
}
}
if (((xkbi->flags&_XkbStateNotifyInProgress)==0)&&(changed!=0)) {
xkbStateNotify sn;
sn.keycode= event->detail.key;
sn.eventType= event->type;
sn.requestMajor = sn.requestMinor = 0;
sn.changed= changed;
XkbSendStateNotify(dev,&sn);
}
}