1706f2543Smrg/************************************************************
2706f2543SmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3706f2543Smrg
4706f2543SmrgPermission to use, copy, modify, and distribute this
5706f2543Smrgsoftware and its documentation for any purpose and without
6706f2543Smrgfee is hereby granted, provided that the above copyright
7706f2543Smrgnotice appear in all copies and that both that copyright
8706f2543Smrgnotice and this permission notice appear in supporting
9706f2543Smrgdocumentation, and that the name of Silicon Graphics not be
10706f2543Smrgused in advertising or publicity pertaining to distribution
11706f2543Smrgof the software without specific prior written permission.
12706f2543SmrgSilicon Graphics makes no representation about the suitability
13706f2543Smrgof this software for any purpose. It is provided "as is"
14706f2543Smrgwithout any express or implied warranty.
15706f2543Smrg
16706f2543SmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18706f2543SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19706f2543SmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20706f2543SmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21706f2543SmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22706f2543SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23706f2543SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
24706f2543Smrg
25706f2543Smrg********************************************************/
26706f2543Smrg
27706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
28706f2543Smrg#include <dix-config.h>
29706f2543Smrg#endif
30706f2543Smrg
31706f2543Smrg#include <stdio.h>
32706f2543Smrg#include <math.h>
33706f2543Smrg#include <X11/X.h>
34706f2543Smrg#include <X11/Xproto.h>
35706f2543Smrg#include <X11/keysym.h>
36706f2543Smrg#include "misc.h"
37706f2543Smrg#include "inputstr.h"
38706f2543Smrg#include "exevents.h"
39706f2543Smrg#include "eventstr.h"
40706f2543Smrg#include <xkbsrv.h>
41706f2543Smrg#include "xkb.h"
42706f2543Smrg#include <ctype.h>
43706f2543Smrg#include "mi.h"
44706f2543Smrg#include "mipointer.h"
45706f2543Smrg#include "inpututils.h"
46706f2543Smrg#define EXTENSION_EVENT_BASE 64
47706f2543Smrg
48706f2543SmrgDevPrivateKeyRec xkbDevicePrivateKeyRec;
49706f2543Smrg
50706f2543Smrgvoid XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button);
51706f2543Smrgstatic void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y);
52706f2543Smrg
53706f2543Smrgvoid
54706f2543SmrgxkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc,
55706f2543Smrg                   pointer data)
56706f2543Smrg{
57706f2543Smrg    xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
58706f2543Smrg    ProcessInputProc backupproc;
59706f2543Smrg    if(xkbPrivPtr->unwrapProc)
60706f2543Smrg	xkbPrivPtr->unwrapProc = NULL;
61706f2543Smrg
62706f2543Smrg    UNWRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr, backupproc);
63706f2543Smrg    proc(device,data);
64706f2543Smrg    COND_WRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr,
65706f2543Smrg				 backupproc,xkbUnwrapProc);
66706f2543Smrg}
67706f2543Smrg
68706f2543SmrgBool
69706f2543SmrgXkbInitPrivates(void)
70706f2543Smrg{
71706f2543Smrg    return dixRegisterPrivateKey(&xkbDevicePrivateKeyRec, PRIVATE_DEVICE, sizeof(xkbDeviceInfoRec));
72706f2543Smrg}
73706f2543Smrg
74706f2543Smrgvoid
75706f2543SmrgXkbSetExtension(DeviceIntPtr device, ProcessInputProc proc)
76706f2543Smrg{
77706f2543Smrg    xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
78706f2543Smrg    WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc);
79706f2543Smrg}
80706f2543Smrg
81706f2543Smrg/***====================================================================***/
82706f2543Smrg
83706f2543Smrgstatic XkbAction
84706f2543Smrg_FixUpAction(XkbDescPtr xkb,XkbAction *act)
85706f2543Smrg{
86706f2543Smrgstatic XkbAction	fake;
87706f2543Smrg
88706f2543Smrg    if (XkbIsPtrAction(act)&&(!(xkb->ctrls->enabled_ctrls&XkbMouseKeysMask))) {
89706f2543Smrg	fake.type = XkbSA_NoAction;
90706f2543Smrg	return fake;
91706f2543Smrg    }
92706f2543Smrg    if (xkb->ctrls->enabled_ctrls&XkbStickyKeysMask) {
93706f2543Smrg	if (act->any.type==XkbSA_SetMods) {
94706f2543Smrg	    fake.mods.type = XkbSA_LatchMods;
95706f2543Smrg	    fake.mods.mask = act->mods.mask;
96706f2543Smrg	    if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask))
97706f2543Smrg		 fake.mods.flags= XkbSA_ClearLocks|XkbSA_LatchToLock;
98706f2543Smrg	    else fake.mods.flags= XkbSA_ClearLocks;
99706f2543Smrg	    return fake;
100706f2543Smrg	}
101706f2543Smrg	if (act->any.type==XkbSA_SetGroup) {
102706f2543Smrg	    fake.group.type = XkbSA_LatchGroup;
103706f2543Smrg	    if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask))
104706f2543Smrg		 fake.group.flags= XkbSA_ClearLocks|XkbSA_LatchToLock;
105706f2543Smrg	    else fake.group.flags= XkbSA_ClearLocks;
106706f2543Smrg	    XkbSASetGroup(&fake.group,XkbSAGroup(&act->group));
107706f2543Smrg	    return fake;
108706f2543Smrg	}
109706f2543Smrg    }
110706f2543Smrg    return *act;
111706f2543Smrg}
112706f2543Smrg
113706f2543Smrgstatic XkbAction
114706f2543SmrgXkbGetKeyAction(XkbSrvInfoPtr xkbi,XkbStatePtr xkbState,CARD8 key)
115706f2543Smrg{
116706f2543Smrgint			effectiveGroup;
117706f2543Smrgint			col;
118706f2543SmrgXkbDescPtr		xkb;
119706f2543SmrgXkbKeyTypePtr		type;
120706f2543SmrgXkbAction *		pActs;
121706f2543Smrgstatic XkbAction 	fake;
122706f2543Smrg
123706f2543Smrg    xkb= xkbi->desc;
124706f2543Smrg    if (!XkbKeyHasActions(xkb,key) || !XkbKeycodeInRange(xkb,key)) {
125706f2543Smrg	fake.type = XkbSA_NoAction;
126706f2543Smrg	return fake;
127706f2543Smrg    }
128706f2543Smrg    pActs= XkbKeyActionsPtr(xkb,key);
129706f2543Smrg    col= 0;
130706f2543Smrg
131706f2543Smrg    effectiveGroup = XkbGetEffectiveGroup(xkbi, xkbState, key);
132706f2543Smrg    if (effectiveGroup != XkbGroup1Index)
133706f2543Smrg        col += (effectiveGroup * XkbKeyGroupsWidth(xkb, key));
134706f2543Smrg
135706f2543Smrg    type= XkbKeyKeyType(xkb,key,effectiveGroup);
136706f2543Smrg    if (type->map!=NULL) {
137706f2543Smrg	register unsigned		i,mods;
138706f2543Smrg	register XkbKTMapEntryPtr	entry;
139706f2543Smrg	mods= xkbState->mods&type->mods.mask;
140706f2543Smrg	for (entry= type->map,i=0;i<type->map_count;i++,entry++) {
141706f2543Smrg	    if ((entry->active)&&(entry->mods.mask==mods)) {
142706f2543Smrg		col+= entry->level;
143706f2543Smrg		break;
144706f2543Smrg	    }
145706f2543Smrg	}
146706f2543Smrg    }
147706f2543Smrg    if (pActs[col].any.type==XkbSA_NoAction)
148706f2543Smrg	return pActs[col];
149706f2543Smrg    fake= _FixUpAction(xkb,&pActs[col]);
150706f2543Smrg    return fake;
151706f2543Smrg}
152706f2543Smrg
153706f2543Smrgstatic XkbAction
154706f2543SmrgXkbGetButtonAction(DeviceIntPtr kbd,DeviceIntPtr dev,int button)
155706f2543Smrg{
156706f2543SmrgXkbAction fake;
157706f2543Smrg   if ((dev->button)&&(dev->button->xkb_acts)) {
158706f2543Smrg	if (dev->button->xkb_acts[button-1].any.type!=XkbSA_NoAction) {
159706f2543Smrg	    fake= _FixUpAction(kbd->key->xkbInfo->desc,
160706f2543Smrg					&dev->button->xkb_acts[button-1]);
161706f2543Smrg	    return fake;
162706f2543Smrg	}
163706f2543Smrg   }
164706f2543Smrg   fake.any.type= XkbSA_NoAction;
165706f2543Smrg   return fake;
166706f2543Smrg}
167706f2543Smrg
168706f2543Smrg/***====================================================================***/
169706f2543Smrg
170706f2543Smrg#define	SYNTHETIC_KEYCODE	1
171706f2543Smrg#define	BTN_ACT_FLAG		0x100
172706f2543Smrg
173706f2543Smrgstatic int
174706f2543Smrg_XkbFilterSetState(	XkbSrvInfoPtr	xkbi,
175706f2543Smrg			XkbFilterPtr	filter,
176706f2543Smrg			unsigned	keycode,
177706f2543Smrg			XkbAction *pAction)
178706f2543Smrg{
179706f2543Smrg    if (filter->keycode==0) {		/* initial press */
180706f2543Smrg	filter->keycode = keycode;
181706f2543Smrg	filter->active = 1;
182706f2543Smrg	filter->filterOthers = ((pAction->mods.mask&XkbSA_ClearLocks)!=0);
183706f2543Smrg	filter->priv = 0;
184706f2543Smrg	filter->filter = _XkbFilterSetState;
185706f2543Smrg	if (pAction->type==XkbSA_SetMods) {
186706f2543Smrg	    filter->upAction = *pAction;
187706f2543Smrg	    xkbi->setMods= pAction->mods.mask;
188706f2543Smrg	}
189706f2543Smrg	else {
190706f2543Smrg	    xkbi->groupChange = XkbSAGroup(&pAction->group);
191706f2543Smrg	    if (pAction->group.flags&XkbSA_GroupAbsolute)
192706f2543Smrg		xkbi->groupChange-= xkbi->state.base_group;
193706f2543Smrg	    filter->upAction= *pAction;
194706f2543Smrg	    XkbSASetGroup(&filter->upAction.group,xkbi->groupChange);
195706f2543Smrg	}
196706f2543Smrg    }
197706f2543Smrg    else if (filter->keycode==keycode) {
198706f2543Smrg	if (filter->upAction.type==XkbSA_SetMods) {
199706f2543Smrg	    xkbi->clearMods = filter->upAction.mods.mask;
200706f2543Smrg	    if (filter->upAction.mods.flags&XkbSA_ClearLocks) {
201706f2543Smrg		xkbi->state.locked_mods&= ~filter->upAction.mods.mask;
202706f2543Smrg	    }
203706f2543Smrg	}
204706f2543Smrg	else {
205706f2543Smrg	    if (filter->upAction.group.flags&XkbSA_ClearLocks) {
206706f2543Smrg		xkbi->state.locked_group = 0;
207706f2543Smrg	    }
208706f2543Smrg	    xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
209706f2543Smrg	}
210706f2543Smrg	filter->active = 0;
211706f2543Smrg    }
212706f2543Smrg    else {
213706f2543Smrg	filter->upAction.mods.flags&= ~XkbSA_ClearLocks;
214706f2543Smrg	filter->filterOthers = 0;
215706f2543Smrg    }
216706f2543Smrg    return 1;
217706f2543Smrg}
218706f2543Smrg
219706f2543Smrg#define	LATCH_KEY_DOWN	1
220706f2543Smrg#define	LATCH_PENDING	2
221706f2543Smrg#define	NO_LATCH	3
222706f2543Smrg
223706f2543Smrgstatic int
224706f2543Smrg_XkbFilterLatchState(	XkbSrvInfoPtr	xkbi,
225706f2543Smrg			XkbFilterPtr	filter,
226706f2543Smrg			unsigned	keycode,
227706f2543Smrg			XkbAction *	pAction)
228706f2543Smrg{
229706f2543Smrg
230706f2543Smrg    if (filter->keycode==0) {			/* initial press */
231706f2543Smrg	filter->keycode = keycode;
232706f2543Smrg	filter->active = 1;
233706f2543Smrg	filter->filterOthers = 1;
234706f2543Smrg	filter->priv = LATCH_KEY_DOWN;
235706f2543Smrg	filter->filter = _XkbFilterLatchState;
236706f2543Smrg	if (pAction->type==XkbSA_LatchMods) {
237706f2543Smrg	    filter->upAction = *pAction;
238706f2543Smrg	    xkbi->setMods = pAction->mods.mask;
239706f2543Smrg	}
240706f2543Smrg	else {
241706f2543Smrg	    xkbi->groupChange = XkbSAGroup(&pAction->group);
242706f2543Smrg	    if (pAction->group.flags&XkbSA_GroupAbsolute)
243706f2543Smrg		 xkbi->groupChange-= xkbi->state.base_group;
244706f2543Smrg	    filter->upAction= *pAction;
245706f2543Smrg	    XkbSASetGroup(&filter->upAction.group,xkbi->groupChange);
246706f2543Smrg	}
247706f2543Smrg    }
248706f2543Smrg    else if ( pAction && (filter->priv==LATCH_PENDING) ) {
249706f2543Smrg	if (((1<<pAction->type)&XkbSA_BreakLatch)!=0) {
250706f2543Smrg	    filter->active = 0;
251706f2543Smrg	    if (filter->upAction.type==XkbSA_LatchMods)
252706f2543Smrg		 xkbi->state.latched_mods&= ~filter->upAction.mods.mask;
253706f2543Smrg	    else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group);
254706f2543Smrg	}
255706f2543Smrg	else if ((pAction->type==filter->upAction.type)&&
256706f2543Smrg		 (pAction->mods.flags==filter->upAction.mods.flags)&&
257706f2543Smrg		 (pAction->mods.mask==filter->upAction.mods.mask)) {
258706f2543Smrg	    if (filter->upAction.mods.flags&XkbSA_LatchToLock) {
259706f2543Smrg		XkbControlsPtr ctrls= xkbi->desc->ctrls;
260706f2543Smrg		if (filter->upAction.type==XkbSA_LatchMods)
261706f2543Smrg		     pAction->mods.type= XkbSA_LockMods;
262706f2543Smrg		else pAction->group.type= XkbSA_LockGroup;
263706f2543Smrg		if (XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask)&&
264706f2543Smrg		    		(ctrls->enabled_ctrls&XkbStickyKeysMask)) {
265706f2543Smrg		    XkbDDXAccessXBeep(xkbi->device,_BEEP_STICKY_LOCK,
266706f2543Smrg						XkbStickyKeysMask);
267706f2543Smrg		}
268706f2543Smrg	    }
269706f2543Smrg	    else {
270706f2543Smrg		if (filter->upAction.type==XkbSA_LatchMods)
271706f2543Smrg		     pAction->mods.type= XkbSA_SetMods;
272706f2543Smrg		else pAction->group.type= XkbSA_SetGroup;
273706f2543Smrg	    }
274706f2543Smrg	    if (filter->upAction.type==XkbSA_LatchMods)
275706f2543Smrg		 xkbi->state.latched_mods&= ~filter->upAction.mods.mask;
276706f2543Smrg	    else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group);
277706f2543Smrg	    filter->active = 0;
278706f2543Smrg	}
279706f2543Smrg    }
280706f2543Smrg    else if (filter->keycode==keycode) {	/* release */
281706f2543Smrg	XkbControlsPtr	ctrls= xkbi->desc->ctrls;
282706f2543Smrg	int		needBeep;
283706f2543Smrg	int		beepType= _BEEP_NONE;
284706f2543Smrg
285706f2543Smrg	needBeep= ((ctrls->enabled_ctrls&XkbStickyKeysMask)&&
286706f2543Smrg			XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask));
287706f2543Smrg	if (filter->upAction.type==XkbSA_LatchMods) {
288706f2543Smrg	    xkbi->clearMods = filter->upAction.mods.mask;
289706f2543Smrg	    if ((filter->upAction.mods.flags&XkbSA_ClearLocks)&&
290706f2543Smrg		 (xkbi->clearMods&xkbi->state.locked_mods)==xkbi->clearMods) {
291706f2543Smrg		xkbi->state.locked_mods&= ~xkbi->clearMods;
292706f2543Smrg		filter->priv= NO_LATCH;
293706f2543Smrg		beepType= _BEEP_STICKY_UNLOCK;
294706f2543Smrg	    }
295706f2543Smrg	}
296706f2543Smrg	else {
297706f2543Smrg	    xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
298706f2543Smrg	    if ((filter->upAction.group.flags&XkbSA_ClearLocks)&&
299706f2543Smrg						(xkbi->state.locked_group)) {
300706f2543Smrg		xkbi->state.locked_group = 0;
301706f2543Smrg		filter->priv = NO_LATCH;
302706f2543Smrg		beepType= _BEEP_STICKY_UNLOCK;
303706f2543Smrg	    }
304706f2543Smrg	}
305706f2543Smrg	if (filter->priv==NO_LATCH) {
306706f2543Smrg	    filter->active= 0;
307706f2543Smrg	}
308706f2543Smrg	else {
309706f2543Smrg	    filter->priv= LATCH_PENDING;
310706f2543Smrg	    if (filter->upAction.type==XkbSA_LatchMods) {
311706f2543Smrg		xkbi->state.latched_mods |= filter->upAction.mods.mask;
312706f2543Smrg		needBeep = xkbi->state.latched_mods ? needBeep : 0;
313706f2543Smrg		xkbi->state.latched_mods |= filter->upAction.mods.mask;
314706f2543Smrg	    }
315706f2543Smrg	    else {
316706f2543Smrg		xkbi->state.latched_group+= XkbSAGroup(&filter->upAction.group);
317706f2543Smrg	    }
318706f2543Smrg	    if (needBeep && (beepType==_BEEP_NONE))
319706f2543Smrg		beepType= _BEEP_STICKY_LATCH;
320706f2543Smrg	}
321706f2543Smrg	if (needBeep && (beepType!=_BEEP_NONE))
322706f2543Smrg	    XkbDDXAccessXBeep(xkbi->device,beepType,XkbStickyKeysMask);
323706f2543Smrg    }
324706f2543Smrg    else if (filter->priv==LATCH_KEY_DOWN) {
325706f2543Smrg	filter->priv= NO_LATCH;
326706f2543Smrg	filter->filterOthers = 0;
327706f2543Smrg    }
328706f2543Smrg    return 1;
329706f2543Smrg}
330706f2543Smrg
331706f2543Smrgstatic int
332706f2543Smrg_XkbFilterLockState(	XkbSrvInfoPtr	xkbi,
333706f2543Smrg			XkbFilterPtr	filter,
334706f2543Smrg			unsigned	keycode,
335706f2543Smrg			XkbAction *	pAction)
336706f2543Smrg{
337706f2543Smrg    if (pAction&&(pAction->type==XkbSA_LockGroup)) {
338706f2543Smrg	if (pAction->group.flags&XkbSA_GroupAbsolute)
339706f2543Smrg	     xkbi->state.locked_group= XkbSAGroup(&pAction->group);
340706f2543Smrg	else xkbi->state.locked_group+= XkbSAGroup(&pAction->group);
341706f2543Smrg	return 1;
342706f2543Smrg    }
343706f2543Smrg    if (filter->keycode==0) {		/* initial press */
344706f2543Smrg	filter->keycode = keycode;
345706f2543Smrg	filter->active = 1;
346706f2543Smrg	filter->filterOthers = 0;
347706f2543Smrg	filter->priv = 0;
348706f2543Smrg	filter->filter = _XkbFilterLockState;
349706f2543Smrg	filter->upAction = *pAction;
350706f2543Smrg	xkbi->state.locked_mods^= pAction->mods.mask;
351706f2543Smrg	xkbi->setMods = pAction->mods.mask;
352706f2543Smrg    }
353706f2543Smrg    else if (filter->keycode==keycode) {
354706f2543Smrg	filter->active = 0;
355706f2543Smrg	xkbi->clearMods = filter->upAction.mods.mask;
356706f2543Smrg    }
357706f2543Smrg    return 1;
358706f2543Smrg}
359706f2543Smrg
360706f2543Smrg#define	ISO_KEY_DOWN		0
361706f2543Smrg#define	NO_ISO_LOCK		1
362706f2543Smrg
363706f2543Smrgstatic int
364706f2543Smrg_XkbFilterISOLock(	XkbSrvInfoPtr	xkbi,
365706f2543Smrg			XkbFilterPtr	filter,
366706f2543Smrg			unsigned	keycode,
367706f2543Smrg			XkbAction *	pAction)
368706f2543Smrg{
369706f2543Smrg
370706f2543Smrg    if (filter->keycode==0) {		/* initial press */
371706f2543Smrg	CARD8	flags= pAction->iso.flags;
372706f2543Smrg
373706f2543Smrg	filter->keycode = keycode;
374706f2543Smrg	filter->active = 1;
375706f2543Smrg	filter->filterOthers = 1;
376706f2543Smrg	filter->priv = ISO_KEY_DOWN;
377706f2543Smrg	filter->upAction = *pAction;
378706f2543Smrg	filter->filter = _XkbFilterISOLock;
379706f2543Smrg	if (flags&XkbSA_ISODfltIsGroup) {
380706f2543Smrg	    xkbi->groupChange = XkbSAGroup(&pAction->iso);
381706f2543Smrg	    xkbi->setMods = 0;
382706f2543Smrg	}
383706f2543Smrg	else {
384706f2543Smrg	    xkbi->setMods = pAction->iso.mask;
385706f2543Smrg	    xkbi->groupChange = 0;
386706f2543Smrg	}
387706f2543Smrg	if ((!(flags&XkbSA_ISONoAffectMods))&&(xkbi->state.base_mods)) {
388706f2543Smrg	    filter->priv= NO_ISO_LOCK;
389706f2543Smrg	    xkbi->state.locked_mods^= xkbi->state.base_mods;
390706f2543Smrg	}
391706f2543Smrg	if ((!(flags&XkbSA_ISONoAffectGroup))&&(xkbi->state.base_group)) {
392706f2543Smrg/* 6/22/93 (ef) -- lock groups if group key is down first */
393706f2543Smrg	}
394706f2543Smrg	if (!(flags&XkbSA_ISONoAffectPtr)) {
395706f2543Smrg/* 6/22/93 (ef) -- lock mouse buttons if they're down */
396706f2543Smrg	}
397706f2543Smrg    }
398706f2543Smrg    else if (filter->keycode==keycode) {
399706f2543Smrg	CARD8	flags= filter->upAction.iso.flags;
400706f2543Smrg
401706f2543Smrg	if (flags&XkbSA_ISODfltIsGroup) {
402706f2543Smrg	    xkbi->groupChange = -XkbSAGroup(&filter->upAction.iso);
403706f2543Smrg	    xkbi->clearMods = 0;
404706f2543Smrg	    if (filter->priv==ISO_KEY_DOWN)
405706f2543Smrg		xkbi->state.locked_group+= XkbSAGroup(&filter->upAction.iso);
406706f2543Smrg	}
407706f2543Smrg	else {
408706f2543Smrg	    xkbi->clearMods= filter->upAction.iso.mask;
409706f2543Smrg	    xkbi->groupChange= 0;
410706f2543Smrg	    if (filter->priv==ISO_KEY_DOWN)
411706f2543Smrg		xkbi->state.locked_mods^= filter->upAction.iso.mask;
412706f2543Smrg	}
413706f2543Smrg	filter->active = 0;
414706f2543Smrg    }
415706f2543Smrg    else if (pAction) {
416706f2543Smrg	CARD8	flags= filter->upAction.iso.flags;
417706f2543Smrg
418706f2543Smrg	switch (pAction->type) {
419706f2543Smrg	    case XkbSA_SetMods: case XkbSA_LatchMods:
420706f2543Smrg		if (!(flags&XkbSA_ISONoAffectMods)) {
421706f2543Smrg		    pAction->type= XkbSA_LockMods;
422706f2543Smrg		    filter->priv= NO_ISO_LOCK;
423706f2543Smrg		}
424706f2543Smrg		break;
425706f2543Smrg	    case XkbSA_SetGroup: case XkbSA_LatchGroup:
426706f2543Smrg		if (!(flags&XkbSA_ISONoAffectGroup)) {
427706f2543Smrg		    pAction->type= XkbSA_LockGroup;
428706f2543Smrg		    filter->priv= NO_ISO_LOCK;
429706f2543Smrg		}
430706f2543Smrg		break;
431706f2543Smrg	    case XkbSA_PtrBtn:
432706f2543Smrg		if (!(flags&XkbSA_ISONoAffectPtr)) {
433706f2543Smrg		     pAction->type= XkbSA_LockPtrBtn;
434706f2543Smrg		     filter->priv= NO_ISO_LOCK;
435706f2543Smrg		}
436706f2543Smrg		break;
437706f2543Smrg	    case XkbSA_SetControls:
438706f2543Smrg		if (!(flags&XkbSA_ISONoAffectCtrls)) {
439706f2543Smrg		    pAction->type= XkbSA_LockControls;
440706f2543Smrg		    filter->priv= NO_ISO_LOCK;
441706f2543Smrg		}
442706f2543Smrg		break;
443706f2543Smrg	}
444706f2543Smrg    }
445706f2543Smrg    return 1;
446706f2543Smrg}
447706f2543Smrg
448706f2543Smrg
449706f2543Smrgstatic CARD32
450706f2543Smrg_XkbPtrAccelExpire(OsTimerPtr timer,CARD32 now,pointer arg)
451706f2543Smrg{
452706f2543SmrgXkbSrvInfoPtr	xkbi= (XkbSrvInfoPtr)arg;
453706f2543SmrgXkbControlsPtr	ctrls= xkbi->desc->ctrls;
454706f2543Smrgint		dx,dy;
455706f2543Smrg
456706f2543Smrg    if (xkbi->mouseKey==0)
457706f2543Smrg	return 0;
458706f2543Smrg
459706f2543Smrg    if (xkbi->mouseKeysAccel) {
460706f2543Smrg	if ((xkbi->mouseKeysCounter)<ctrls->mk_time_to_max) {
461706f2543Smrg	    double step;
462706f2543Smrg	    xkbi->mouseKeysCounter++;
463706f2543Smrg	    step= xkbi->mouseKeysCurveFactor*
464706f2543Smrg		 pow((double)xkbi->mouseKeysCounter,xkbi->mouseKeysCurve);
465706f2543Smrg	    if (xkbi->mouseKeysDX<0)
466706f2543Smrg		 dx= floor( ((double)xkbi->mouseKeysDX)*step );
467706f2543Smrg	    else dx=  ceil( ((double)xkbi->mouseKeysDX)*step );
468706f2543Smrg	    if (xkbi->mouseKeysDY<0)
469706f2543Smrg		 dy= floor( ((double)xkbi->mouseKeysDY)*step );
470706f2543Smrg	    else dy=  ceil( ((double)xkbi->mouseKeysDY)*step );
471706f2543Smrg	}
472706f2543Smrg	else {
473706f2543Smrg	    dx= xkbi->mouseKeysDX*ctrls->mk_max_speed;
474706f2543Smrg	    dy= xkbi->mouseKeysDY*ctrls->mk_max_speed;
475706f2543Smrg	}
476706f2543Smrg	if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteX)
477706f2543Smrg	    dx= xkbi->mouseKeysDX;
478706f2543Smrg	if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteY)
479706f2543Smrg	    dy= xkbi->mouseKeysDY;
480706f2543Smrg    }
481706f2543Smrg    else {
482706f2543Smrg	dx= xkbi->mouseKeysDX;
483706f2543Smrg	dy= xkbi->mouseKeysDY;
484706f2543Smrg    }
485706f2543Smrg    XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy);
486706f2543Smrg    return xkbi->desc->ctrls->mk_interval;
487706f2543Smrg}
488706f2543Smrg
489706f2543Smrgstatic int
490706f2543Smrg_XkbFilterPointerMove(	XkbSrvInfoPtr	xkbi,
491706f2543Smrg			XkbFilterPtr	filter,
492706f2543Smrg			unsigned	keycode,
493706f2543Smrg			XkbAction *	pAction)
494706f2543Smrg{
495706f2543Smrgint	x,y;
496706f2543SmrgBool	accel;
497706f2543Smrg
498706f2543Smrg    if (filter->keycode==0) {		/* initial press */
499706f2543Smrg	filter->keycode = keycode;
500706f2543Smrg	filter->active = 1;
501706f2543Smrg	filter->filterOthers = 0;
502706f2543Smrg	filter->priv=0;
503706f2543Smrg	filter->filter = _XkbFilterPointerMove;
504706f2543Smrg	filter->upAction= *pAction;
505706f2543Smrg	xkbi->mouseKeysCounter= 0;
506706f2543Smrg	xkbi->mouseKey= keycode;
507706f2543Smrg	accel= ((pAction->ptr.flags&XkbSA_NoAcceleration)==0);
508706f2543Smrg	x= XkbPtrActionX(&pAction->ptr);
509706f2543Smrg	y= XkbPtrActionY(&pAction->ptr);
510706f2543Smrg	XkbFakePointerMotion(xkbi->device, pAction->ptr.flags,x,y);
511706f2543Smrg	AccessXCancelRepeatKey(xkbi,keycode);
512706f2543Smrg	xkbi->mouseKeysAccel= accel&&
513706f2543Smrg		(xkbi->desc->ctrls->enabled_ctrls&XkbMouseKeysAccelMask);
514706f2543Smrg	xkbi->mouseKeysFlags= pAction->ptr.flags;
515706f2543Smrg	xkbi->mouseKeysDX= XkbPtrActionX(&pAction->ptr);
516706f2543Smrg	xkbi->mouseKeysDY= XkbPtrActionY(&pAction->ptr);
517706f2543Smrg	xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0,
518706f2543Smrg				xkbi->desc->ctrls->mk_delay,
519706f2543Smrg				_XkbPtrAccelExpire,(pointer)xkbi);
520706f2543Smrg    }
521706f2543Smrg    else if (filter->keycode==keycode) {
522706f2543Smrg	filter->active = 0;
523706f2543Smrg	if (xkbi->mouseKey==keycode) {
524706f2543Smrg	    xkbi->mouseKey= 0;
525706f2543Smrg	    xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, 0,
526706f2543Smrg							NULL, NULL);
527706f2543Smrg	}
528706f2543Smrg    }
529706f2543Smrg    return 0;
530706f2543Smrg}
531706f2543Smrg
532706f2543Smrgstatic int
533706f2543Smrg_XkbFilterPointerBtn(	XkbSrvInfoPtr	xkbi,
534706f2543Smrg			XkbFilterPtr	filter,
535706f2543Smrg			unsigned	keycode,
536706f2543Smrg			XkbAction *	pAction)
537706f2543Smrg{
538706f2543Smrg    if (filter->keycode==0) {		/* initial press */
539706f2543Smrg	int	button= pAction->btn.button;
540706f2543Smrg
541706f2543Smrg	if (button==XkbSA_UseDfltButton)
542706f2543Smrg	    button = xkbi->desc->ctrls->mk_dflt_btn;
543706f2543Smrg
544706f2543Smrg	filter->keycode = keycode;
545706f2543Smrg	filter->active = 1;
546706f2543Smrg	filter->filterOthers = 0;
547706f2543Smrg	filter->priv=0;
548706f2543Smrg	filter->filter = _XkbFilterPointerBtn;
549706f2543Smrg	filter->upAction= *pAction;
550706f2543Smrg	filter->upAction.btn.button= button;
551706f2543Smrg	switch (pAction->type) {
552706f2543Smrg	    case XkbSA_LockPtrBtn:
553706f2543Smrg		if (((xkbi->lockedPtrButtons&(1<<button))==0)&&
554706f2543Smrg			((pAction->btn.flags&XkbSA_LockNoLock)==0)) {
555706f2543Smrg		    xkbi->lockedPtrButtons|= (1<<button);
556706f2543Smrg		    AccessXCancelRepeatKey(xkbi,keycode);
557706f2543Smrg		    XkbFakeDeviceButton(xkbi->device, 1, button);
558706f2543Smrg		    filter->upAction.type= XkbSA_NoAction;
559706f2543Smrg		}
560706f2543Smrg		break;
561706f2543Smrg	    case XkbSA_PtrBtn:
562706f2543Smrg		{
563706f2543Smrg		    register int i,nClicks;
564706f2543Smrg		    AccessXCancelRepeatKey(xkbi,keycode);
565706f2543Smrg		    if (pAction->btn.count>0) {
566706f2543Smrg			nClicks= pAction->btn.count;
567706f2543Smrg			for (i=0;i<nClicks;i++) {
568706f2543Smrg			    XkbFakeDeviceButton(xkbi->device, 1, button);
569706f2543Smrg			    XkbFakeDeviceButton(xkbi->device, 0, button);
570706f2543Smrg			}
571706f2543Smrg			filter->upAction.type= XkbSA_NoAction;
572706f2543Smrg		    }
573706f2543Smrg		    else XkbFakeDeviceButton(xkbi->device, 1, button);
574706f2543Smrg		}
575706f2543Smrg		break;
576706f2543Smrg	    case XkbSA_SetPtrDflt:
577706f2543Smrg		{
578706f2543Smrg		    XkbControlsPtr	ctrls= xkbi->desc->ctrls;
579706f2543Smrg		    XkbControlsRec	old;
580706f2543Smrg		    xkbControlsNotify	cn;
581706f2543Smrg
582706f2543Smrg		    old= *ctrls;
583706f2543Smrg		    AccessXCancelRepeatKey(xkbi,keycode);
584706f2543Smrg		    switch (pAction->dflt.affect) {
585706f2543Smrg			case XkbSA_AffectDfltBtn:
586706f2543Smrg			    if (pAction->dflt.flags&XkbSA_DfltBtnAbsolute)
587706f2543Smrg				ctrls->mk_dflt_btn=
588706f2543Smrg					XkbSAPtrDfltValue(&pAction->dflt);
589706f2543Smrg			    else {
590706f2543Smrg				ctrls->mk_dflt_btn+=
591706f2543Smrg					XkbSAPtrDfltValue(&pAction->dflt);
592706f2543Smrg				if (ctrls->mk_dflt_btn>5)
593706f2543Smrg				    ctrls->mk_dflt_btn= 5;
594706f2543Smrg				else if (ctrls->mk_dflt_btn<1)
595706f2543Smrg				    ctrls->mk_dflt_btn= 1;
596706f2543Smrg			    }
597706f2543Smrg			    break;
598706f2543Smrg			default:
599706f2543Smrg			    ErrorF(
600706f2543Smrg		"Attempt to change unknown pointer default (%d) ignored\n",
601706f2543Smrg							pAction->dflt.affect);
602706f2543Smrg			    break;
603706f2543Smrg		    }
604706f2543Smrg		    if (XkbComputeControlsNotify(xkbi->device,
605706f2543Smrg						&old,xkbi->desc->ctrls,
606706f2543Smrg						&cn,FALSE)) {
607706f2543Smrg			cn.keycode = keycode;
608706f2543Smrg                        /* XXX: what about DeviceKeyPress? */
609706f2543Smrg			cn.eventType = KeyPress;
610706f2543Smrg			cn.requestMajor = 0;
611706f2543Smrg			cn.requestMinor = 0;
612706f2543Smrg			XkbSendControlsNotify(xkbi->device,&cn);
613706f2543Smrg		    }
614706f2543Smrg		}
615706f2543Smrg		break;
616706f2543Smrg	}
617706f2543Smrg    }
618706f2543Smrg    else if (filter->keycode==keycode) {
619706f2543Smrg	int	button= filter->upAction.btn.button;
620706f2543Smrg
621706f2543Smrg	switch (filter->upAction.type) {
622706f2543Smrg	    case XkbSA_LockPtrBtn:
623706f2543Smrg		if (((filter->upAction.btn.flags&XkbSA_LockNoUnlock)!=0)||
624706f2543Smrg				((xkbi->lockedPtrButtons&(1<<button))==0)) {
625706f2543Smrg		    break;
626706f2543Smrg		}
627706f2543Smrg		xkbi->lockedPtrButtons&= ~(1<<button);
628706f2543Smrg
629706f2543Smrg		if (IsMaster(xkbi->device))
630706f2543Smrg		{
631706f2543Smrg		    XkbMergeLockedPtrBtns(xkbi->device);
632706f2543Smrg                    /* One SD still has lock set, don't post event */
633706f2543Smrg		    if ((xkbi->lockedPtrButtons & (1 << button)) != 0)
634706f2543Smrg			break;
635706f2543Smrg		}
636706f2543Smrg
637706f2543Smrg		/* fallthrough */
638706f2543Smrg	    case XkbSA_PtrBtn:
639706f2543Smrg		XkbFakeDeviceButton(xkbi->device, 0, button);
640706f2543Smrg		break;
641706f2543Smrg	}
642706f2543Smrg	filter->active = 0;
643706f2543Smrg    }
644706f2543Smrg    return 0;
645706f2543Smrg}
646706f2543Smrg
647706f2543Smrgstatic int
648706f2543Smrg_XkbFilterControls(	XkbSrvInfoPtr	xkbi,
649706f2543Smrg			XkbFilterPtr	filter,
650706f2543Smrg			unsigned	keycode,
651706f2543Smrg			XkbAction *	pAction)
652706f2543Smrg{
653706f2543SmrgXkbControlsRec		old;
654706f2543SmrgXkbControlsPtr		ctrls;
655706f2543SmrgDeviceIntPtr		kbd;
656706f2543Smrgunsigned int		change;
657706f2543SmrgXkbEventCauseRec	cause;
658706f2543Smrg
659706f2543Smrg    kbd= xkbi->device;
660706f2543Smrg    ctrls= xkbi->desc->ctrls;
661706f2543Smrg    old= *ctrls;
662706f2543Smrg    if (filter->keycode==0) {		/* initial press */
663706f2543Smrg	filter->keycode = keycode;
664706f2543Smrg	filter->active = 1;
665706f2543Smrg	filter->filterOthers = 0;
666706f2543Smrg	change= XkbActionCtrls(&pAction->ctrls);
667706f2543Smrg	filter->priv = change;
668706f2543Smrg	filter->filter = _XkbFilterControls;
669706f2543Smrg	filter->upAction = *pAction;
670706f2543Smrg
671706f2543Smrg	if (pAction->type==XkbSA_LockControls) {
672706f2543Smrg	    filter->priv= (ctrls->enabled_ctrls&change);
673706f2543Smrg	    change&= ~ctrls->enabled_ctrls;
674706f2543Smrg	}
675706f2543Smrg
676706f2543Smrg	if (change) {
677706f2543Smrg	    xkbControlsNotify	cn;
678706f2543Smrg	    XkbSrvLedInfoPtr	sli;
679706f2543Smrg
680706f2543Smrg	    ctrls->enabled_ctrls|= change;
681706f2543Smrg	    if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) {
682706f2543Smrg		cn.keycode = keycode;
683706f2543Smrg                /* XXX: what about DeviceKeyPress? */
684706f2543Smrg		cn.eventType = KeyPress;
685706f2543Smrg		cn.requestMajor = 0;
686706f2543Smrg		cn.requestMinor = 0;
687706f2543Smrg		XkbSendControlsNotify(kbd,&cn);
688706f2543Smrg	    }
689706f2543Smrg
690706f2543Smrg	    XkbSetCauseKey(&cause,keycode,KeyPress);
691706f2543Smrg
692706f2543Smrg	    /* If sticky keys were disabled, clear all locks and latches */
693706f2543Smrg	    if ((old.enabled_ctrls&XkbStickyKeysMask)&&
694706f2543Smrg		(!(ctrls->enabled_ctrls&XkbStickyKeysMask))) {
695706f2543Smrg		XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause);
696706f2543Smrg    	    }
697706f2543Smrg	    sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0);
698706f2543Smrg	    XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause);
699706f2543Smrg	    if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
700706f2543Smrg		XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_ON,change);
701706f2543Smrg	}
702706f2543Smrg    }
703706f2543Smrg    else if (filter->keycode==keycode) {
704706f2543Smrg	change= filter->priv;
705706f2543Smrg	if (change) {
706706f2543Smrg	    xkbControlsNotify 	cn;
707706f2543Smrg	    XkbSrvLedInfoPtr	sli;
708706f2543Smrg
709706f2543Smrg	    ctrls->enabled_ctrls&= ~change;
710706f2543Smrg	    if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) {
711706f2543Smrg		cn.keycode = keycode;
712706f2543Smrg		cn.eventType = KeyRelease;
713706f2543Smrg		cn.requestMajor = 0;
714706f2543Smrg		cn.requestMinor = 0;
715706f2543Smrg		XkbSendControlsNotify(kbd,&cn);
716706f2543Smrg	    }
717706f2543Smrg
718706f2543Smrg	    XkbSetCauseKey(&cause,keycode,KeyRelease);
719706f2543Smrg	    /* If sticky keys were disabled, clear all locks and latches */
720706f2543Smrg	    if ((old.enabled_ctrls&XkbStickyKeysMask)&&
721706f2543Smrg		(!(ctrls->enabled_ctrls&XkbStickyKeysMask))) {
722706f2543Smrg		XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause);
723706f2543Smrg    	    }
724706f2543Smrg	    sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0);
725706f2543Smrg	    XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause);
726706f2543Smrg	    if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
727706f2543Smrg		XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_OFF,change);
728706f2543Smrg	}
729706f2543Smrg	filter->keycode= 0;
730706f2543Smrg	filter->active= 0;
731706f2543Smrg    }
732706f2543Smrg    return 1;
733706f2543Smrg}
734706f2543Smrg
735706f2543Smrgstatic int
736706f2543Smrg_XkbFilterActionMessage(XkbSrvInfoPtr	xkbi,
737706f2543Smrg			XkbFilterPtr	filter,
738706f2543Smrg			unsigned	keycode,
739706f2543Smrg			XkbAction *	pAction)
740706f2543Smrg{
741706f2543SmrgXkbMessageAction *	pMsg;
742706f2543SmrgDeviceIntPtr		kbd;
743706f2543Smrg
744706f2543Smrg    kbd= xkbi->device;
745706f2543Smrg    if (filter->keycode==0) {		/* initial press */
746706f2543Smrg	pMsg= &pAction->msg;
747706f2543Smrg	if ((pMsg->flags&XkbSA_MessageOnRelease)||
748706f2543Smrg	    ((pMsg->flags&XkbSA_MessageGenKeyEvent)==0)) {
749706f2543Smrg	    filter->keycode = keycode;
750706f2543Smrg	    filter->active = 1;
751706f2543Smrg	    filter->filterOthers = 0;
752706f2543Smrg	    filter->priv = 0;
753706f2543Smrg	    filter->filter = _XkbFilterActionMessage;
754706f2543Smrg	    filter->upAction = *pAction;
755706f2543Smrg	}
756706f2543Smrg	if (pMsg->flags&XkbSA_MessageOnPress)  {
757706f2543Smrg	    xkbActionMessage	msg;
758706f2543Smrg
759706f2543Smrg	    msg.keycode= keycode;
760706f2543Smrg	    msg.press= 1;
761706f2543Smrg	    msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
762706f2543Smrg	    memcpy((char *)msg.message,
763706f2543Smrg				(char *)pMsg->message,XkbActionMessageLength);
764706f2543Smrg	    XkbSendActionMessage(kbd,&msg);
765706f2543Smrg	}
766706f2543Smrg	return ((pAction->msg.flags&XkbSA_MessageGenKeyEvent)!=0);
767706f2543Smrg    }
768706f2543Smrg    else if (filter->keycode==keycode) {
769706f2543Smrg	pMsg= &filter->upAction.msg;
770706f2543Smrg	if (pMsg->flags&XkbSA_MessageOnRelease) {
771706f2543Smrg	    xkbActionMessage	msg;
772706f2543Smrg
773706f2543Smrg	    msg.keycode= keycode;
774706f2543Smrg	    msg.press= 0;
775706f2543Smrg	    msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
776706f2543Smrg	    memcpy((char *)msg.message,(char *)pMsg->message,
777706f2543Smrg						XkbActionMessageLength);
778706f2543Smrg	    XkbSendActionMessage(kbd,&msg);
779706f2543Smrg	}
780706f2543Smrg	filter->keycode= 0;
781706f2543Smrg	filter->active= 0;
782706f2543Smrg	return ((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
783706f2543Smrg    }
784706f2543Smrg    return 0;
785706f2543Smrg}
786706f2543Smrg
787706f2543Smrgstatic int
788706f2543Smrg_XkbFilterRedirectKey(	XkbSrvInfoPtr	xkbi,
789706f2543Smrg			XkbFilterPtr	filter,
790706f2543Smrg			unsigned	keycode,
791706f2543Smrg			XkbAction *	pAction)
792706f2543Smrg{
793706f2543SmrgDeviceEvent	ev;
794706f2543Smrgint		x,y;
795706f2543SmrgXkbStateRec	old;
796706f2543Smrgunsigned	mods,mask;
797706f2543SmrgxkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device);
798706f2543SmrgProcessInputProc backupproc;
799706f2543Smrg
800706f2543Smrg    /* never actually used uninitialised, but gcc isn't smart enough
801706f2543Smrg     * to work that out. */
802706f2543Smrg    memset(&old, 0, sizeof(old));
803706f2543Smrg    memset(&ev, 0, sizeof(ev));
804706f2543Smrg
805706f2543Smrg    if ((filter->keycode!=0)&&(filter->keycode!=keycode))
806706f2543Smrg	return 1;
807706f2543Smrg
808706f2543Smrg    GetSpritePosition(xkbi->device, &x,&y);
809706f2543Smrg    ev.header = ET_Internal;
810706f2543Smrg    ev.length = sizeof(DeviceEvent);
811706f2543Smrg    ev.time = GetTimeInMillis();
812706f2543Smrg    ev.root_x = x;
813706f2543Smrg    ev.root_y = y;
814706f2543Smrg
815706f2543Smrg    if (filter->keycode==0) {		/* initial press */
816706f2543Smrg	if ((pAction->redirect.new_key<xkbi->desc->min_key_code)||
817706f2543Smrg	    (pAction->redirect.new_key>xkbi->desc->max_key_code)) {
818706f2543Smrg	    return 1;
819706f2543Smrg	}
820706f2543Smrg	filter->keycode = keycode;
821706f2543Smrg	filter->active = 1;
822706f2543Smrg	filter->filterOthers = 0;
823706f2543Smrg	filter->priv = 0;
824706f2543Smrg	filter->filter = _XkbFilterRedirectKey;
825706f2543Smrg	filter->upAction = *pAction;
826706f2543Smrg
827706f2543Smrg        ev.type = ET_KeyPress;
828706f2543Smrg        ev.detail.key = pAction->redirect.new_key;
829706f2543Smrg
830706f2543Smrg        mask= XkbSARedirectVModsMask(&pAction->redirect);
831706f2543Smrg        mods= XkbSARedirectVMods(&pAction->redirect);
832706f2543Smrg        if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask);
833706f2543Smrg        if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods);
834706f2543Smrg        mask|= pAction->redirect.mods_mask;
835706f2543Smrg        mods|= pAction->redirect.mods;
836706f2543Smrg
837706f2543Smrg	if ( mask || mods ) {
838706f2543Smrg	    old= xkbi->state;
839706f2543Smrg	    xkbi->state.base_mods&= ~mask;
840706f2543Smrg	    xkbi->state.base_mods|= (mods&mask);
841706f2543Smrg	    xkbi->state.latched_mods&= ~mask;
842706f2543Smrg	    xkbi->state.latched_mods|= (mods&mask);
843706f2543Smrg	    xkbi->state.locked_mods&= ~mask;
844706f2543Smrg	    xkbi->state.locked_mods|= (mods&mask);
845706f2543Smrg	    XkbComputeDerivedState(xkbi);
846706f2543Smrg	}
847706f2543Smrg
848706f2543Smrg	UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
849706f2543Smrg	xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
850706f2543Smrg	COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
851706f2543Smrg				     backupproc,xkbUnwrapProc);
852706f2543Smrg
853706f2543Smrg	if ( mask || mods )
854706f2543Smrg	    xkbi->state= old;
855706f2543Smrg    }
856706f2543Smrg    else if (filter->keycode==keycode) {
857706f2543Smrg
858706f2543Smrg        ev.type = ET_KeyRelease;
859706f2543Smrg        ev.detail.key = filter->upAction.redirect.new_key;
860706f2543Smrg
861706f2543Smrg        mask= XkbSARedirectVModsMask(&filter->upAction.redirect);
862706f2543Smrg        mods= XkbSARedirectVMods(&filter->upAction.redirect);
863706f2543Smrg        if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask);
864706f2543Smrg        if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods);
865706f2543Smrg        mask|= filter->upAction.redirect.mods_mask;
866706f2543Smrg        mods|= filter->upAction.redirect.mods;
867706f2543Smrg
868706f2543Smrg	if ( mask || mods ) {
869706f2543Smrg	    old= xkbi->state;
870706f2543Smrg	    xkbi->state.base_mods&= ~mask;
871706f2543Smrg	    xkbi->state.base_mods|= (mods&mask);
872706f2543Smrg	    xkbi->state.latched_mods&= ~mask;
873706f2543Smrg	    xkbi->state.latched_mods|= (mods&mask);
874706f2543Smrg	    xkbi->state.locked_mods&= ~mask;
875706f2543Smrg	    xkbi->state.locked_mods|= (mods&mask);
876706f2543Smrg	    XkbComputeDerivedState(xkbi);
877706f2543Smrg	}
878706f2543Smrg
879706f2543Smrg	UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
880706f2543Smrg	xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
881706f2543Smrg	COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
882706f2543Smrg				     backupproc,xkbUnwrapProc);
883706f2543Smrg
884706f2543Smrg	if ( mask || mods )
885706f2543Smrg	    xkbi->state= old;
886706f2543Smrg
887706f2543Smrg	filter->keycode= 0;
888706f2543Smrg	filter->active= 0;
889706f2543Smrg    }
890706f2543Smrg    return 0;
891706f2543Smrg}
892706f2543Smrg
893706f2543Smrgstatic int
894706f2543Smrg_XkbFilterSwitchScreen(	XkbSrvInfoPtr	xkbi,
895706f2543Smrg			XkbFilterPtr	filter,
896706f2543Smrg			unsigned	keycode,
897706f2543Smrg			XkbAction *	pAction)
898706f2543Smrg{
899706f2543Smrg    DeviceIntPtr dev = xkbi->device;
900706f2543Smrg    if (dev == inputInfo.keyboard)
901706f2543Smrg        return 0;
902706f2543Smrg
903706f2543Smrg    if (filter->keycode==0) {		/* initial press */
904706f2543Smrg	filter->keycode = keycode;
905706f2543Smrg	filter->active = 1;
906706f2543Smrg	filter->filterOthers = 0;
907706f2543Smrg	filter->filter = _XkbFilterSwitchScreen;
908706f2543Smrg	AccessXCancelRepeatKey(xkbi, keycode);
909706f2543Smrg	XkbDDXSwitchScreen(dev,keycode,pAction);
910706f2543Smrg        return 0;
911706f2543Smrg    }
912706f2543Smrg    else if (filter->keycode==keycode) {
913706f2543Smrg	filter->active= 0;
914706f2543Smrg        return 0;
915706f2543Smrg    }
916706f2543Smrg    return 1;
917706f2543Smrg}
918706f2543Smrg
919706f2543Smrgstatic int
920706f2543Smrg_XkbFilterXF86Private(	XkbSrvInfoPtr	xkbi,
921706f2543Smrg			XkbFilterPtr	filter,
922706f2543Smrg			unsigned	keycode,
923706f2543Smrg			XkbAction *	pAction)
924706f2543Smrg{
925706f2543Smrg    DeviceIntPtr dev = xkbi->device;
926706f2543Smrg    if (dev == inputInfo.keyboard)
927706f2543Smrg        return 0;
928706f2543Smrg
929706f2543Smrg    if (filter->keycode==0) {		/* initial press */
930706f2543Smrg	filter->keycode = keycode;
931706f2543Smrg	filter->active = 1;
932706f2543Smrg	filter->filterOthers = 0;
933706f2543Smrg	filter->filter = _XkbFilterXF86Private;
934706f2543Smrg	XkbDDXPrivate(dev,keycode,pAction);
935706f2543Smrg        return 0;
936706f2543Smrg    }
937706f2543Smrg    else if (filter->keycode==keycode) {
938706f2543Smrg	filter->active= 0;
939706f2543Smrg        return 0;
940706f2543Smrg    }
941706f2543Smrg    return 1;
942706f2543Smrg}
943706f2543Smrg
944706f2543Smrg
945706f2543Smrgstatic int
946706f2543Smrg_XkbFilterDeviceBtn(	XkbSrvInfoPtr	xkbi,
947706f2543Smrg			XkbFilterPtr	filter,
948706f2543Smrg			unsigned	keycode,
949706f2543Smrg			XkbAction *	pAction)
950706f2543Smrg{
951706f2543SmrgDeviceIntPtr	dev;
952706f2543Smrgint		button;
953706f2543Smrg
954706f2543Smrg    if (xkbi->device == inputInfo.keyboard)
955706f2543Smrg        return 0;
956706f2543Smrg
957706f2543Smrg    if (filter->keycode==0) {		/* initial press */
958706f2543Smrg	_XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient,
959706f2543Smrg			       DixUnknownAccess, &button);
960706f2543Smrg	if (!dev || !dev->public.on)
961706f2543Smrg	    return 1;
962706f2543Smrg
963706f2543Smrg	button= pAction->devbtn.button;
964706f2543Smrg	if ((button<1)||(button>dev->button->numButtons))
965706f2543Smrg	    return 1;
966706f2543Smrg
967706f2543Smrg	filter->keycode = keycode;
968706f2543Smrg	filter->active = 1;
969706f2543Smrg	filter->filterOthers = 0;
970706f2543Smrg	filter->priv=0;
971706f2543Smrg	filter->filter = _XkbFilterDeviceBtn;
972706f2543Smrg	filter->upAction= *pAction;
973706f2543Smrg	switch (pAction->type) {
974706f2543Smrg	    case XkbSA_LockDeviceBtn:
975706f2543Smrg		if ((pAction->devbtn.flags&XkbSA_LockNoLock)||
976706f2543Smrg		    BitIsOn(dev->button->down, button))
977706f2543Smrg		    return 0;
978706f2543Smrg		XkbFakeDeviceButton(dev,TRUE,button);
979706f2543Smrg		filter->upAction.type= XkbSA_NoAction;
980706f2543Smrg		break;
981706f2543Smrg	    case XkbSA_DeviceBtn:
982706f2543Smrg		if (pAction->devbtn.count>0) {
983706f2543Smrg		    int nClicks,i;
984706f2543Smrg		    nClicks= pAction->btn.count;
985706f2543Smrg		    for (i=0;i<nClicks;i++) {
986706f2543Smrg			XkbFakeDeviceButton(dev,TRUE,button);
987706f2543Smrg			XkbFakeDeviceButton(dev,FALSE,button);
988706f2543Smrg		    }
989706f2543Smrg		    filter->upAction.type= XkbSA_NoAction;
990706f2543Smrg		}
991706f2543Smrg		else XkbFakeDeviceButton(dev,TRUE,button);
992706f2543Smrg		break;
993706f2543Smrg	}
994706f2543Smrg    }
995706f2543Smrg    else if (filter->keycode==keycode) {
996706f2543Smrg	int	button;
997706f2543Smrg
998706f2543Smrg	filter->active= 0;
999706f2543Smrg	_XkbLookupButtonDevice(&dev, filter->upAction.devbtn.device,
1000706f2543Smrg			       serverClient, DixUnknownAccess, &button);
1001706f2543Smrg	if (!dev || !dev->public.on)
1002706f2543Smrg	    return 1;
1003706f2543Smrg
1004706f2543Smrg	button= filter->upAction.btn.button;
1005706f2543Smrg	switch (filter->upAction.type) {
1006706f2543Smrg	    case XkbSA_LockDeviceBtn:
1007706f2543Smrg		if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)||
1008706f2543Smrg		    !BitIsOn(dev->button->down, button))
1009706f2543Smrg		    return 0;
1010706f2543Smrg		XkbFakeDeviceButton(dev,FALSE,button);
1011706f2543Smrg		break;
1012706f2543Smrg	    case XkbSA_DeviceBtn:
1013706f2543Smrg		XkbFakeDeviceButton(dev,FALSE,button);
1014706f2543Smrg		break;
1015706f2543Smrg	}
1016706f2543Smrg	filter->active = 0;
1017706f2543Smrg    }
1018706f2543Smrg    return 0;
1019706f2543Smrg}
1020706f2543Smrg
1021706f2543Smrgstatic XkbFilterPtr
1022706f2543Smrg_XkbNextFreeFilter(
1023706f2543Smrg	XkbSrvInfoPtr xkbi
1024706f2543Smrg)
1025706f2543Smrg{
1026706f2543Smrgregister int	i;
1027706f2543Smrg
1028706f2543Smrg    if (xkbi->szFilters==0) {
1029706f2543Smrg	xkbi->szFilters = 4;
1030706f2543Smrg	xkbi->filters = calloc(xkbi->szFilters, sizeof(XkbFilterRec));
1031706f2543Smrg	/* 6/21/93 (ef) -- XXX! deal with allocation failure */
1032706f2543Smrg    }
1033706f2543Smrg    for (i=0;i<xkbi->szFilters;i++) {
1034706f2543Smrg	if (!xkbi->filters[i].active) {
1035706f2543Smrg	    xkbi->filters[i].keycode = 0;
1036706f2543Smrg	    return &xkbi->filters[i];
1037706f2543Smrg	}
1038706f2543Smrg    }
1039706f2543Smrg    xkbi->szFilters*=2;
1040706f2543Smrg    xkbi->filters= realloc(xkbi->filters,
1041706f2543Smrg                            xkbi->szFilters * sizeof(XkbFilterRec));
1042706f2543Smrg    /* 6/21/93 (ef) -- XXX! deal with allocation failure */
1043706f2543Smrg    memset(&xkbi->filters[xkbi->szFilters/2], 0,
1044706f2543Smrg            (xkbi->szFilters/2)*sizeof(XkbFilterRec));
1045706f2543Smrg    return &xkbi->filters[xkbi->szFilters/2];
1046706f2543Smrg}
1047706f2543Smrg
1048706f2543Smrgstatic int
1049706f2543Smrg_XkbApplyFilters(XkbSrvInfoPtr xkbi,unsigned kc,XkbAction *pAction)
1050706f2543Smrg{
1051706f2543Smrgregister int	i,send;
1052706f2543Smrg
1053706f2543Smrg    send= 1;
1054706f2543Smrg    for (i=0;i<xkbi->szFilters;i++) {
1055706f2543Smrg	if ((xkbi->filters[i].active)&&(xkbi->filters[i].filter))
1056706f2543Smrg	    send= ((*xkbi->filters[i].filter)(xkbi,&xkbi->filters[i],kc,pAction)
1057706f2543Smrg                    && send);
1058706f2543Smrg    }
1059706f2543Smrg    return send;
1060706f2543Smrg}
1061706f2543Smrg
1062706f2543Smrgvoid
1063706f2543SmrgXkbHandleActions(DeviceIntPtr dev, DeviceIntPtr kbd, DeviceEvent* event)
1064706f2543Smrg{
1065706f2543Smrgint		key,bit,i;
1066706f2543SmrgXkbSrvInfoPtr	xkbi;
1067706f2543SmrgKeyClassPtr	keyc;
1068706f2543Smrgint		changed,sendEvent;
1069706f2543SmrgBool		genStateNotify;
1070706f2543SmrgXkbAction	act;
1071706f2543SmrgXkbFilterPtr	filter;
1072706f2543SmrgBool		keyEvent;
1073706f2543SmrgBool		pressEvent;
1074706f2543SmrgProcessInputProc backupproc;
1075706f2543Smrg
1076706f2543SmrgxkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
1077706f2543Smrg
1078706f2543Smrg    keyc= kbd->key;
1079706f2543Smrg    xkbi= keyc->xkbInfo;
1080706f2543Smrg    key= event->detail.key;
1081706f2543Smrg    /* The state may change, so if we're not in the middle of sending a state
1082706f2543Smrg     * notify, prepare for it */
1083706f2543Smrg    if ((xkbi->flags&_XkbStateNotifyInProgress)==0) {
1084706f2543Smrg	xkbi->prev_state = xkbi->state;
1085706f2543Smrg	xkbi->flags|= _XkbStateNotifyInProgress;
1086706f2543Smrg	genStateNotify= TRUE;
1087706f2543Smrg    }
1088706f2543Smrg    else genStateNotify= FALSE;
1089706f2543Smrg
1090706f2543Smrg    xkbi->clearMods = xkbi->setMods = 0;
1091706f2543Smrg    xkbi->groupChange = 0;
1092706f2543Smrg
1093706f2543Smrg    sendEvent = 1;
1094706f2543Smrg    keyEvent= ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease));
1095706f2543Smrg    pressEvent= ((event->type == ET_KeyPress)|| (event->type == ET_ButtonPress));
1096706f2543Smrg
1097706f2543Smrg    if (pressEvent) {
1098706f2543Smrg	if (keyEvent)
1099706f2543Smrg	    act = XkbGetKeyAction(xkbi,&xkbi->state,key);
1100706f2543Smrg	else {
1101706f2543Smrg	    act = XkbGetButtonAction(kbd,dev,key);
1102706f2543Smrg	    key|= BTN_ACT_FLAG;
1103706f2543Smrg	}
1104706f2543Smrg	sendEvent = _XkbApplyFilters(xkbi,key,&act);
1105706f2543Smrg	if (sendEvent) {
1106706f2543Smrg	    switch (act.type) {
1107706f2543Smrg		case XkbSA_SetMods:
1108706f2543Smrg		case XkbSA_SetGroup:
1109706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1110706f2543Smrg		    sendEvent = _XkbFilterSetState(xkbi,filter,key,&act);
1111706f2543Smrg		    break;
1112706f2543Smrg		case XkbSA_LatchMods:
1113706f2543Smrg		case XkbSA_LatchGroup:
1114706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1115706f2543Smrg		    sendEvent=_XkbFilterLatchState(xkbi,filter,key,&act);
1116706f2543Smrg		    break;
1117706f2543Smrg		case XkbSA_LockMods:
1118706f2543Smrg		case XkbSA_LockGroup:
1119706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1120706f2543Smrg		    sendEvent=_XkbFilterLockState(xkbi,filter,key,&act);
1121706f2543Smrg		    break;
1122706f2543Smrg		case XkbSA_ISOLock:
1123706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1124706f2543Smrg		    sendEvent=_XkbFilterISOLock(xkbi,filter,key,&act);
1125706f2543Smrg		    break;
1126706f2543Smrg		case XkbSA_MovePtr:
1127706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1128706f2543Smrg		    sendEvent= _XkbFilterPointerMove(xkbi,filter,key,&act);
1129706f2543Smrg		    break;
1130706f2543Smrg		case XkbSA_PtrBtn:
1131706f2543Smrg		case XkbSA_LockPtrBtn:
1132706f2543Smrg		case XkbSA_SetPtrDflt:
1133706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1134706f2543Smrg		    sendEvent= _XkbFilterPointerBtn(xkbi,filter,key,&act);
1135706f2543Smrg		    break;
1136706f2543Smrg		case XkbSA_Terminate:
1137706f2543Smrg		    sendEvent= XkbDDXTerminateServer(dev,key,&act);
1138706f2543Smrg		    break;
1139706f2543Smrg		case XkbSA_SwitchScreen:
1140706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1141706f2543Smrg		    sendEvent=_XkbFilterSwitchScreen(xkbi,filter,key,&act);
1142706f2543Smrg		    break;
1143706f2543Smrg		case XkbSA_SetControls:
1144706f2543Smrg		case XkbSA_LockControls:
1145706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1146706f2543Smrg		    sendEvent=_XkbFilterControls(xkbi,filter,key,&act);
1147706f2543Smrg		    break;
1148706f2543Smrg		case XkbSA_ActionMessage:
1149706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1150706f2543Smrg		    sendEvent=_XkbFilterActionMessage(xkbi,filter,key,&act);
1151706f2543Smrg		    break;
1152706f2543Smrg		case XkbSA_RedirectKey:
1153706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1154706f2543Smrg		    sendEvent= _XkbFilterRedirectKey(xkbi,filter,key,&act);
1155706f2543Smrg		    break;
1156706f2543Smrg		case XkbSA_DeviceBtn:
1157706f2543Smrg		case XkbSA_LockDeviceBtn:
1158706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1159706f2543Smrg		    sendEvent= _XkbFilterDeviceBtn(xkbi,filter,key,&act);
1160706f2543Smrg		    break;
1161706f2543Smrg		case XkbSA_XFree86Private:
1162706f2543Smrg		    filter = _XkbNextFreeFilter(xkbi);
1163706f2543Smrg		    sendEvent= _XkbFilterXF86Private(xkbi,filter,key,&act);
1164706f2543Smrg		    break;
1165706f2543Smrg	    }
1166706f2543Smrg	}
1167706f2543Smrg    }
1168706f2543Smrg    else {
1169706f2543Smrg	if (!keyEvent)
1170706f2543Smrg	    key|= BTN_ACT_FLAG;
1171706f2543Smrg	sendEvent = _XkbApplyFilters(xkbi,key,NULL);
1172706f2543Smrg    }
1173706f2543Smrg
1174706f2543Smrg    if (xkbi->groupChange!=0)
1175706f2543Smrg	xkbi->state.base_group+= xkbi->groupChange;
1176706f2543Smrg    if (xkbi->setMods) {
1177706f2543Smrg	for (i=0,bit=1; xkbi->setMods; i++,bit<<=1 ) {
1178706f2543Smrg	    if (xkbi->setMods&bit) {
1179706f2543Smrg		keyc->modifierKeyCount[i]++;
1180706f2543Smrg		xkbi->state.base_mods|= bit;
1181706f2543Smrg		xkbi->setMods&= ~bit;
1182706f2543Smrg	    }
1183706f2543Smrg	}
1184706f2543Smrg    }
1185706f2543Smrg    if (xkbi->clearMods) {
1186706f2543Smrg	for (i=0,bit=1; xkbi->clearMods; i++,bit<<=1 ) {
1187706f2543Smrg	    if (xkbi->clearMods&bit) {
1188706f2543Smrg		keyc->modifierKeyCount[i]--;
1189706f2543Smrg		if (keyc->modifierKeyCount[i]<=0) {
1190706f2543Smrg		    xkbi->state.base_mods&= ~bit;
1191706f2543Smrg		    keyc->modifierKeyCount[i] = 0;
1192706f2543Smrg		}
1193706f2543Smrg		xkbi->clearMods&= ~bit;
1194706f2543Smrg	    }
1195706f2543Smrg	}
1196706f2543Smrg    }
1197706f2543Smrg
1198706f2543Smrg    if (sendEvent) {
1199706f2543Smrg        DeviceIntPtr tmpdev;
1200706f2543Smrg	if (keyEvent)
1201706f2543Smrg            tmpdev = dev;
1202706f2543Smrg        else
1203706f2543Smrg            tmpdev = GetPairedDevice(dev);
1204706f2543Smrg
1205706f2543Smrg        UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc);
1206706f2543Smrg        dev->public.processInputProc((InternalEvent*)event, tmpdev);
1207706f2543Smrg        COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr,
1208706f2543Smrg                                     backupproc,xkbUnwrapProc);
1209706f2543Smrg    }
1210706f2543Smrg    else if (keyEvent) {
1211706f2543Smrg	FixKeyState(event, dev);
1212706f2543Smrg    }
1213706f2543Smrg
1214706f2543Smrg    XkbComputeDerivedState(xkbi);
1215706f2543Smrg    changed = XkbStateChangedFlags(&xkbi->prev_state,&xkbi->state);
1216706f2543Smrg    if (genStateNotify) {
1217706f2543Smrg	if (changed) {
1218706f2543Smrg	    xkbStateNotify	sn;
1219706f2543Smrg	    sn.keycode= key;
1220706f2543Smrg	    sn.eventType= event->type;
1221706f2543Smrg	    sn.requestMajor = sn.requestMinor = 0;
1222706f2543Smrg	    sn.changed= changed;
1223706f2543Smrg	    XkbSendStateNotify(dev,&sn);
1224706f2543Smrg	}
1225706f2543Smrg	xkbi->flags&= ~_XkbStateNotifyInProgress;
1226706f2543Smrg    }
1227706f2543Smrg    changed= XkbIndicatorsToUpdate(dev,changed,FALSE);
1228706f2543Smrg    if (changed) {
1229706f2543Smrg	XkbEventCauseRec	cause;
1230706f2543Smrg	XkbSetCauseKey(&cause, key, event->type);
1231706f2543Smrg	XkbUpdateIndicators(dev,changed,FALSE,NULL,&cause);
1232706f2543Smrg    }
1233706f2543Smrg    return;
1234706f2543Smrg}
1235706f2543Smrg
1236706f2543Smrgint
1237706f2543SmrgXkbLatchModifiers(DeviceIntPtr pXDev,CARD8 mask,CARD8 latches)
1238706f2543Smrg{
1239706f2543SmrgXkbSrvInfoPtr	xkbi;
1240706f2543SmrgXkbFilterPtr	filter;
1241706f2543SmrgXkbAction	act;
1242706f2543Smrgunsigned	clear;
1243706f2543Smrg
1244706f2543Smrg    if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) {
1245706f2543Smrg	xkbi = pXDev->key->xkbInfo;
1246706f2543Smrg	clear= (mask&(~latches));
1247706f2543Smrg	xkbi->state.latched_mods&= ~clear;
1248706f2543Smrg	/* Clear any pending latch to locks.
1249706f2543Smrg	 */
1250706f2543Smrg	act.type = XkbSA_NoAction;
1251706f2543Smrg	_XkbApplyFilters(xkbi,SYNTHETIC_KEYCODE,&act);
1252706f2543Smrg	act.type = XkbSA_LatchMods;
1253706f2543Smrg	act.mods.flags = 0;
1254706f2543Smrg	act.mods.mask  = mask&latches;
1255706f2543Smrg	filter = _XkbNextFreeFilter(xkbi);
1256706f2543Smrg	_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act);
1257706f2543Smrg	_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL);
1258706f2543Smrg	return Success;
1259706f2543Smrg    }
1260706f2543Smrg    return BadValue;
1261706f2543Smrg}
1262706f2543Smrg
1263706f2543Smrgint
1264706f2543SmrgXkbLatchGroup(DeviceIntPtr pXDev,int group)
1265706f2543Smrg{
1266706f2543SmrgXkbSrvInfoPtr	xkbi;
1267706f2543SmrgXkbFilterPtr	filter;
1268706f2543SmrgXkbAction	act;
1269706f2543Smrg
1270706f2543Smrg    if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) {
1271706f2543Smrg	xkbi = pXDev->key->xkbInfo;
1272706f2543Smrg	act.type = XkbSA_LatchGroup;
1273706f2543Smrg	act.group.flags = 0;
1274706f2543Smrg	XkbSASetGroup(&act.group,group);
1275706f2543Smrg	filter = _XkbNextFreeFilter(xkbi);
1276706f2543Smrg	_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act);
1277706f2543Smrg	_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL);
1278706f2543Smrg	return Success;
1279706f2543Smrg    }
1280706f2543Smrg    return BadValue;
1281706f2543Smrg}
1282706f2543Smrg
1283706f2543Smrg/***====================================================================***/
1284706f2543Smrg
1285706f2543Smrgvoid
1286706f2543SmrgXkbClearAllLatchesAndLocks(	DeviceIntPtr		dev,
1287706f2543Smrg				XkbSrvInfoPtr		xkbi,
1288706f2543Smrg				Bool			genEv,
1289706f2543Smrg				XkbEventCausePtr	cause)
1290706f2543Smrg{
1291706f2543SmrgXkbStateRec	os;
1292706f2543SmrgxkbStateNotify	sn;
1293706f2543Smrg
1294706f2543Smrg    sn.changed= 0;
1295706f2543Smrg    os= xkbi->state;
1296706f2543Smrg    if (os.latched_mods) { /* clear all latches */
1297706f2543Smrg	XkbLatchModifiers(dev,~0,0);
1298706f2543Smrg	sn.changed|= XkbModifierLatchMask;
1299706f2543Smrg    }
1300706f2543Smrg    if (os.latched_group) {
1301706f2543Smrg	XkbLatchGroup(dev,0);
1302706f2543Smrg	sn.changed|= XkbGroupLatchMask;
1303706f2543Smrg    }
1304706f2543Smrg    if (os.locked_mods) {
1305706f2543Smrg	xkbi->state.locked_mods= 0;
1306706f2543Smrg	sn.changed|= XkbModifierLockMask;
1307706f2543Smrg    }
1308706f2543Smrg    if (os.locked_group) {
1309706f2543Smrg	xkbi->state.locked_group= 0;
1310706f2543Smrg	sn.changed|= XkbGroupLockMask;
1311706f2543Smrg    }
1312706f2543Smrg    if ( genEv && sn.changed) {
1313706f2543Smrg	CARD32 	changed;
1314706f2543Smrg
1315706f2543Smrg	XkbComputeDerivedState(xkbi);
1316706f2543Smrg	sn.keycode= 		cause->kc;
1317706f2543Smrg	sn.eventType=		cause->event;
1318706f2543Smrg	sn.requestMajor= 	cause->mjr;
1319706f2543Smrg	sn.requestMinor= 	cause->mnr;
1320706f2543Smrg	sn.changed= XkbStateChangedFlags(&os,&xkbi->state);
1321706f2543Smrg	XkbSendStateNotify(dev,&sn);
1322706f2543Smrg	changed= XkbIndicatorsToUpdate(dev,sn.changed,FALSE);
1323706f2543Smrg	if (changed) {
1324706f2543Smrg	    XkbUpdateIndicators(dev,changed,TRUE,NULL,cause);
1325706f2543Smrg	}
1326706f2543Smrg    }
1327706f2543Smrg    return;
1328706f2543Smrg}
1329706f2543Smrg
1330706f2543Smrg/*
1331706f2543Smrg * The event is injected into the event processing, not the EQ. Thus,
1332706f2543Smrg * ensure that we restore the master after the event sequence to the
1333706f2543Smrg * original set of classes. Otherwise, the master remains on the XTEST
1334706f2543Smrg * classes and drops events that don't fit into the XTEST layout (e.g.
1335706f2543Smrg * events with more than 2 valuators).
1336706f2543Smrg *
1337706f2543Smrg * FIXME: EQ injection in the processing stage is not designed for, so this
1338706f2543Smrg * is a rather awkward hack. The event list returned by GetPointerEvents()
1339706f2543Smrg * and friends is always prefixed with a DCE if the last _posted_ device was
1340706f2543Smrg * different. For normal events, this sequence then resets the master during
1341706f2543Smrg * the processing stage. Since we inject the PointerKey events in the
1342706f2543Smrg * processing stage though, we need to manually reset to restore the
1343706f2543Smrg * previous order, because the events already in the EQ must be sent for the
1344706f2543Smrg * right device.
1345706f2543Smrg * So we post-fix the event list we get from GPE with a DCE back to the
1346706f2543Smrg * previous slave device.
1347706f2543Smrg *
1348706f2543Smrg * First one on drinking island wins!
1349706f2543Smrg */
1350706f2543Smrgstatic void
1351706f2543SmrgInjectPointerKeyEvents(DeviceIntPtr dev, int type, int button, int flags, ValuatorMask *mask)
1352706f2543Smrg{
1353706f2543Smrg    ScreenPtr           pScreen;
1354706f2543Smrg    EventListPtr        events;
1355706f2543Smrg    int                 nevents, i;
1356706f2543Smrg    DeviceIntPtr        ptr, mpointer, lastSlave = NULL;
1357706f2543Smrg    Bool                saveWait;
1358706f2543Smrg
1359706f2543Smrg    if (IsMaster(dev)) {
1360706f2543Smrg        mpointer = GetMaster(dev, MASTER_POINTER);
1361706f2543Smrg        lastSlave = mpointer->u.lastSlave;
1362706f2543Smrg        ptr = GetXTestDevice(mpointer);
1363706f2543Smrg    } else if (!dev->u.master)
1364706f2543Smrg        ptr = dev;
1365706f2543Smrg    else
1366706f2543Smrg        return;
1367706f2543Smrg
1368706f2543Smrg
1369706f2543Smrg    events = InitEventList(GetMaximumEventsNum() + 1);
1370706f2543Smrg    OsBlockSignals();
1371706f2543Smrg    pScreen = miPointerGetScreen(ptr);
1372706f2543Smrg    saveWait = miPointerSetWaitForUpdate(pScreen, FALSE);
1373706f2543Smrg    nevents = GetPointerEvents(events, ptr, type, button, flags, mask);
1374706f2543Smrg    if (IsMaster(dev) && (lastSlave && lastSlave != ptr))
1375706f2543Smrg        UpdateFromMaster(&events[nevents], lastSlave, DEVCHANGE_POINTER_EVENT, &nevents);
1376706f2543Smrg    miPointerSetWaitForUpdate(pScreen, saveWait);
1377706f2543Smrg    OsReleaseSignals();
1378706f2543Smrg
1379706f2543Smrg    for (i = 0; i < nevents; i++)
1380706f2543Smrg        mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
1381706f2543Smrg
1382706f2543Smrg    FreeEventList(events, GetMaximumEventsNum());
1383706f2543Smrg
1384706f2543Smrg}
1385706f2543Smrg
1386706f2543Smrgstatic void
1387706f2543SmrgXkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
1388706f2543Smrg{
1389706f2543Smrg    ValuatorMask        mask;
1390706f2543Smrg    int                 gpe_flags = 0;
1391706f2543Smrg
1392706f2543Smrg    /* ignore attached SDs */
1393706f2543Smrg    if (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) != NULL)
1394706f2543Smrg        return;
1395706f2543Smrg
1396706f2543Smrg    if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
1397706f2543Smrg        gpe_flags = POINTER_ABSOLUTE;
1398706f2543Smrg    else
1399706f2543Smrg        gpe_flags = POINTER_RELATIVE;
1400706f2543Smrg
1401706f2543Smrg    valuator_mask_set_range(&mask, 0, 2, (int[]){x, y});
1402706f2543Smrg
1403706f2543Smrg    InjectPointerKeyEvents(dev, MotionNotify, 0, gpe_flags, &mask);
1404706f2543Smrg}
1405706f2543Smrg
1406706f2543Smrgvoid
1407706f2543SmrgXkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
1408706f2543Smrg{
1409706f2543Smrg    DeviceIntPtr        ptr;
1410706f2543Smrg    int                 down;
1411706f2543Smrg
1412706f2543Smrg    /* If dev is a slave device, and the SD is attached, do nothing. If we'd
1413706f2543Smrg     * post through the attached master pointer we'd get duplicate events.
1414706f2543Smrg     *
1415706f2543Smrg     * if dev is a master keyboard, post through the XTEST device
1416706f2543Smrg     *
1417706f2543Smrg     * if dev is a floating slave, post through the device itself.
1418706f2543Smrg     */
1419706f2543Smrg
1420706f2543Smrg    if (IsMaster(dev)) {
1421706f2543Smrg        DeviceIntPtr mpointer = GetMaster(dev, MASTER_POINTER);
1422706f2543Smrg        ptr = GetXTestDevice(mpointer);
1423706f2543Smrg    } else if (!dev->u.master)
1424706f2543Smrg        ptr = dev;
1425706f2543Smrg    else
1426706f2543Smrg        return;
1427706f2543Smrg
1428706f2543Smrg    down = button_is_down(ptr, button, BUTTON_PROCESSED);
1429706f2543Smrg    if (press == down)
1430706f2543Smrg        return;
1431706f2543Smrg
1432706f2543Smrg    InjectPointerKeyEvents(dev, press ? ButtonPress : ButtonRelease,
1433706f2543Smrg                           button, 0, NULL);
1434706f2543Smrg}
1435