428261197a
Tested by ajacoutot@, krw@, shadchin@ and jasper@ on various configurations including multihead with both zaphod and xrandr.
1442 lines
40 KiB
C
1442 lines
40 KiB
C
/************************************************************
|
|
Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
|
|
|
|
Permission to use, copy, modify, and distribute this
|
|
software and its documentation for any purpose and without
|
|
fee is hereby granted, provided that the above copyright
|
|
notice appear in all copies and that both that copyright
|
|
notice and this permission notice appear in supporting
|
|
documentation, and that the name of Silicon Graphics not be
|
|
used in advertising or publicity pertaining to distribution
|
|
of the software without specific prior written permission.
|
|
Silicon Graphics makes no representation about the suitability
|
|
of this software for any purpose. It is provided "as is"
|
|
without any express or implied warranty.
|
|
|
|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
|
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
|
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
|
|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
********************************************************/
|
|
|
|
#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 "misc.h"
|
|
#include "inputstr.h"
|
|
#include "exevents.h"
|
|
#include "eventstr.h"
|
|
#include <xkbsrv.h>
|
|
#include "xkb.h"
|
|
#include <ctype.h>
|
|
#include "mi.h"
|
|
#include "mipointer.h"
|
|
#define EXTENSION_EVENT_BASE 64
|
|
|
|
DevPrivateKeyRec xkbDevicePrivateKeyRec;
|
|
|
|
void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button);
|
|
static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y);
|
|
|
|
void
|
|
xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc,
|
|
pointer data)
|
|
{
|
|
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
|
|
ProcessInputProc backupproc;
|
|
if(xkbPrivPtr->unwrapProc)
|
|
xkbPrivPtr->unwrapProc = NULL;
|
|
|
|
UNWRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr, backupproc);
|
|
proc(device,data);
|
|
COND_WRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr,
|
|
backupproc,xkbUnwrapProc);
|
|
}
|
|
|
|
Bool
|
|
XkbInitPrivates(void)
|
|
{
|
|
return dixRegisterPrivateKey(&xkbDevicePrivateKeyRec, PRIVATE_DEVICE, 0);
|
|
}
|
|
|
|
void
|
|
XkbSetExtension(DeviceIntPtr device, ProcessInputProc proc)
|
|
{
|
|
xkbDeviceInfoPtr xkbPrivPtr;
|
|
|
|
xkbPrivPtr = (xkbDeviceInfoPtr) calloc(1, sizeof(xkbDeviceInfoRec));
|
|
if (!xkbPrivPtr)
|
|
return;
|
|
xkbPrivPtr->unwrapProc = NULL;
|
|
|
|
dixSetPrivate(&device->devPrivates, xkbDevicePrivateKey, xkbPrivPtr);
|
|
WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc);
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static XkbAction
|
|
_FixUpAction(XkbDescPtr xkb,XkbAction *act)
|
|
{
|
|
static XkbAction fake;
|
|
|
|
if (XkbIsPtrAction(act)&&(!(xkb->ctrls->enabled_ctrls&XkbMouseKeysMask))) {
|
|
fake.type = XkbSA_NoAction;
|
|
return fake;
|
|
}
|
|
if (xkb->ctrls->enabled_ctrls&XkbStickyKeysMask) {
|
|
if (act->any.type==XkbSA_SetMods) {
|
|
fake.mods.type = XkbSA_LatchMods;
|
|
fake.mods.mask = act->mods.mask;
|
|
if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask))
|
|
fake.mods.flags= XkbSA_ClearLocks|XkbSA_LatchToLock;
|
|
else fake.mods.flags= XkbSA_ClearLocks;
|
|
return fake;
|
|
}
|
|
if (act->any.type==XkbSA_SetGroup) {
|
|
fake.group.type = XkbSA_LatchGroup;
|
|
if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask))
|
|
fake.group.flags= XkbSA_ClearLocks|XkbSA_LatchToLock;
|
|
else fake.group.flags= XkbSA_ClearLocks;
|
|
XkbSASetGroup(&fake.group,XkbSAGroup(&act->group));
|
|
return fake;
|
|
}
|
|
}
|
|
return *act;
|
|
}
|
|
|
|
static XkbAction
|
|
XkbGetKeyAction(XkbSrvInfoPtr xkbi,XkbStatePtr xkbState,CARD8 key)
|
|
{
|
|
int effectiveGroup;
|
|
int col;
|
|
XkbDescPtr xkb;
|
|
XkbKeyTypePtr type;
|
|
XkbAction * pActs;
|
|
static XkbAction fake;
|
|
|
|
xkb= xkbi->desc;
|
|
if (!XkbKeyHasActions(xkb,key) || !XkbKeycodeInRange(xkb,key)) {
|
|
fake.type = XkbSA_NoAction;
|
|
return fake;
|
|
}
|
|
pActs= XkbKeyActionsPtr(xkb,key);
|
|
col= 0;
|
|
|
|
effectiveGroup = XkbGetEffectiveGroup(xkbi, xkbState, key);
|
|
if (effectiveGroup != XkbGroup1Index)
|
|
col += (effectiveGroup * XkbKeyGroupsWidth(xkb, key));
|
|
|
|
type= XkbKeyKeyType(xkb,key,effectiveGroup);
|
|
if (type->map!=NULL) {
|
|
register unsigned i,mods;
|
|
register XkbKTMapEntryPtr entry;
|
|
mods= xkbState->mods&type->mods.mask;
|
|
for (entry= type->map,i=0;i<type->map_count;i++,entry++) {
|
|
if ((entry->active)&&(entry->mods.mask==mods)) {
|
|
col+= entry->level;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (pActs[col].any.type==XkbSA_NoAction)
|
|
return pActs[col];
|
|
fake= _FixUpAction(xkb,&pActs[col]);
|
|
return fake;
|
|
}
|
|
|
|
static XkbAction
|
|
XkbGetButtonAction(DeviceIntPtr kbd,DeviceIntPtr dev,int button)
|
|
{
|
|
XkbAction fake;
|
|
if ((dev->button)&&(dev->button->xkb_acts)) {
|
|
if (dev->button->xkb_acts[button-1].any.type!=XkbSA_NoAction) {
|
|
fake= _FixUpAction(kbd->key->xkbInfo->desc,
|
|
&dev->button->xkb_acts[button-1]);
|
|
return fake;
|
|
}
|
|
}
|
|
fake.any.type= XkbSA_NoAction;
|
|
return fake;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
#define SYNTHETIC_KEYCODE 1
|
|
#define BTN_ACT_FLAG 0x100
|
|
|
|
static int
|
|
_XkbFilterSetState( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction *pAction)
|
|
{
|
|
if (filter->keycode==0) { /* initial press */
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = ((pAction->mods.mask&XkbSA_ClearLocks)!=0);
|
|
filter->priv = 0;
|
|
filter->filter = _XkbFilterSetState;
|
|
if (pAction->type==XkbSA_SetMods) {
|
|
filter->upAction = *pAction;
|
|
xkbi->setMods= pAction->mods.mask;
|
|
}
|
|
else {
|
|
xkbi->groupChange = XkbSAGroup(&pAction->group);
|
|
if (pAction->group.flags&XkbSA_GroupAbsolute)
|
|
xkbi->groupChange-= xkbi->state.base_group;
|
|
filter->upAction= *pAction;
|
|
XkbSASetGroup(&filter->upAction.group,xkbi->groupChange);
|
|
}
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
if (filter->upAction.type==XkbSA_SetMods) {
|
|
xkbi->clearMods = filter->upAction.mods.mask;
|
|
if (filter->upAction.mods.flags&XkbSA_ClearLocks) {
|
|
xkbi->state.locked_mods&= ~filter->upAction.mods.mask;
|
|
}
|
|
}
|
|
else {
|
|
if (filter->upAction.group.flags&XkbSA_ClearLocks) {
|
|
xkbi->state.locked_group = 0;
|
|
}
|
|
xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
|
|
}
|
|
filter->active = 0;
|
|
}
|
|
else {
|
|
filter->upAction.mods.flags&= ~XkbSA_ClearLocks;
|
|
filter->filterOthers = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#define LATCH_KEY_DOWN 1
|
|
#define LATCH_PENDING 2
|
|
#define NO_LATCH 3
|
|
|
|
static int
|
|
_XkbFilterLatchState( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
|
|
if (filter->keycode==0) { /* initial press */
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 1;
|
|
filter->priv = LATCH_KEY_DOWN;
|
|
filter->filter = _XkbFilterLatchState;
|
|
if (pAction->type==XkbSA_LatchMods) {
|
|
filter->upAction = *pAction;
|
|
xkbi->setMods = pAction->mods.mask;
|
|
}
|
|
else {
|
|
xkbi->groupChange = XkbSAGroup(&pAction->group);
|
|
if (pAction->group.flags&XkbSA_GroupAbsolute)
|
|
xkbi->groupChange-= xkbi->state.base_group;
|
|
filter->upAction= *pAction;
|
|
XkbSASetGroup(&filter->upAction.group,xkbi->groupChange);
|
|
}
|
|
}
|
|
else if ( pAction && (filter->priv==LATCH_PENDING) ) {
|
|
if (((1<<pAction->type)&XkbSA_BreakLatch)!=0) {
|
|
filter->active = 0;
|
|
if (filter->upAction.type==XkbSA_LatchMods)
|
|
xkbi->state.latched_mods&= ~filter->upAction.mods.mask;
|
|
else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group);
|
|
}
|
|
else if ((pAction->type==filter->upAction.type)&&
|
|
(pAction->mods.flags==filter->upAction.mods.flags)&&
|
|
(pAction->mods.mask==filter->upAction.mods.mask)) {
|
|
if (filter->upAction.mods.flags&XkbSA_LatchToLock) {
|
|
XkbControlsPtr ctrls= xkbi->desc->ctrls;
|
|
if (filter->upAction.type==XkbSA_LatchMods)
|
|
pAction->mods.type= XkbSA_LockMods;
|
|
else pAction->group.type= XkbSA_LockGroup;
|
|
if (XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask)&&
|
|
(ctrls->enabled_ctrls&XkbStickyKeysMask)) {
|
|
XkbDDXAccessXBeep(xkbi->device,_BEEP_STICKY_LOCK,
|
|
XkbStickyKeysMask);
|
|
}
|
|
}
|
|
else {
|
|
if (filter->upAction.type==XkbSA_LatchMods)
|
|
pAction->mods.type= XkbSA_SetMods;
|
|
else pAction->group.type= XkbSA_SetGroup;
|
|
}
|
|
if (filter->upAction.type==XkbSA_LatchMods)
|
|
xkbi->state.latched_mods&= ~filter->upAction.mods.mask;
|
|
else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group);
|
|
filter->active = 0;
|
|
}
|
|
}
|
|
else if (filter->keycode==keycode) { /* release */
|
|
XkbControlsPtr ctrls= xkbi->desc->ctrls;
|
|
int needBeep;
|
|
int beepType= _BEEP_NONE;
|
|
|
|
needBeep= ((ctrls->enabled_ctrls&XkbStickyKeysMask)&&
|
|
XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask));
|
|
if (filter->upAction.type==XkbSA_LatchMods) {
|
|
xkbi->clearMods = filter->upAction.mods.mask;
|
|
if ((filter->upAction.mods.flags&XkbSA_ClearLocks)&&
|
|
(xkbi->clearMods&xkbi->state.locked_mods)==xkbi->clearMods) {
|
|
xkbi->state.locked_mods&= ~xkbi->clearMods;
|
|
filter->priv= NO_LATCH;
|
|
beepType= _BEEP_STICKY_UNLOCK;
|
|
}
|
|
}
|
|
else {
|
|
xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
|
|
if ((filter->upAction.group.flags&XkbSA_ClearLocks)&&
|
|
(xkbi->state.locked_group)) {
|
|
xkbi->state.locked_group = 0;
|
|
filter->priv = NO_LATCH;
|
|
beepType= _BEEP_STICKY_UNLOCK;
|
|
}
|
|
}
|
|
if (filter->priv==NO_LATCH) {
|
|
filter->active= 0;
|
|
}
|
|
else {
|
|
filter->priv= LATCH_PENDING;
|
|
if (filter->upAction.type==XkbSA_LatchMods) {
|
|
xkbi->state.latched_mods |= filter->upAction.mods.mask;
|
|
needBeep = xkbi->state.latched_mods ? needBeep : 0;
|
|
xkbi->state.latched_mods |= filter->upAction.mods.mask;
|
|
}
|
|
else {
|
|
xkbi->state.latched_group+= XkbSAGroup(&filter->upAction.group);
|
|
}
|
|
if (needBeep && (beepType==_BEEP_NONE))
|
|
beepType= _BEEP_STICKY_LATCH;
|
|
}
|
|
if (needBeep && (beepType!=_BEEP_NONE))
|
|
XkbDDXAccessXBeep(xkbi->device,beepType,XkbStickyKeysMask);
|
|
}
|
|
else if (filter->priv==LATCH_KEY_DOWN) {
|
|
filter->priv= NO_LATCH;
|
|
filter->filterOthers = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterLockState( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
if (pAction&&(pAction->type==XkbSA_LockGroup)) {
|
|
if (pAction->group.flags&XkbSA_GroupAbsolute)
|
|
xkbi->state.locked_group= XkbSAGroup(&pAction->group);
|
|
else xkbi->state.locked_group+= XkbSAGroup(&pAction->group);
|
|
return 1;
|
|
}
|
|
if (filter->keycode==0) { /* initial press */
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->priv = 0;
|
|
filter->filter = _XkbFilterLockState;
|
|
filter->upAction = *pAction;
|
|
xkbi->state.locked_mods^= pAction->mods.mask;
|
|
xkbi->setMods = pAction->mods.mask;
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
filter->active = 0;
|
|
xkbi->clearMods = filter->upAction.mods.mask;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#define ISO_KEY_DOWN 0
|
|
#define NO_ISO_LOCK 1
|
|
|
|
static int
|
|
_XkbFilterISOLock( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
|
|
if (filter->keycode==0) { /* initial press */
|
|
CARD8 flags= pAction->iso.flags;
|
|
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 1;
|
|
filter->priv = ISO_KEY_DOWN;
|
|
filter->upAction = *pAction;
|
|
filter->filter = _XkbFilterISOLock;
|
|
if (flags&XkbSA_ISODfltIsGroup) {
|
|
xkbi->groupChange = XkbSAGroup(&pAction->iso);
|
|
xkbi->setMods = 0;
|
|
}
|
|
else {
|
|
xkbi->setMods = pAction->iso.mask;
|
|
xkbi->groupChange = 0;
|
|
}
|
|
if ((!(flags&XkbSA_ISONoAffectMods))&&(xkbi->state.base_mods)) {
|
|
filter->priv= NO_ISO_LOCK;
|
|
xkbi->state.locked_mods^= xkbi->state.base_mods;
|
|
}
|
|
if ((!(flags&XkbSA_ISONoAffectGroup))&&(xkbi->state.base_group)) {
|
|
/* 6/22/93 (ef) -- lock groups if group key is down first */
|
|
}
|
|
if (!(flags&XkbSA_ISONoAffectPtr)) {
|
|
/* 6/22/93 (ef) -- lock mouse buttons if they're down */
|
|
}
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
CARD8 flags= filter->upAction.iso.flags;
|
|
|
|
if (flags&XkbSA_ISODfltIsGroup) {
|
|
xkbi->groupChange = -XkbSAGroup(&filter->upAction.iso);
|
|
xkbi->clearMods = 0;
|
|
if (filter->priv==ISO_KEY_DOWN)
|
|
xkbi->state.locked_group+= XkbSAGroup(&filter->upAction.iso);
|
|
}
|
|
else {
|
|
xkbi->clearMods= filter->upAction.iso.mask;
|
|
xkbi->groupChange= 0;
|
|
if (filter->priv==ISO_KEY_DOWN)
|
|
xkbi->state.locked_mods^= filter->upAction.iso.mask;
|
|
}
|
|
filter->active = 0;
|
|
}
|
|
else if (pAction) {
|
|
CARD8 flags= filter->upAction.iso.flags;
|
|
|
|
switch (pAction->type) {
|
|
case XkbSA_SetMods: case XkbSA_LatchMods:
|
|
if (!(flags&XkbSA_ISONoAffectMods)) {
|
|
pAction->type= XkbSA_LockMods;
|
|
filter->priv= NO_ISO_LOCK;
|
|
}
|
|
break;
|
|
case XkbSA_SetGroup: case XkbSA_LatchGroup:
|
|
if (!(flags&XkbSA_ISONoAffectGroup)) {
|
|
pAction->type= XkbSA_LockGroup;
|
|
filter->priv= NO_ISO_LOCK;
|
|
}
|
|
break;
|
|
case XkbSA_PtrBtn:
|
|
if (!(flags&XkbSA_ISONoAffectPtr)) {
|
|
pAction->type= XkbSA_LockPtrBtn;
|
|
filter->priv= NO_ISO_LOCK;
|
|
}
|
|
break;
|
|
case XkbSA_SetControls:
|
|
if (!(flags&XkbSA_ISONoAffectCtrls)) {
|
|
pAction->type= XkbSA_LockControls;
|
|
filter->priv= NO_ISO_LOCK;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static CARD32
|
|
_XkbPtrAccelExpire(OsTimerPtr timer,CARD32 now,pointer arg)
|
|
{
|
|
XkbSrvInfoPtr xkbi= (XkbSrvInfoPtr)arg;
|
|
XkbControlsPtr ctrls= xkbi->desc->ctrls;
|
|
int dx,dy;
|
|
|
|
if (xkbi->mouseKey==0)
|
|
return 0;
|
|
|
|
if (xkbi->mouseKeysAccel) {
|
|
if ((xkbi->mouseKeysCounter)<ctrls->mk_time_to_max) {
|
|
double step;
|
|
xkbi->mouseKeysCounter++;
|
|
step= xkbi->mouseKeysCurveFactor*
|
|
pow((double)xkbi->mouseKeysCounter,xkbi->mouseKeysCurve);
|
|
if (xkbi->mouseKeysDX<0)
|
|
dx= floor( ((double)xkbi->mouseKeysDX)*step );
|
|
else dx= ceil( ((double)xkbi->mouseKeysDX)*step );
|
|
if (xkbi->mouseKeysDY<0)
|
|
dy= floor( ((double)xkbi->mouseKeysDY)*step );
|
|
else dy= ceil( ((double)xkbi->mouseKeysDY)*step );
|
|
}
|
|
else {
|
|
dx= xkbi->mouseKeysDX*ctrls->mk_max_speed;
|
|
dy= xkbi->mouseKeysDY*ctrls->mk_max_speed;
|
|
}
|
|
if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteX)
|
|
dx= xkbi->mouseKeysDX;
|
|
if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteY)
|
|
dy= xkbi->mouseKeysDY;
|
|
}
|
|
else {
|
|
dx= xkbi->mouseKeysDX;
|
|
dy= xkbi->mouseKeysDY;
|
|
}
|
|
XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy);
|
|
return xkbi->desc->ctrls->mk_interval;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterPointerMove( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
int x,y;
|
|
Bool accel;
|
|
|
|
if (filter->keycode==0) { /* initial press */
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->priv=0;
|
|
filter->filter = _XkbFilterPointerMove;
|
|
filter->upAction= *pAction;
|
|
xkbi->mouseKeysCounter= 0;
|
|
xkbi->mouseKey= keycode;
|
|
accel= ((pAction->ptr.flags&XkbSA_NoAcceleration)==0);
|
|
x= XkbPtrActionX(&pAction->ptr);
|
|
y= XkbPtrActionY(&pAction->ptr);
|
|
XkbFakePointerMotion(xkbi->device, pAction->ptr.flags,x,y);
|
|
AccessXCancelRepeatKey(xkbi,keycode);
|
|
xkbi->mouseKeysAccel= accel&&
|
|
(xkbi->desc->ctrls->enabled_ctrls&XkbMouseKeysAccelMask);
|
|
xkbi->mouseKeysFlags= pAction->ptr.flags;
|
|
xkbi->mouseKeysDX= XkbPtrActionX(&pAction->ptr);
|
|
xkbi->mouseKeysDY= XkbPtrActionY(&pAction->ptr);
|
|
xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0,
|
|
xkbi->desc->ctrls->mk_delay,
|
|
_XkbPtrAccelExpire,(pointer)xkbi);
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
filter->active = 0;
|
|
if (xkbi->mouseKey==keycode) {
|
|
xkbi->mouseKey= 0;
|
|
xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, 0,
|
|
NULL, NULL);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterPointerBtn( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
if (filter->keycode==0) { /* initial press */
|
|
int button= pAction->btn.button;
|
|
|
|
if (button==XkbSA_UseDfltButton)
|
|
button = xkbi->desc->ctrls->mk_dflt_btn;
|
|
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->priv=0;
|
|
filter->filter = _XkbFilterPointerBtn;
|
|
filter->upAction= *pAction;
|
|
filter->upAction.btn.button= button;
|
|
switch (pAction->type) {
|
|
case XkbSA_LockPtrBtn:
|
|
if (((xkbi->lockedPtrButtons&(1<<button))==0)&&
|
|
((pAction->btn.flags&XkbSA_LockNoLock)==0)) {
|
|
xkbi->lockedPtrButtons|= (1<<button);
|
|
AccessXCancelRepeatKey(xkbi,keycode);
|
|
XkbFakeDeviceButton(xkbi->device, 1, button);
|
|
filter->upAction.type= XkbSA_NoAction;
|
|
}
|
|
break;
|
|
case XkbSA_PtrBtn:
|
|
{
|
|
register int i,nClicks;
|
|
AccessXCancelRepeatKey(xkbi,keycode);
|
|
if (pAction->btn.count>0) {
|
|
nClicks= pAction->btn.count;
|
|
for (i=0;i<nClicks;i++) {
|
|
XkbFakeDeviceButton(xkbi->device, 1, button);
|
|
XkbFakeDeviceButton(xkbi->device, 0, button);
|
|
}
|
|
filter->upAction.type= XkbSA_NoAction;
|
|
}
|
|
else XkbFakeDeviceButton(xkbi->device, 1, button);
|
|
}
|
|
break;
|
|
case XkbSA_SetPtrDflt:
|
|
{
|
|
XkbControlsPtr ctrls= xkbi->desc->ctrls;
|
|
XkbControlsRec old;
|
|
xkbControlsNotify cn;
|
|
|
|
old= *ctrls;
|
|
AccessXCancelRepeatKey(xkbi,keycode);
|
|
switch (pAction->dflt.affect) {
|
|
case XkbSA_AffectDfltBtn:
|
|
if (pAction->dflt.flags&XkbSA_DfltBtnAbsolute)
|
|
ctrls->mk_dflt_btn=
|
|
XkbSAPtrDfltValue(&pAction->dflt);
|
|
else {
|
|
ctrls->mk_dflt_btn+=
|
|
XkbSAPtrDfltValue(&pAction->dflt);
|
|
if (ctrls->mk_dflt_btn>5)
|
|
ctrls->mk_dflt_btn= 5;
|
|
else if (ctrls->mk_dflt_btn<1)
|
|
ctrls->mk_dflt_btn= 1;
|
|
}
|
|
break;
|
|
default:
|
|
ErrorF(
|
|
"Attempt to change unknown pointer default (%d) ignored\n",
|
|
pAction->dflt.affect);
|
|
break;
|
|
}
|
|
if (XkbComputeControlsNotify(xkbi->device,
|
|
&old,xkbi->desc->ctrls,
|
|
&cn,FALSE)) {
|
|
cn.keycode = keycode;
|
|
/* XXX: what about DeviceKeyPress? */
|
|
cn.eventType = KeyPress;
|
|
cn.requestMajor = 0;
|
|
cn.requestMinor = 0;
|
|
XkbSendControlsNotify(xkbi->device,&cn);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
int button= filter->upAction.btn.button;
|
|
|
|
switch (filter->upAction.type) {
|
|
case XkbSA_LockPtrBtn:
|
|
if (((filter->upAction.btn.flags&XkbSA_LockNoUnlock)!=0)||
|
|
((xkbi->lockedPtrButtons&(1<<button))==0)) {
|
|
break;
|
|
}
|
|
xkbi->lockedPtrButtons&= ~(1<<button);
|
|
|
|
if (IsMaster(xkbi->device))
|
|
{
|
|
XkbMergeLockedPtrBtns(xkbi->device);
|
|
/* One SD still has lock set, don't post event */
|
|
if ((xkbi->lockedPtrButtons & (1 << button)) != 0)
|
|
break;
|
|
}
|
|
|
|
/* fallthrough */
|
|
case XkbSA_PtrBtn:
|
|
XkbFakeDeviceButton(xkbi->device, 0, button);
|
|
break;
|
|
}
|
|
filter->active = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterControls( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
XkbControlsRec old;
|
|
XkbControlsPtr ctrls;
|
|
DeviceIntPtr kbd;
|
|
unsigned int change;
|
|
XkbEventCauseRec cause;
|
|
|
|
kbd= xkbi->device;
|
|
ctrls= xkbi->desc->ctrls;
|
|
old= *ctrls;
|
|
if (filter->keycode==0) { /* initial press */
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
change= XkbActionCtrls(&pAction->ctrls);
|
|
filter->priv = change;
|
|
filter->filter = _XkbFilterControls;
|
|
filter->upAction = *pAction;
|
|
|
|
if (pAction->type==XkbSA_LockControls) {
|
|
filter->priv= (ctrls->enabled_ctrls&change);
|
|
change&= ~ctrls->enabled_ctrls;
|
|
}
|
|
|
|
if (change) {
|
|
xkbControlsNotify cn;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
ctrls->enabled_ctrls|= change;
|
|
if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) {
|
|
cn.keycode = keycode;
|
|
/* XXX: what about DeviceKeyPress? */
|
|
cn.eventType = KeyPress;
|
|
cn.requestMajor = 0;
|
|
cn.requestMinor = 0;
|
|
XkbSendControlsNotify(kbd,&cn);
|
|
}
|
|
|
|
XkbSetCauseKey(&cause,keycode,KeyPress);
|
|
|
|
/* If sticky keys were disabled, clear all locks and latches */
|
|
if ((old.enabled_ctrls&XkbStickyKeysMask)&&
|
|
(!(ctrls->enabled_ctrls&XkbStickyKeysMask))) {
|
|
XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause);
|
|
}
|
|
sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0);
|
|
XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause);
|
|
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
|
|
XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_ON,change);
|
|
}
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
change= filter->priv;
|
|
if (change) {
|
|
xkbControlsNotify cn;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
ctrls->enabled_ctrls&= ~change;
|
|
if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) {
|
|
cn.keycode = keycode;
|
|
cn.eventType = KeyRelease;
|
|
cn.requestMajor = 0;
|
|
cn.requestMinor = 0;
|
|
XkbSendControlsNotify(kbd,&cn);
|
|
}
|
|
|
|
XkbSetCauseKey(&cause,keycode,KeyRelease);
|
|
/* If sticky keys were disabled, clear all locks and latches */
|
|
if ((old.enabled_ctrls&XkbStickyKeysMask)&&
|
|
(!(ctrls->enabled_ctrls&XkbStickyKeysMask))) {
|
|
XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause);
|
|
}
|
|
sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0);
|
|
XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause);
|
|
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
|
|
XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_OFF,change);
|
|
}
|
|
filter->keycode= 0;
|
|
filter->active= 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterActionMessage(XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
XkbMessageAction * pMsg;
|
|
DeviceIntPtr kbd;
|
|
|
|
kbd= xkbi->device;
|
|
if (filter->keycode==0) { /* initial press */
|
|
pMsg= &pAction->msg;
|
|
if ((pMsg->flags&XkbSA_MessageOnRelease)||
|
|
((pMsg->flags&XkbSA_MessageGenKeyEvent)==0)) {
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->priv = 0;
|
|
filter->filter = _XkbFilterActionMessage;
|
|
filter->upAction = *pAction;
|
|
}
|
|
if (pMsg->flags&XkbSA_MessageOnPress) {
|
|
xkbActionMessage msg;
|
|
|
|
msg.keycode= keycode;
|
|
msg.press= 1;
|
|
msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
|
|
memcpy((char *)msg.message,
|
|
(char *)pMsg->message,XkbActionMessageLength);
|
|
XkbSendActionMessage(kbd,&msg);
|
|
}
|
|
return ((pAction->msg.flags&XkbSA_MessageGenKeyEvent)!=0);
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
pMsg= &filter->upAction.msg;
|
|
if (pMsg->flags&XkbSA_MessageOnRelease) {
|
|
xkbActionMessage msg;
|
|
|
|
msg.keycode= keycode;
|
|
msg.press= 0;
|
|
msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
|
|
memcpy((char *)msg.message,(char *)pMsg->message,
|
|
XkbActionMessageLength);
|
|
XkbSendActionMessage(kbd,&msg);
|
|
}
|
|
filter->keycode= 0;
|
|
filter->active= 0;
|
|
return ((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterRedirectKey( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
DeviceEvent ev;
|
|
int x,y;
|
|
XkbStateRec old;
|
|
unsigned mods,mask;
|
|
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device);
|
|
ProcessInputProc backupproc;
|
|
|
|
/* never actually used uninitialised, but gcc isn't smart enough
|
|
* to work that out. */
|
|
memset(&old, 0, sizeof(old));
|
|
memset(&ev, 0, sizeof(ev));
|
|
|
|
if ((filter->keycode!=0)&&(filter->keycode!=keycode))
|
|
return 1;
|
|
|
|
GetSpritePosition(xkbi->device, &x,&y);
|
|
ev.header = ET_Internal;
|
|
ev.length = sizeof(DeviceEvent);
|
|
ev.time = GetTimeInMillis();
|
|
ev.root_x = x;
|
|
ev.root_y = y;
|
|
|
|
if (filter->keycode==0) { /* initial press */
|
|
if ((pAction->redirect.new_key<xkbi->desc->min_key_code)||
|
|
(pAction->redirect.new_key>xkbi->desc->max_key_code)) {
|
|
return 1;
|
|
}
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->priv = 0;
|
|
filter->filter = _XkbFilterRedirectKey;
|
|
filter->upAction = *pAction;
|
|
|
|
ev.type = ET_KeyPress;
|
|
ev.detail.key = pAction->redirect.new_key;
|
|
|
|
mask= XkbSARedirectVModsMask(&pAction->redirect);
|
|
mods= XkbSARedirectVMods(&pAction->redirect);
|
|
if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask);
|
|
if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods);
|
|
mask|= pAction->redirect.mods_mask;
|
|
mods|= pAction->redirect.mods;
|
|
|
|
if ( mask || mods ) {
|
|
old= xkbi->state;
|
|
xkbi->state.base_mods&= ~mask;
|
|
xkbi->state.base_mods|= (mods&mask);
|
|
xkbi->state.latched_mods&= ~mask;
|
|
xkbi->state.latched_mods|= (mods&mask);
|
|
xkbi->state.locked_mods&= ~mask;
|
|
xkbi->state.locked_mods|= (mods&mask);
|
|
XkbComputeDerivedState(xkbi);
|
|
}
|
|
|
|
UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
|
|
xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
|
|
COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
|
|
backupproc,xkbUnwrapProc);
|
|
|
|
if ( mask || mods )
|
|
xkbi->state= old;
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
|
|
ev.type = ET_KeyRelease;
|
|
ev.detail.key = filter->upAction.redirect.new_key;
|
|
|
|
mask= XkbSARedirectVModsMask(&filter->upAction.redirect);
|
|
mods= XkbSARedirectVMods(&filter->upAction.redirect);
|
|
if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask);
|
|
if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods);
|
|
mask|= filter->upAction.redirect.mods_mask;
|
|
mods|= filter->upAction.redirect.mods;
|
|
|
|
if ( mask || mods ) {
|
|
old= xkbi->state;
|
|
xkbi->state.base_mods&= ~mask;
|
|
xkbi->state.base_mods|= (mods&mask);
|
|
xkbi->state.latched_mods&= ~mask;
|
|
xkbi->state.latched_mods|= (mods&mask);
|
|
xkbi->state.locked_mods&= ~mask;
|
|
xkbi->state.locked_mods|= (mods&mask);
|
|
XkbComputeDerivedState(xkbi);
|
|
}
|
|
|
|
UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
|
|
xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
|
|
COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
|
|
backupproc,xkbUnwrapProc);
|
|
|
|
if ( mask || mods )
|
|
xkbi->state= old;
|
|
|
|
filter->keycode= 0;
|
|
filter->active= 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterSwitchScreen( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
DeviceIntPtr dev = xkbi->device;
|
|
if (dev == inputInfo.keyboard)
|
|
return 0;
|
|
|
|
if (filter->keycode==0) { /* initial press */
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->filter = _XkbFilterSwitchScreen;
|
|
AccessXCancelRepeatKey(xkbi, keycode);
|
|
XkbDDXSwitchScreen(dev,keycode,pAction);
|
|
return 0;
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
filter->active= 0;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_XkbFilterXF86Private( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
DeviceIntPtr dev = xkbi->device;
|
|
if (dev == inputInfo.keyboard)
|
|
return 0;
|
|
|
|
if (filter->keycode==0) { /* initial press */
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->filter = _XkbFilterXF86Private;
|
|
XkbDDXPrivate(dev,keycode,pAction);
|
|
return 0;
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
filter->active= 0;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
_XkbFilterDeviceBtn( XkbSrvInfoPtr xkbi,
|
|
XkbFilterPtr filter,
|
|
unsigned keycode,
|
|
XkbAction * pAction)
|
|
{
|
|
DeviceIntPtr dev;
|
|
int button;
|
|
|
|
if (xkbi->device == inputInfo.keyboard)
|
|
return 0;
|
|
|
|
if (filter->keycode==0) { /* initial press */
|
|
_XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient,
|
|
DixUnknownAccess, &button);
|
|
if (!dev || !dev->public.on)
|
|
return 1;
|
|
|
|
button= pAction->devbtn.button;
|
|
if ((button<1)||(button>dev->button->numButtons))
|
|
return 1;
|
|
|
|
filter->keycode = keycode;
|
|
filter->active = 1;
|
|
filter->filterOthers = 0;
|
|
filter->priv=0;
|
|
filter->filter = _XkbFilterDeviceBtn;
|
|
filter->upAction= *pAction;
|
|
switch (pAction->type) {
|
|
case XkbSA_LockDeviceBtn:
|
|
if ((pAction->devbtn.flags&XkbSA_LockNoLock)||
|
|
BitIsOn(dev->button->down, button))
|
|
return 0;
|
|
XkbFakeDeviceButton(dev,TRUE,button);
|
|
filter->upAction.type= XkbSA_NoAction;
|
|
break;
|
|
case XkbSA_DeviceBtn:
|
|
if (pAction->devbtn.count>0) {
|
|
int nClicks,i;
|
|
nClicks= pAction->btn.count;
|
|
for (i=0;i<nClicks;i++) {
|
|
XkbFakeDeviceButton(dev,TRUE,button);
|
|
XkbFakeDeviceButton(dev,FALSE,button);
|
|
}
|
|
filter->upAction.type= XkbSA_NoAction;
|
|
}
|
|
else XkbFakeDeviceButton(dev,TRUE,button);
|
|
break;
|
|
}
|
|
}
|
|
else if (filter->keycode==keycode) {
|
|
int button;
|
|
|
|
filter->active= 0;
|
|
_XkbLookupButtonDevice(&dev, filter->upAction.devbtn.device,
|
|
serverClient, DixUnknownAccess, &button);
|
|
if (!dev || !dev->public.on)
|
|
return 1;
|
|
|
|
button= filter->upAction.btn.button;
|
|
switch (filter->upAction.type) {
|
|
case XkbSA_LockDeviceBtn:
|
|
if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)||
|
|
!BitIsOn(dev->button->down, button))
|
|
return 0;
|
|
XkbFakeDeviceButton(dev,FALSE,button);
|
|
break;
|
|
case XkbSA_DeviceBtn:
|
|
XkbFakeDeviceButton(dev,FALSE,button);
|
|
break;
|
|
}
|
|
filter->active = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static XkbFilterPtr
|
|
_XkbNextFreeFilter(
|
|
XkbSrvInfoPtr xkbi
|
|
)
|
|
{
|
|
register int i;
|
|
|
|
if (xkbi->szFilters==0) {
|
|
xkbi->szFilters = 4;
|
|
xkbi->filters = calloc(xkbi->szFilters, sizeof(XkbFilterRec));
|
|
/* 6/21/93 (ef) -- XXX! deal with allocation failure */
|
|
}
|
|
for (i=0;i<xkbi->szFilters;i++) {
|
|
if (!xkbi->filters[i].active) {
|
|
xkbi->filters[i].keycode = 0;
|
|
return &xkbi->filters[i];
|
|
}
|
|
}
|
|
xkbi->szFilters*=2;
|
|
xkbi->filters= realloc(xkbi->filters,
|
|
xkbi->szFilters * sizeof(XkbFilterRec));
|
|
/* 6/21/93 (ef) -- XXX! deal with allocation failure */
|
|
memset(&xkbi->filters[xkbi->szFilters/2], 0,
|
|
(xkbi->szFilters/2)*sizeof(XkbFilterRec));
|
|
return &xkbi->filters[xkbi->szFilters/2];
|
|
}
|
|
|
|
static int
|
|
_XkbApplyFilters(XkbSrvInfoPtr xkbi,unsigned kc,XkbAction *pAction)
|
|
{
|
|
register int i,send;
|
|
|
|
send= 1;
|
|
for (i=0;i<xkbi->szFilters;i++) {
|
|
if ((xkbi->filters[i].active)&&(xkbi->filters[i].filter))
|
|
send= ((*xkbi->filters[i].filter)(xkbi,&xkbi->filters[i],kc,pAction)
|
|
&& send);
|
|
}
|
|
return send;
|
|
}
|
|
|
|
void
|
|
XkbHandleActions(DeviceIntPtr dev, DeviceIntPtr kbd, DeviceEvent* event)
|
|
{
|
|
int key,bit,i;
|
|
XkbSrvInfoPtr xkbi;
|
|
KeyClassPtr keyc;
|
|
int changed,sendEvent;
|
|
Bool genStateNotify;
|
|
XkbAction act;
|
|
XkbFilterPtr filter;
|
|
Bool keyEvent;
|
|
Bool pressEvent;
|
|
ProcessInputProc backupproc;
|
|
|
|
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
|
|
|
|
keyc= kbd->key;
|
|
xkbi= keyc->xkbInfo;
|
|
key= event->detail.key;
|
|
/* The state may change, so if we're not in the middle of sending a state
|
|
* notify, prepare for it */
|
|
if ((xkbi->flags&_XkbStateNotifyInProgress)==0) {
|
|
xkbi->prev_state = xkbi->state;
|
|
xkbi->flags|= _XkbStateNotifyInProgress;
|
|
genStateNotify= TRUE;
|
|
}
|
|
else genStateNotify= FALSE;
|
|
|
|
xkbi->clearMods = xkbi->setMods = 0;
|
|
xkbi->groupChange = 0;
|
|
|
|
sendEvent = 1;
|
|
keyEvent= ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease));
|
|
pressEvent= ((event->type == ET_KeyPress)|| (event->type == ET_ButtonPress));
|
|
|
|
if (pressEvent) {
|
|
if (keyEvent)
|
|
act = XkbGetKeyAction(xkbi,&xkbi->state,key);
|
|
else {
|
|
act = XkbGetButtonAction(kbd,dev,key);
|
|
key|= BTN_ACT_FLAG;
|
|
}
|
|
sendEvent = _XkbApplyFilters(xkbi,key,&act);
|
|
if (sendEvent) {
|
|
switch (act.type) {
|
|
case XkbSA_SetMods:
|
|
case XkbSA_SetGroup:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent = _XkbFilterSetState(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_LatchMods:
|
|
case XkbSA_LatchGroup:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent=_XkbFilterLatchState(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_LockMods:
|
|
case XkbSA_LockGroup:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent=_XkbFilterLockState(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_ISOLock:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent=_XkbFilterISOLock(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_MovePtr:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent= _XkbFilterPointerMove(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_PtrBtn:
|
|
case XkbSA_LockPtrBtn:
|
|
case XkbSA_SetPtrDflt:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent= _XkbFilterPointerBtn(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_Terminate:
|
|
sendEvent= XkbDDXTerminateServer(dev,key,&act);
|
|
break;
|
|
case XkbSA_SwitchScreen:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent=_XkbFilterSwitchScreen(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_SetControls:
|
|
case XkbSA_LockControls:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent=_XkbFilterControls(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_ActionMessage:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent=_XkbFilterActionMessage(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_RedirectKey:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent= _XkbFilterRedirectKey(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_DeviceBtn:
|
|
case XkbSA_LockDeviceBtn:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent= _XkbFilterDeviceBtn(xkbi,filter,key,&act);
|
|
break;
|
|
case XkbSA_XFree86Private:
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
sendEvent= _XkbFilterXF86Private(xkbi,filter,key,&act);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (!keyEvent)
|
|
key|= BTN_ACT_FLAG;
|
|
sendEvent = _XkbApplyFilters(xkbi,key,NULL);
|
|
}
|
|
|
|
if (xkbi->groupChange!=0)
|
|
xkbi->state.base_group+= xkbi->groupChange;
|
|
if (xkbi->setMods) {
|
|
for (i=0,bit=1; xkbi->setMods; i++,bit<<=1 ) {
|
|
if (xkbi->setMods&bit) {
|
|
keyc->modifierKeyCount[i]++;
|
|
xkbi->state.base_mods|= bit;
|
|
xkbi->setMods&= ~bit;
|
|
}
|
|
}
|
|
}
|
|
if (xkbi->clearMods) {
|
|
for (i=0,bit=1; xkbi->clearMods; i++,bit<<=1 ) {
|
|
if (xkbi->clearMods&bit) {
|
|
keyc->modifierKeyCount[i]--;
|
|
if (keyc->modifierKeyCount[i]<=0) {
|
|
xkbi->state.base_mods&= ~bit;
|
|
keyc->modifierKeyCount[i] = 0;
|
|
}
|
|
xkbi->clearMods&= ~bit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sendEvent) {
|
|
DeviceIntPtr tmpdev;
|
|
if (keyEvent)
|
|
tmpdev = dev;
|
|
else
|
|
tmpdev = GetPairedDevice(dev);
|
|
|
|
UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc);
|
|
dev->public.processInputProc((InternalEvent*)event, tmpdev);
|
|
COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr,
|
|
backupproc,xkbUnwrapProc);
|
|
}
|
|
else if (keyEvent) {
|
|
FixKeyState(event, dev);
|
|
}
|
|
|
|
XkbComputeDerivedState(xkbi);
|
|
changed = XkbStateChangedFlags(&xkbi->prev_state,&xkbi->state);
|
|
if (genStateNotify) {
|
|
if (changed) {
|
|
xkbStateNotify sn;
|
|
sn.keycode= key;
|
|
sn.eventType= event->type;
|
|
sn.requestMajor = sn.requestMinor = 0;
|
|
sn.changed= changed;
|
|
XkbSendStateNotify(dev,&sn);
|
|
}
|
|
xkbi->flags&= ~_XkbStateNotifyInProgress;
|
|
}
|
|
changed= XkbIndicatorsToUpdate(dev,changed,FALSE);
|
|
if (changed) {
|
|
XkbEventCauseRec cause;
|
|
XkbSetCauseKey(&cause, key, event->type);
|
|
XkbUpdateIndicators(dev,changed,FALSE,NULL,&cause);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int
|
|
XkbLatchModifiers(DeviceIntPtr pXDev,CARD8 mask,CARD8 latches)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbFilterPtr filter;
|
|
XkbAction act;
|
|
unsigned clear;
|
|
|
|
if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) {
|
|
xkbi = pXDev->key->xkbInfo;
|
|
clear= (mask&(~latches));
|
|
xkbi->state.latched_mods&= ~clear;
|
|
/* Clear any pending latch to locks.
|
|
*/
|
|
act.type = XkbSA_NoAction;
|
|
_XkbApplyFilters(xkbi,SYNTHETIC_KEYCODE,&act);
|
|
act.type = XkbSA_LatchMods;
|
|
act.mods.flags = 0;
|
|
act.mods.mask = mask&latches;
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act);
|
|
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL);
|
|
return Success;
|
|
}
|
|
return BadValue;
|
|
}
|
|
|
|
int
|
|
XkbLatchGroup(DeviceIntPtr pXDev,int group)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbFilterPtr filter;
|
|
XkbAction act;
|
|
|
|
if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) {
|
|
xkbi = pXDev->key->xkbInfo;
|
|
act.type = XkbSA_LatchGroup;
|
|
act.group.flags = 0;
|
|
XkbSASetGroup(&act.group,group);
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act);
|
|
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL);
|
|
return Success;
|
|
}
|
|
return BadValue;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
void
|
|
XkbClearAllLatchesAndLocks( DeviceIntPtr dev,
|
|
XkbSrvInfoPtr xkbi,
|
|
Bool genEv,
|
|
XkbEventCausePtr cause)
|
|
{
|
|
XkbStateRec os;
|
|
xkbStateNotify sn;
|
|
|
|
sn.changed= 0;
|
|
os= xkbi->state;
|
|
if (os.latched_mods) { /* clear all latches */
|
|
XkbLatchModifiers(dev,~0,0);
|
|
sn.changed|= XkbModifierLatchMask;
|
|
}
|
|
if (os.latched_group) {
|
|
XkbLatchGroup(dev,0);
|
|
sn.changed|= XkbGroupLatchMask;
|
|
}
|
|
if (os.locked_mods) {
|
|
xkbi->state.locked_mods= 0;
|
|
sn.changed|= XkbModifierLockMask;
|
|
}
|
|
if (os.locked_group) {
|
|
xkbi->state.locked_group= 0;
|
|
sn.changed|= XkbGroupLockMask;
|
|
}
|
|
if ( genEv && sn.changed) {
|
|
CARD32 changed;
|
|
|
|
XkbComputeDerivedState(xkbi);
|
|
sn.keycode= cause->kc;
|
|
sn.eventType= cause->event;
|
|
sn.requestMajor= cause->mjr;
|
|
sn.requestMinor= cause->mnr;
|
|
sn.changed= XkbStateChangedFlags(&os,&xkbi->state);
|
|
XkbSendStateNotify(dev,&sn);
|
|
changed= XkbIndicatorsToUpdate(dev,sn.changed,FALSE);
|
|
if (changed) {
|
|
XkbUpdateIndicators(dev,changed,TRUE,NULL,cause);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* The event is injected into the event processing, not the EQ. Thus,
|
|
* ensure that we restore the master after the event sequence to the
|
|
* original set of classes. Otherwise, the master remains on the XTEST
|
|
* classes and drops events that don't fit into the XTEST layout (e.g.
|
|
* events with more than 2 valuators).
|
|
*
|
|
* FIXME: EQ injection in the processing stage is not designed for, so this
|
|
* is a rather awkward hack. The event list returned by GetPointerEvents()
|
|
* and friends is always prefixed with a DCE if the last _posted_ device was
|
|
* different. For normal events, this sequence then resets the master during
|
|
* the processing stage. Since we inject the PointerKey events in the
|
|
* processing stage though, we need to manually reset to restore the
|
|
* previous order, because the events already in the EQ must be sent for the
|
|
* right device.
|
|
* So we post-fix the event list we get from GPE with a DCE back to the
|
|
* previous slave device.
|
|
*
|
|
* First one on drinking island wins!
|
|
*/
|
|
static void
|
|
InjectPointerKeyEvents(DeviceIntPtr dev, int type, int button, int flags, int num_valuators, int *valuators)
|
|
{
|
|
ScreenPtr pScreen;
|
|
EventListPtr events;
|
|
int nevents, i;
|
|
DeviceIntPtr ptr, mpointer, lastSlave = NULL;
|
|
Bool saveWait;
|
|
|
|
if (IsMaster(dev)) {
|
|
mpointer = GetMaster(dev, MASTER_POINTER);
|
|
lastSlave = mpointer->u.lastSlave;
|
|
ptr = GetXTestDevice(mpointer);
|
|
} else if (!dev->u.master)
|
|
ptr = dev;
|
|
else
|
|
return;
|
|
|
|
|
|
events = InitEventList(GetMaximumEventsNum() + 1);
|
|
OsBlockSignals();
|
|
pScreen = miPointerGetScreen(ptr);
|
|
saveWait = miPointerSetWaitForUpdate(pScreen, FALSE);
|
|
nevents = GetPointerEvents(events, ptr, type, button, flags, 0,
|
|
num_valuators, valuators);
|
|
if (IsMaster(dev) && (lastSlave && lastSlave != ptr))
|
|
UpdateFromMaster(&events[nevents], lastSlave, DEVCHANGE_POINTER_EVENT, &nevents);
|
|
miPointerSetWaitForUpdate(pScreen, saveWait);
|
|
OsReleaseSignals();
|
|
|
|
for (i = 0; i < nevents; i++)
|
|
mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
|
|
|
|
FreeEventList(events, GetMaximumEventsNum());
|
|
|
|
}
|
|
|
|
static void
|
|
XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
|
|
{
|
|
int gpe_flags = 0;
|
|
int motion[2];
|
|
|
|
/* ignore attached SDs */
|
|
if (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) != NULL)
|
|
return;
|
|
|
|
if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
|
|
gpe_flags = POINTER_ABSOLUTE;
|
|
else
|
|
gpe_flags = POINTER_RELATIVE;
|
|
|
|
motion[0] = x;
|
|
motion[1] = y;
|
|
InjectPointerKeyEvents(dev, MotionNotify, 0, gpe_flags, 2, motion);
|
|
}
|
|
|
|
void
|
|
XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
|
|
{
|
|
DeviceIntPtr ptr;
|
|
int down;
|
|
|
|
/* If dev is a slave device, and the SD is attached, do nothing. If we'd
|
|
* post through the attached master pointer we'd get duplicate events.
|
|
*
|
|
* if dev is a master keyboard, post through the XTEST device
|
|
*
|
|
* if dev is a floating slave, post through the device itself.
|
|
*/
|
|
|
|
if (IsMaster(dev)) {
|
|
DeviceIntPtr mpointer = GetMaster(dev, MASTER_POINTER);
|
|
ptr = GetXTestDevice(mpointer);
|
|
} else if (!dev->u.master)
|
|
ptr = dev;
|
|
else
|
|
return;
|
|
|
|
down = button_is_down(ptr, button, BUTTON_PROCESSED);
|
|
if (press == down)
|
|
return;
|
|
|
|
InjectPointerKeyEvents(dev, press ? ButtonPress : ButtonRelease,
|
|
button, 0, 0, NULL);
|
|
}
|