xref: /OK3568_Linux_fs/external/xserver/xkb/xkbAccessX.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /************************************************************
2*4882a593Smuzhiyun Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this
5*4882a593Smuzhiyun software and its documentation for any purpose and without
6*4882a593Smuzhiyun fee is hereby granted, provided that the above copyright
7*4882a593Smuzhiyun notice appear in all copies and that both that copyright
8*4882a593Smuzhiyun notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation, and that the name of Silicon Graphics not be
10*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution
11*4882a593Smuzhiyun of the software without specific prior written permission.
12*4882a593Smuzhiyun Silicon Graphics makes no representation about the suitability
13*4882a593Smuzhiyun of this software for any purpose. It is provided "as is"
14*4882a593Smuzhiyun without any express or implied warranty.
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17*4882a593Smuzhiyun SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18*4882a593Smuzhiyun AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19*4882a593Smuzhiyun GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20*4882a593Smuzhiyun DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21*4882a593Smuzhiyun DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22*4882a593Smuzhiyun OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23*4882a593Smuzhiyun THE USE OR PERFORMANCE OF THIS SOFTWARE.
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun ********************************************************/
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
28*4882a593Smuzhiyun #include <dix-config.h>
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <stdio.h>
32*4882a593Smuzhiyun #include <math.h>
33*4882a593Smuzhiyun #include <X11/X.h>
34*4882a593Smuzhiyun #include <X11/Xproto.h>
35*4882a593Smuzhiyun #include <X11/keysym.h>
36*4882a593Smuzhiyun #include "exglobals.h"
37*4882a593Smuzhiyun #include <X11/extensions/XIproto.h>
38*4882a593Smuzhiyun #include "inputstr.h"
39*4882a593Smuzhiyun #include "eventstr.h"
40*4882a593Smuzhiyun #include "inpututils.h"
41*4882a593Smuzhiyun #include <xkbsrv.h>
42*4882a593Smuzhiyun #if !defined(WIN32)
43*4882a593Smuzhiyun #include <sys/time.h>
44*4882a593Smuzhiyun #endif
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun int XkbDfltRepeatDelay = 660;
47*4882a593Smuzhiyun int XkbDfltRepeatInterval = 40;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #define	DFLT_TIMEOUT_CTRLS (XkbAX_KRGMask|XkbStickyKeysMask|XkbMouseKeysMask)
50*4882a593Smuzhiyun #define	DFLT_TIMEOUT_OPTS  (XkbAX_IndicatorFBMask)
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun unsigned short XkbDfltAccessXTimeout = 120;
53*4882a593Smuzhiyun unsigned int XkbDfltAccessXTimeoutMask = DFLT_TIMEOUT_CTRLS;
54*4882a593Smuzhiyun static unsigned int XkbDfltAccessXTimeoutValues = 0;
55*4882a593Smuzhiyun static unsigned int XkbDfltAccessXTimeoutOptionsMask = DFLT_TIMEOUT_OPTS;
56*4882a593Smuzhiyun static unsigned int XkbDfltAccessXTimeoutOptionsValues = 0;
57*4882a593Smuzhiyun unsigned int XkbDfltAccessXFeedback = XkbAccessXFeedbackMask;
58*4882a593Smuzhiyun unsigned short XkbDfltAccessXOptions =
59*4882a593Smuzhiyun     XkbAX_AllOptionsMask & ~(XkbAX_IndicatorFBMask | XkbAX_SKReleaseFBMask |
60*4882a593Smuzhiyun                              XkbAX_SKRejectFBMask);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun void
AccessXComputeCurveFactor(XkbSrvInfoPtr xkbi,XkbControlsPtr ctrls)63*4882a593Smuzhiyun AccessXComputeCurveFactor(XkbSrvInfoPtr xkbi, XkbControlsPtr ctrls)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun     xkbi->mouseKeysCurve = 1.0 + (((double) ctrls->mk_curve) * 0.001);
66*4882a593Smuzhiyun     xkbi->mouseKeysCurveFactor = (((double) ctrls->mk_max_speed) /
67*4882a593Smuzhiyun                                   pow((double) ctrls->mk_time_to_max,
68*4882a593Smuzhiyun                                       xkbi->mouseKeysCurve));
69*4882a593Smuzhiyun     return;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun void
AccessXInit(DeviceIntPtr keybd)73*4882a593Smuzhiyun AccessXInit(DeviceIntPtr keybd)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = keybd->key->xkbInfo;
76*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun     xkbi->shiftKeyCount = 0;
79*4882a593Smuzhiyun     xkbi->mouseKeysCounter = 0;
80*4882a593Smuzhiyun     xkbi->inactiveKey = 0;
81*4882a593Smuzhiyun     xkbi->slowKey = 0;
82*4882a593Smuzhiyun     xkbi->repeatKey = 0;
83*4882a593Smuzhiyun     xkbi->krgTimerActive = _OFF_TIMER;
84*4882a593Smuzhiyun     xkbi->beepType = _BEEP_NONE;
85*4882a593Smuzhiyun     xkbi->beepCount = 0;
86*4882a593Smuzhiyun     xkbi->mouseKeyTimer = NULL;
87*4882a593Smuzhiyun     xkbi->slowKeysTimer = NULL;
88*4882a593Smuzhiyun     xkbi->bounceKeysTimer = NULL;
89*4882a593Smuzhiyun     xkbi->repeatKeyTimer = NULL;
90*4882a593Smuzhiyun     xkbi->krgTimer = NULL;
91*4882a593Smuzhiyun     xkbi->beepTimer = NULL;
92*4882a593Smuzhiyun     xkbi->checkRepeat = NULL;
93*4882a593Smuzhiyun     ctrls->repeat_delay = XkbDfltRepeatDelay;
94*4882a593Smuzhiyun     ctrls->repeat_interval = XkbDfltRepeatInterval;
95*4882a593Smuzhiyun     ctrls->debounce_delay = 300;
96*4882a593Smuzhiyun     ctrls->slow_keys_delay = 300;
97*4882a593Smuzhiyun     ctrls->mk_delay = 160;
98*4882a593Smuzhiyun     ctrls->mk_interval = 40;
99*4882a593Smuzhiyun     ctrls->mk_time_to_max = 30;
100*4882a593Smuzhiyun     ctrls->mk_max_speed = 30;
101*4882a593Smuzhiyun     ctrls->mk_curve = 500;
102*4882a593Smuzhiyun     ctrls->mk_dflt_btn = 1;
103*4882a593Smuzhiyun     ctrls->ax_timeout = XkbDfltAccessXTimeout;
104*4882a593Smuzhiyun     ctrls->axt_ctrls_mask = XkbDfltAccessXTimeoutMask;
105*4882a593Smuzhiyun     ctrls->axt_ctrls_values = XkbDfltAccessXTimeoutValues;
106*4882a593Smuzhiyun     ctrls->axt_opts_mask = XkbDfltAccessXTimeoutOptionsMask;
107*4882a593Smuzhiyun     ctrls->axt_opts_values = XkbDfltAccessXTimeoutOptionsValues;
108*4882a593Smuzhiyun     if (XkbDfltAccessXTimeout)
109*4882a593Smuzhiyun         ctrls->enabled_ctrls |= XkbAccessXTimeoutMask;
110*4882a593Smuzhiyun     else
111*4882a593Smuzhiyun         ctrls->enabled_ctrls &= ~XkbAccessXTimeoutMask;
112*4882a593Smuzhiyun     ctrls->enabled_ctrls |= XkbDfltAccessXFeedback;
113*4882a593Smuzhiyun     ctrls->ax_options = XkbDfltAccessXOptions;
114*4882a593Smuzhiyun     AccessXComputeCurveFactor(xkbi, ctrls);
115*4882a593Smuzhiyun     return;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun /************************************************************************/
119*4882a593Smuzhiyun /*									*/
120*4882a593Smuzhiyun /* AccessXKeyboardEvent							*/
121*4882a593Smuzhiyun /*									*/
122*4882a593Smuzhiyun /*	Generate a synthetic keyboard event.				*/
123*4882a593Smuzhiyun /*									*/
124*4882a593Smuzhiyun /************************************************************************/
125*4882a593Smuzhiyun static void
AccessXKeyboardEvent(DeviceIntPtr keybd,int type,BYTE keyCode,Bool isRepeat)126*4882a593Smuzhiyun AccessXKeyboardEvent(DeviceIntPtr keybd, int type, BYTE keyCode, Bool isRepeat)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun     DeviceEvent event;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun     init_device_event(&event, keybd, GetTimeInMillis(), EVENT_SOURCE_NORMAL);
131*4882a593Smuzhiyun     event.type = type;
132*4882a593Smuzhiyun     event.detail.key = keyCode;
133*4882a593Smuzhiyun     event.key_repeat = isRepeat;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun     if (xkbDebugFlags & 0x8) {
136*4882a593Smuzhiyun         DebugF("[xkb] AXKE: Key %d %s\n", keyCode,
137*4882a593Smuzhiyun                (event.type == ET_KeyPress ? "down" : "up"));
138*4882a593Smuzhiyun     }
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun     XkbProcessKeyboardEvent(&event, keybd);
141*4882a593Smuzhiyun     return;
142*4882a593Smuzhiyun }                               /* AccessXKeyboardEvent */
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /************************************************************************/
145*4882a593Smuzhiyun /*									*/
146*4882a593Smuzhiyun /* AccessXKRGTurnOn							*/
147*4882a593Smuzhiyun /*									*/
148*4882a593Smuzhiyun /*	Turn the keyboard response group on.				*/
149*4882a593Smuzhiyun /*									*/
150*4882a593Smuzhiyun /************************************************************************/
151*4882a593Smuzhiyun static void
AccessXKRGTurnOn(DeviceIntPtr dev,CARD16 KRGControl,xkbControlsNotify * pCN)152*4882a593Smuzhiyun AccessXKRGTurnOn(DeviceIntPtr dev, CARD16 KRGControl, xkbControlsNotify * pCN)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
155*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
156*4882a593Smuzhiyun     XkbControlsRec old;
157*4882a593Smuzhiyun     XkbEventCauseRec cause;
158*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun     old = *ctrls;
161*4882a593Smuzhiyun     ctrls->enabled_ctrls |= (KRGControl & XkbAX_KRGMask);
162*4882a593Smuzhiyun     if (XkbComputeControlsNotify(dev, &old, ctrls, pCN, FALSE))
163*4882a593Smuzhiyun         XkbSendControlsNotify(dev, pCN);
164*4882a593Smuzhiyun     cause.kc = pCN->keycode;
165*4882a593Smuzhiyun     cause.event = pCN->eventType;
166*4882a593Smuzhiyun     cause.mjr = pCN->requestMajor;
167*4882a593Smuzhiyun     cause.mnr = pCN->requestMinor;
168*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
169*4882a593Smuzhiyun     XkbUpdateIndicators(dev, sli->usesControls, TRUE, NULL, &cause);
170*4882a593Smuzhiyun     if (XkbAX_NeedFeedback(ctrls, XkbAX_FeatureFBMask))
171*4882a593Smuzhiyun         XkbDDXAccessXBeep(dev, _BEEP_FEATURE_ON, KRGControl);
172*4882a593Smuzhiyun     return;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun }                               /* AccessXKRGTurnOn */
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun /************************************************************************/
177*4882a593Smuzhiyun /*									*/
178*4882a593Smuzhiyun /* AccessXKRGTurnOff							*/
179*4882a593Smuzhiyun /*									*/
180*4882a593Smuzhiyun /*	Turn the keyboard response group off.				*/
181*4882a593Smuzhiyun /*									*/
182*4882a593Smuzhiyun /************************************************************************/
183*4882a593Smuzhiyun static void
AccessXKRGTurnOff(DeviceIntPtr dev,xkbControlsNotify * pCN)184*4882a593Smuzhiyun AccessXKRGTurnOff(DeviceIntPtr dev, xkbControlsNotify * pCN)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
187*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
188*4882a593Smuzhiyun     XkbControlsRec old;
189*4882a593Smuzhiyun     XkbEventCauseRec cause;
190*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun     old = *ctrls;
193*4882a593Smuzhiyun     ctrls->enabled_ctrls &= ~XkbAX_KRGMask;
194*4882a593Smuzhiyun     if (XkbComputeControlsNotify(dev, &old, ctrls, pCN, FALSE))
195*4882a593Smuzhiyun         XkbSendControlsNotify(dev, pCN);
196*4882a593Smuzhiyun     cause.kc = pCN->keycode;
197*4882a593Smuzhiyun     cause.event = pCN->eventType;
198*4882a593Smuzhiyun     cause.mjr = pCN->requestMajor;
199*4882a593Smuzhiyun     cause.mnr = pCN->requestMinor;
200*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
201*4882a593Smuzhiyun     XkbUpdateIndicators(dev, sli->usesControls, TRUE, NULL, &cause);
202*4882a593Smuzhiyun     if (XkbAX_NeedFeedback(ctrls, XkbAX_FeatureFBMask)) {
203*4882a593Smuzhiyun         unsigned changes = old.enabled_ctrls ^ ctrls->enabled_ctrls;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun         XkbDDXAccessXBeep(dev, _BEEP_FEATURE_OFF, changes);
206*4882a593Smuzhiyun     }
207*4882a593Smuzhiyun     return;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun }                               /* AccessXKRGTurnOff */
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun /************************************************************************/
212*4882a593Smuzhiyun /*									*/
213*4882a593Smuzhiyun /* AccessXStickyKeysTurnOn						*/
214*4882a593Smuzhiyun /*									*/
215*4882a593Smuzhiyun /*	Turn StickyKeys on.						*/
216*4882a593Smuzhiyun /*									*/
217*4882a593Smuzhiyun /************************************************************************/
218*4882a593Smuzhiyun static void
AccessXStickyKeysTurnOn(DeviceIntPtr dev,xkbControlsNotify * pCN)219*4882a593Smuzhiyun AccessXStickyKeysTurnOn(DeviceIntPtr dev, xkbControlsNotify * pCN)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
222*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
223*4882a593Smuzhiyun     XkbControlsRec old;
224*4882a593Smuzhiyun     XkbEventCauseRec cause;
225*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun     old = *ctrls;
228*4882a593Smuzhiyun     ctrls->enabled_ctrls |= XkbStickyKeysMask;
229*4882a593Smuzhiyun     xkbi->shiftKeyCount = 0;
230*4882a593Smuzhiyun     if (XkbComputeControlsNotify(dev, &old, ctrls, pCN, FALSE))
231*4882a593Smuzhiyun         XkbSendControlsNotify(dev, pCN);
232*4882a593Smuzhiyun     cause.kc = pCN->keycode;
233*4882a593Smuzhiyun     cause.event = pCN->eventType;
234*4882a593Smuzhiyun     cause.mjr = pCN->requestMajor;
235*4882a593Smuzhiyun     cause.mnr = pCN->requestMinor;
236*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
237*4882a593Smuzhiyun     XkbUpdateIndicators(dev, sli->usesControls, TRUE, NULL, &cause);
238*4882a593Smuzhiyun     if (XkbAX_NeedFeedback(ctrls, XkbAX_FeatureFBMask)) {
239*4882a593Smuzhiyun         XkbDDXAccessXBeep(dev, _BEEP_FEATURE_ON, XkbStickyKeysMask);
240*4882a593Smuzhiyun     }
241*4882a593Smuzhiyun     return;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun }                               /* AccessXStickyKeysTurnOn */
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun /************************************************************************/
246*4882a593Smuzhiyun /*									*/
247*4882a593Smuzhiyun /* AccessXStickyKeysTurnOff						*/
248*4882a593Smuzhiyun /*									*/
249*4882a593Smuzhiyun /*	Turn StickyKeys off.						*/
250*4882a593Smuzhiyun /*									*/
251*4882a593Smuzhiyun /************************************************************************/
252*4882a593Smuzhiyun static void
AccessXStickyKeysTurnOff(DeviceIntPtr dev,xkbControlsNotify * pCN)253*4882a593Smuzhiyun AccessXStickyKeysTurnOff(DeviceIntPtr dev, xkbControlsNotify * pCN)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
256*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
257*4882a593Smuzhiyun     XkbControlsRec old;
258*4882a593Smuzhiyun     XkbEventCauseRec cause;
259*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun     old = *ctrls;
262*4882a593Smuzhiyun     ctrls->enabled_ctrls &= ~XkbStickyKeysMask;
263*4882a593Smuzhiyun     xkbi->shiftKeyCount = 0;
264*4882a593Smuzhiyun     if (XkbComputeControlsNotify(dev, &old, ctrls, pCN, FALSE))
265*4882a593Smuzhiyun         XkbSendControlsNotify(dev, pCN);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun     cause.kc = pCN->keycode;
268*4882a593Smuzhiyun     cause.event = pCN->eventType;
269*4882a593Smuzhiyun     cause.mjr = pCN->requestMajor;
270*4882a593Smuzhiyun     cause.mnr = pCN->requestMinor;
271*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
272*4882a593Smuzhiyun     XkbUpdateIndicators(dev, sli->usesControls, TRUE, NULL, &cause);
273*4882a593Smuzhiyun     if (XkbAX_NeedFeedback(ctrls, XkbAX_FeatureFBMask)) {
274*4882a593Smuzhiyun         XkbDDXAccessXBeep(dev, _BEEP_FEATURE_OFF, XkbStickyKeysMask);
275*4882a593Smuzhiyun     }
276*4882a593Smuzhiyun #ifndef NO_CLEAR_LATCHES_FOR_STICKY_KEYS_OFF
277*4882a593Smuzhiyun     XkbClearAllLatchesAndLocks(dev, xkbi, FALSE, &cause);
278*4882a593Smuzhiyun #endif
279*4882a593Smuzhiyun     return;
280*4882a593Smuzhiyun }                               /* AccessXStickyKeysTurnOff */
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun static CARD32
AccessXKRGExpire(OsTimerPtr timer,CARD32 now,void * arg)283*4882a593Smuzhiyun AccessXKRGExpire(OsTimerPtr timer, CARD32 now, void *arg)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun     xkbControlsNotify cn;
286*4882a593Smuzhiyun     DeviceIntPtr dev = arg;
287*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun     if (xkbi->krgTimerActive == _KRG_WARN_TIMER) {
290*4882a593Smuzhiyun         XkbDDXAccessXBeep(dev, _BEEP_SLOW_WARN, XkbStickyKeysMask);
291*4882a593Smuzhiyun         xkbi->krgTimerActive = _KRG_TIMER;
292*4882a593Smuzhiyun         return 4000;
293*4882a593Smuzhiyun     }
294*4882a593Smuzhiyun     xkbi->krgTimerActive = _OFF_TIMER;
295*4882a593Smuzhiyun     cn.keycode = xkbi->slowKeyEnableKey;
296*4882a593Smuzhiyun     cn.eventType = KeyPress;
297*4882a593Smuzhiyun     cn.requestMajor = 0;
298*4882a593Smuzhiyun     cn.requestMinor = 0;
299*4882a593Smuzhiyun     if (xkbi->desc->ctrls->enabled_ctrls & XkbSlowKeysMask) {
300*4882a593Smuzhiyun         AccessXKRGTurnOff(dev, &cn);
301*4882a593Smuzhiyun         LogMessage(X_INFO, "XKB SlowKeys are disabled.\n");
302*4882a593Smuzhiyun     }
303*4882a593Smuzhiyun     else {
304*4882a593Smuzhiyun         AccessXKRGTurnOn(dev, XkbSlowKeysMask, &cn);
305*4882a593Smuzhiyun         LogMessage(X_INFO, "XKB SlowKeys are now enabled. Hold shift to disable.\n");
306*4882a593Smuzhiyun     }
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun     xkbi->slowKeyEnableKey = 0;
309*4882a593Smuzhiyun     return 0;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun static CARD32
AccessXRepeatKeyExpire(OsTimerPtr timer,CARD32 now,void * arg)313*4882a593Smuzhiyun AccessXRepeatKeyExpire(OsTimerPtr timer, CARD32 now, void *arg)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun     DeviceIntPtr dev = (DeviceIntPtr) arg;
316*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun     if (xkbi->repeatKey == 0)
319*4882a593Smuzhiyun         return 0;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun     if (xkbi->checkRepeat == NULL || xkbi->checkRepeat (dev, xkbi, xkbi->repeatKey))
322*4882a593Smuzhiyun         AccessXKeyboardEvent(dev, ET_KeyPress, xkbi->repeatKey, TRUE);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun     return xkbi->desc->ctrls->repeat_interval;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun void
AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi,KeyCode key)328*4882a593Smuzhiyun AccessXCancelRepeatKey(XkbSrvInfoPtr xkbi, KeyCode key)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun     if (xkbi->repeatKey == key)
331*4882a593Smuzhiyun         xkbi->repeatKey = 0;
332*4882a593Smuzhiyun     return;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun static CARD32
AccessXSlowKeyExpire(OsTimerPtr timer,CARD32 now,void * arg)336*4882a593Smuzhiyun AccessXSlowKeyExpire(OsTimerPtr timer, CARD32 now, void *arg)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun     DeviceIntPtr keybd;
339*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi;
340*4882a593Smuzhiyun     XkbDescPtr xkb;
341*4882a593Smuzhiyun     XkbControlsPtr ctrls;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun     keybd = (DeviceIntPtr) arg;
344*4882a593Smuzhiyun     xkbi = keybd->key->xkbInfo;
345*4882a593Smuzhiyun     xkb = xkbi->desc;
346*4882a593Smuzhiyun     ctrls = xkb->ctrls;
347*4882a593Smuzhiyun     if (xkbi->slowKey != 0) {
348*4882a593Smuzhiyun         xkbAccessXNotify ev;
349*4882a593Smuzhiyun         KeySym *sym = XkbKeySymsPtr(xkb, xkbi->slowKey);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun         ev.detail = XkbAXN_SKAccept;
352*4882a593Smuzhiyun         ev.keycode = xkbi->slowKey;
353*4882a593Smuzhiyun         ev.slowKeysDelay = ctrls->slow_keys_delay;
354*4882a593Smuzhiyun         ev.debounceDelay = ctrls->debounce_delay;
355*4882a593Smuzhiyun         XkbSendAccessXNotify(keybd, &ev);
356*4882a593Smuzhiyun         if (XkbAX_NeedFeedback(ctrls, XkbAX_SKAcceptFBMask))
357*4882a593Smuzhiyun             XkbDDXAccessXBeep(keybd, _BEEP_SLOW_ACCEPT, XkbSlowKeysMask);
358*4882a593Smuzhiyun         AccessXKeyboardEvent(keybd, ET_KeyPress, xkbi->slowKey, FALSE);
359*4882a593Smuzhiyun         /* check for magic sequences */
360*4882a593Smuzhiyun         if ((ctrls->enabled_ctrls & XkbAccessXKeysMask) &&
361*4882a593Smuzhiyun             ((sym[0] == XK_Shift_R) || (sym[0] == XK_Shift_L)))
362*4882a593Smuzhiyun             xkbi->shiftKeyCount++;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun         /* Start repeating if necessary.  Stop autorepeating if the user
365*4882a593Smuzhiyun          * presses a non-modifier key that doesn't autorepeat.
366*4882a593Smuzhiyun          */
367*4882a593Smuzhiyun         if (keybd->kbdfeed->ctrl.autoRepeat &&
368*4882a593Smuzhiyun             ((xkbi->slowKey != xkbi->mouseKey) || (!xkbi->mouseKeysAccel)) &&
369*4882a593Smuzhiyun             (ctrls->enabled_ctrls & XkbRepeatKeysMask)) {
370*4882a593Smuzhiyun             if (BitIsOn(keybd->kbdfeed->ctrl.autoRepeats, xkbi->slowKey)) {
371*4882a593Smuzhiyun                 xkbi->repeatKey = xkbi->slowKey;
372*4882a593Smuzhiyun                 xkbi->repeatKeyTimer = TimerSet(xkbi->repeatKeyTimer,
373*4882a593Smuzhiyun                                                 0, ctrls->repeat_delay,
374*4882a593Smuzhiyun                                                 AccessXRepeatKeyExpire,
375*4882a593Smuzhiyun                                                 (void *) keybd);
376*4882a593Smuzhiyun             }
377*4882a593Smuzhiyun         }
378*4882a593Smuzhiyun     }
379*4882a593Smuzhiyun     return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun static CARD32
AccessXBounceKeyExpire(OsTimerPtr timer,CARD32 now,void * arg)383*4882a593Smuzhiyun AccessXBounceKeyExpire(OsTimerPtr timer, CARD32 now, void *arg)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = ((DeviceIntPtr) arg)->key->xkbInfo;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun     xkbi->inactiveKey = 0;
388*4882a593Smuzhiyun     return 0;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun static CARD32
AccessXTimeoutExpire(OsTimerPtr timer,CARD32 now,void * arg)392*4882a593Smuzhiyun AccessXTimeoutExpire(OsTimerPtr timer, CARD32 now, void *arg)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun     DeviceIntPtr dev = (DeviceIntPtr) arg;
395*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
396*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
397*4882a593Smuzhiyun     XkbControlsRec old;
398*4882a593Smuzhiyun     xkbControlsNotify cn;
399*4882a593Smuzhiyun     XkbEventCauseRec cause;
400*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun     if (xkbi->lastPtrEventTime) {
403*4882a593Smuzhiyun         unsigned timeToWait = (ctrls->ax_timeout * 1000);
404*4882a593Smuzhiyun         unsigned timeElapsed = (now - xkbi->lastPtrEventTime);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun         if (timeToWait > timeElapsed)
407*4882a593Smuzhiyun             return timeToWait - timeElapsed;
408*4882a593Smuzhiyun     }
409*4882a593Smuzhiyun     old = *ctrls;
410*4882a593Smuzhiyun     xkbi->shiftKeyCount = 0;
411*4882a593Smuzhiyun     ctrls->enabled_ctrls &= ~ctrls->axt_ctrls_mask;
412*4882a593Smuzhiyun     ctrls->enabled_ctrls |= (ctrls->axt_ctrls_values & ctrls->axt_ctrls_mask);
413*4882a593Smuzhiyun     if (ctrls->axt_opts_mask) {
414*4882a593Smuzhiyun         ctrls->ax_options &= ~ctrls->axt_opts_mask;
415*4882a593Smuzhiyun         ctrls->ax_options |= (ctrls->axt_opts_values & ctrls->axt_opts_mask);
416*4882a593Smuzhiyun     }
417*4882a593Smuzhiyun     if (XkbComputeControlsNotify(dev, &old, ctrls, &cn, FALSE)) {
418*4882a593Smuzhiyun         cn.keycode = 0;
419*4882a593Smuzhiyun         cn.eventType = 0;
420*4882a593Smuzhiyun         cn.requestMajor = 0;
421*4882a593Smuzhiyun         cn.requestMinor = 0;
422*4882a593Smuzhiyun         XkbSendControlsNotify(dev, &cn);
423*4882a593Smuzhiyun     }
424*4882a593Smuzhiyun     XkbSetCauseUnknown(&cause);
425*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
426*4882a593Smuzhiyun     XkbUpdateIndicators(dev, sli->usesControls, TRUE, NULL, &cause);
427*4882a593Smuzhiyun     if (ctrls->ax_options != old.ax_options) {
428*4882a593Smuzhiyun         unsigned set, cleared, bell;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun         set = ctrls->ax_options & (~old.ax_options);
431*4882a593Smuzhiyun         cleared = (~ctrls->ax_options) & old.ax_options;
432*4882a593Smuzhiyun         if (set && cleared)
433*4882a593Smuzhiyun             bell = _BEEP_FEATURE_CHANGE;
434*4882a593Smuzhiyun         else if (set)
435*4882a593Smuzhiyun             bell = _BEEP_FEATURE_ON;
436*4882a593Smuzhiyun         else
437*4882a593Smuzhiyun             bell = _BEEP_FEATURE_OFF;
438*4882a593Smuzhiyun         XkbDDXAccessXBeep(dev, bell, XkbAccessXTimeoutMask);
439*4882a593Smuzhiyun     }
440*4882a593Smuzhiyun     xkbi->krgTimerActive = _OFF_TIMER;
441*4882a593Smuzhiyun     return 0;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun /************************************************************************/
445*4882a593Smuzhiyun /*									*/
446*4882a593Smuzhiyun /* AccessXFilterPressEvent						*/
447*4882a593Smuzhiyun /*									*/
448*4882a593Smuzhiyun /* Filter events before they get any further if SlowKeys is turned on.	*/
449*4882a593Smuzhiyun /* In addition, this routine handles the ever so popular magic key	*/
450*4882a593Smuzhiyun /* acts for turning various accessibility features on/off.		*/
451*4882a593Smuzhiyun /*									*/
452*4882a593Smuzhiyun /* Returns TRUE if this routine has discarded the event.		*/
453*4882a593Smuzhiyun /* Returns FALSE if the event needs further processing.			*/
454*4882a593Smuzhiyun /*									*/
455*4882a593Smuzhiyun /************************************************************************/
456*4882a593Smuzhiyun Bool
AccessXFilterPressEvent(DeviceEvent * event,DeviceIntPtr keybd)457*4882a593Smuzhiyun AccessXFilterPressEvent(DeviceEvent *event, DeviceIntPtr keybd)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = keybd->key->xkbInfo;
460*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
461*4882a593Smuzhiyun     Bool ignoreKeyEvent = FALSE;
462*4882a593Smuzhiyun     KeyCode key = event->detail.key;
463*4882a593Smuzhiyun     KeySym *sym = XkbKeySymsPtr(xkbi->desc, key);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun     if (ctrls->enabled_ctrls & XkbAccessXKeysMask) {
466*4882a593Smuzhiyun         /* check for magic sequences */
467*4882a593Smuzhiyun         if ((sym[0] == XK_Shift_R) || (sym[0] == XK_Shift_L)) {
468*4882a593Smuzhiyun             xkbi->slowKeyEnableKey = key;
469*4882a593Smuzhiyun             if (XkbAX_NeedFeedback(ctrls, XkbAX_SlowWarnFBMask)) {
470*4882a593Smuzhiyun                 xkbi->krgTimerActive = _KRG_WARN_TIMER;
471*4882a593Smuzhiyun                 xkbi->krgTimer = TimerSet(xkbi->krgTimer, 0, 4000,
472*4882a593Smuzhiyun                                           AccessXKRGExpire, (void *) keybd);
473*4882a593Smuzhiyun             }
474*4882a593Smuzhiyun             else {
475*4882a593Smuzhiyun                 xkbi->krgTimerActive = _KRG_TIMER;
476*4882a593Smuzhiyun                 xkbi->krgTimer = TimerSet(xkbi->krgTimer, 0, 8000,
477*4882a593Smuzhiyun                                           AccessXKRGExpire, (void *) keybd);
478*4882a593Smuzhiyun             }
479*4882a593Smuzhiyun             if (!(ctrls->enabled_ctrls & XkbSlowKeysMask)) {
480*4882a593Smuzhiyun                 CARD32 now = GetTimeInMillis();
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun                 if ((now - xkbi->lastShiftEventTime) > 15000)
483*4882a593Smuzhiyun                     xkbi->shiftKeyCount = 1;
484*4882a593Smuzhiyun                 else
485*4882a593Smuzhiyun                     xkbi->shiftKeyCount++;
486*4882a593Smuzhiyun                 xkbi->lastShiftEventTime = now;
487*4882a593Smuzhiyun             }
488*4882a593Smuzhiyun         }
489*4882a593Smuzhiyun         else {
490*4882a593Smuzhiyun             if (xkbi->krgTimerActive) {
491*4882a593Smuzhiyun                 xkbi->krgTimer = TimerSet(xkbi->krgTimer, 0, 0, NULL, NULL);
492*4882a593Smuzhiyun                 xkbi->krgTimerActive = _OFF_TIMER;
493*4882a593Smuzhiyun             }
494*4882a593Smuzhiyun         }
495*4882a593Smuzhiyun     }
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun     /* Don't transmit the KeyPress if SlowKeys is turned on;
498*4882a593Smuzhiyun      * The wakeup handler will synthesize one for us if the user
499*4882a593Smuzhiyun      * has held the key long enough.
500*4882a593Smuzhiyun      */
501*4882a593Smuzhiyun     if (ctrls->enabled_ctrls & XkbSlowKeysMask) {
502*4882a593Smuzhiyun         xkbAccessXNotify ev;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun         /* If key was already pressed, ignore subsequent press events
505*4882a593Smuzhiyun          * from the server's autorepeat
506*4882a593Smuzhiyun          */
507*4882a593Smuzhiyun         if (xkbi->slowKey == key)
508*4882a593Smuzhiyun             return TRUE;
509*4882a593Smuzhiyun         ev.detail = XkbAXN_SKPress;
510*4882a593Smuzhiyun         ev.keycode = key;
511*4882a593Smuzhiyun         ev.slowKeysDelay = ctrls->slow_keys_delay;
512*4882a593Smuzhiyun         ev.debounceDelay = ctrls->debounce_delay;
513*4882a593Smuzhiyun         XkbSendAccessXNotify(keybd, &ev);
514*4882a593Smuzhiyun         if (XkbAX_NeedFeedback(ctrls, XkbAX_SKPressFBMask))
515*4882a593Smuzhiyun             XkbDDXAccessXBeep(keybd, _BEEP_SLOW_PRESS, XkbSlowKeysMask);
516*4882a593Smuzhiyun         xkbi->slowKey = key;
517*4882a593Smuzhiyun         xkbi->slowKeysTimer = TimerSet(xkbi->slowKeysTimer,
518*4882a593Smuzhiyun                                        0, ctrls->slow_keys_delay,
519*4882a593Smuzhiyun                                        AccessXSlowKeyExpire, (void *) keybd);
520*4882a593Smuzhiyun         ignoreKeyEvent = TRUE;
521*4882a593Smuzhiyun     }
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun     /* Don't transmit the KeyPress if BounceKeys is turned on
524*4882a593Smuzhiyun      * and the user pressed the same key within a given time period
525*4882a593Smuzhiyun      * from the last release.
526*4882a593Smuzhiyun      */
527*4882a593Smuzhiyun     else if ((ctrls->enabled_ctrls & XkbBounceKeysMask) &&
528*4882a593Smuzhiyun              (key == xkbi->inactiveKey)) {
529*4882a593Smuzhiyun         if (XkbAX_NeedFeedback(ctrls, XkbAX_BKRejectFBMask))
530*4882a593Smuzhiyun             XkbDDXAccessXBeep(keybd, _BEEP_BOUNCE_REJECT, XkbBounceKeysMask);
531*4882a593Smuzhiyun         ignoreKeyEvent = TRUE;
532*4882a593Smuzhiyun     }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun     /* Start repeating if necessary.  Stop autorepeating if the user
535*4882a593Smuzhiyun      * presses a non-modifier key that doesn't autorepeat.
536*4882a593Smuzhiyun      */
537*4882a593Smuzhiyun     if (XkbDDXUsesSoftRepeat(keybd)) {
538*4882a593Smuzhiyun         if ((keybd->kbdfeed->ctrl.autoRepeat) &&
539*4882a593Smuzhiyun             ((ctrls->enabled_ctrls & (XkbSlowKeysMask | XkbRepeatKeysMask)) ==
540*4882a593Smuzhiyun              XkbRepeatKeysMask)) {
541*4882a593Smuzhiyun             if (BitIsOn(keybd->kbdfeed->ctrl.autoRepeats, key)) {
542*4882a593Smuzhiyun                 if (xkbDebugFlags & 0x10)
543*4882a593Smuzhiyun                     DebugF("Starting software autorepeat...\n");
544*4882a593Smuzhiyun                 if (xkbi->repeatKey == key)
545*4882a593Smuzhiyun                     ignoreKeyEvent = TRUE;
546*4882a593Smuzhiyun                 else {
547*4882a593Smuzhiyun                     xkbi->repeatKey = key;
548*4882a593Smuzhiyun                     xkbi->repeatKeyTimer = TimerSet(xkbi->repeatKeyTimer,
549*4882a593Smuzhiyun                                                     0, ctrls->repeat_delay,
550*4882a593Smuzhiyun                                                     AccessXRepeatKeyExpire,
551*4882a593Smuzhiyun                                                     (void *) keybd);
552*4882a593Smuzhiyun                 }
553*4882a593Smuzhiyun             }
554*4882a593Smuzhiyun         }
555*4882a593Smuzhiyun     }
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun     /* Check for two keys being pressed at the same time.  This section
558*4882a593Smuzhiyun      * essentially says the following:
559*4882a593Smuzhiyun      *
560*4882a593Smuzhiyun      *  If StickyKeys is on, and a modifier is currently being held down,
561*4882a593Smuzhiyun      *  and one of the following is true:  the current key is not a modifier
562*4882a593Smuzhiyun      *  or the currentKey is a modifier, but not the only modifier being
563*4882a593Smuzhiyun      *  held down, turn StickyKeys off if the TwoKeys off ctrl is set.
564*4882a593Smuzhiyun      */
565*4882a593Smuzhiyun     if ((ctrls->enabled_ctrls & XkbStickyKeysMask) &&
566*4882a593Smuzhiyun         (xkbi->state.base_mods != 0) &&
567*4882a593Smuzhiyun         (XkbAX_NeedOption(ctrls, XkbAX_TwoKeysMask))) {
568*4882a593Smuzhiyun         xkbControlsNotify cn;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun         cn.keycode = key;
571*4882a593Smuzhiyun         cn.eventType = KeyPress;
572*4882a593Smuzhiyun         cn.requestMajor = 0;
573*4882a593Smuzhiyun         cn.requestMinor = 0;
574*4882a593Smuzhiyun         AccessXStickyKeysTurnOff(keybd, &cn);
575*4882a593Smuzhiyun     }
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun     if (!ignoreKeyEvent)
578*4882a593Smuzhiyun         XkbProcessKeyboardEvent(event, keybd);
579*4882a593Smuzhiyun     return ignoreKeyEvent;
580*4882a593Smuzhiyun }                               /* AccessXFilterPressEvent */
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun /************************************************************************/
583*4882a593Smuzhiyun /*									*/
584*4882a593Smuzhiyun /* AccessXFilterReleaseEvent						*/
585*4882a593Smuzhiyun /*									*/
586*4882a593Smuzhiyun /* Filter events before they get any further if SlowKeys is turned on.	*/
587*4882a593Smuzhiyun /* In addition, this routine handles the ever so popular magic key	*/
588*4882a593Smuzhiyun /* acts for turning various accessibility features on/off.		*/
589*4882a593Smuzhiyun /*									*/
590*4882a593Smuzhiyun /* Returns TRUE if this routine has discarded the event.		*/
591*4882a593Smuzhiyun /* Returns FALSE if the event needs further processing.			*/
592*4882a593Smuzhiyun /*									*/
593*4882a593Smuzhiyun /************************************************************************/
594*4882a593Smuzhiyun Bool
AccessXFilterReleaseEvent(DeviceEvent * event,DeviceIntPtr keybd)595*4882a593Smuzhiyun AccessXFilterReleaseEvent(DeviceEvent *event, DeviceIntPtr keybd)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = keybd->key->xkbInfo;
598*4882a593Smuzhiyun     XkbControlsPtr ctrls = xkbi->desc->ctrls;
599*4882a593Smuzhiyun     KeyCode key = event->detail.key;
600*4882a593Smuzhiyun     Bool ignoreKeyEvent = FALSE;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun     /* Don't transmit the KeyRelease if BounceKeys is on and
603*4882a593Smuzhiyun      * this is the release of a key that was ignored due to
604*4882a593Smuzhiyun      * BounceKeys.
605*4882a593Smuzhiyun      */
606*4882a593Smuzhiyun     if (ctrls->enabled_ctrls & XkbBounceKeysMask) {
607*4882a593Smuzhiyun         if ((key != xkbi->mouseKey) && (!BitIsOn(keybd->key->down, key)))
608*4882a593Smuzhiyun             ignoreKeyEvent = TRUE;
609*4882a593Smuzhiyun         xkbi->inactiveKey = key;
610*4882a593Smuzhiyun         xkbi->bounceKeysTimer = TimerSet(xkbi->bounceKeysTimer, 0,
611*4882a593Smuzhiyun                                          ctrls->debounce_delay,
612*4882a593Smuzhiyun                                          AccessXBounceKeyExpire,
613*4882a593Smuzhiyun                                          (void *) keybd);
614*4882a593Smuzhiyun     }
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun     /* Don't transmit the KeyRelease if SlowKeys is turned on and
617*4882a593Smuzhiyun      * the user didn't hold the key long enough.  We know we passed
618*4882a593Smuzhiyun      * the key if the down bit was set by CoreProcessKeyboadEvent.
619*4882a593Smuzhiyun      */
620*4882a593Smuzhiyun     if (ctrls->enabled_ctrls & XkbSlowKeysMask) {
621*4882a593Smuzhiyun         xkbAccessXNotify ev;
622*4882a593Smuzhiyun         unsigned beep_type;
623*4882a593Smuzhiyun         unsigned mask;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun         ev.keycode = key;
626*4882a593Smuzhiyun         ev.slowKeysDelay = ctrls->slow_keys_delay;
627*4882a593Smuzhiyun         ev.debounceDelay = ctrls->debounce_delay;
628*4882a593Smuzhiyun         if (BitIsOn(keybd->key->down, key) || (xkbi->mouseKey == key)) {
629*4882a593Smuzhiyun             ev.detail = XkbAXN_SKRelease;
630*4882a593Smuzhiyun             beep_type = _BEEP_SLOW_RELEASE;
631*4882a593Smuzhiyun             mask = XkbAX_SKReleaseFBMask;
632*4882a593Smuzhiyun         }
633*4882a593Smuzhiyun         else {
634*4882a593Smuzhiyun             ev.detail = XkbAXN_SKReject;
635*4882a593Smuzhiyun             beep_type = _BEEP_SLOW_REJECT;
636*4882a593Smuzhiyun             mask = XkbAX_SKRejectFBMask;
637*4882a593Smuzhiyun             ignoreKeyEvent = TRUE;
638*4882a593Smuzhiyun         }
639*4882a593Smuzhiyun         XkbSendAccessXNotify(keybd, &ev);
640*4882a593Smuzhiyun         if (XkbAX_NeedFeedback(ctrls, mask)) {
641*4882a593Smuzhiyun             XkbDDXAccessXBeep(keybd, beep_type, XkbSlowKeysMask);
642*4882a593Smuzhiyun         }
643*4882a593Smuzhiyun         if (xkbi->slowKey == key)
644*4882a593Smuzhiyun             xkbi->slowKey = 0;
645*4882a593Smuzhiyun     }
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun     /* Stop Repeating if the user releases the key that is currently
648*4882a593Smuzhiyun      * repeating.
649*4882a593Smuzhiyun      */
650*4882a593Smuzhiyun     if (xkbi->repeatKey == key) {
651*4882a593Smuzhiyun         xkbi->repeatKey = 0;
652*4882a593Smuzhiyun     }
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun     if ((ctrls->enabled_ctrls & XkbAccessXTimeoutMask) &&
655*4882a593Smuzhiyun         (ctrls->ax_timeout > 0)) {
656*4882a593Smuzhiyun         xkbi->lastPtrEventTime = 0;
657*4882a593Smuzhiyun         xkbi->krgTimer = TimerSet(xkbi->krgTimer, 0,
658*4882a593Smuzhiyun                                   ctrls->ax_timeout * 1000,
659*4882a593Smuzhiyun                                   AccessXTimeoutExpire, (void *) keybd);
660*4882a593Smuzhiyun         xkbi->krgTimerActive = _ALL_TIMEOUT_TIMER;
661*4882a593Smuzhiyun     }
662*4882a593Smuzhiyun     else if (xkbi->krgTimerActive != _OFF_TIMER) {
663*4882a593Smuzhiyun         xkbi->krgTimer = TimerSet(xkbi->krgTimer, 0, 0, NULL, NULL);
664*4882a593Smuzhiyun         xkbi->krgTimerActive = _OFF_TIMER;
665*4882a593Smuzhiyun     }
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun     /* Keep track of how many times the Shift key has been pressed.
668*4882a593Smuzhiyun      * If it has been pressed and released 5 times in a row, toggle
669*4882a593Smuzhiyun      * the state of StickyKeys.
670*4882a593Smuzhiyun      */
671*4882a593Smuzhiyun     if ((!ignoreKeyEvent) && (xkbi->shiftKeyCount)) {
672*4882a593Smuzhiyun         KeySym *pSym = XkbKeySymsPtr(xkbi->desc, key);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun         if ((pSym[0] != XK_Shift_L) && (pSym[0] != XK_Shift_R)) {
675*4882a593Smuzhiyun             xkbi->shiftKeyCount = 0;
676*4882a593Smuzhiyun         }
677*4882a593Smuzhiyun         else if (xkbi->shiftKeyCount >= 5) {
678*4882a593Smuzhiyun             xkbControlsNotify cn;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun             cn.keycode = key;
681*4882a593Smuzhiyun             cn.eventType = KeyPress;
682*4882a593Smuzhiyun             cn.requestMajor = 0;
683*4882a593Smuzhiyun             cn.requestMinor = 0;
684*4882a593Smuzhiyun             if (ctrls->enabled_ctrls & XkbStickyKeysMask)
685*4882a593Smuzhiyun                 AccessXStickyKeysTurnOff(keybd, &cn);
686*4882a593Smuzhiyun             else
687*4882a593Smuzhiyun                 AccessXStickyKeysTurnOn(keybd, &cn);
688*4882a593Smuzhiyun             xkbi->shiftKeyCount = 0;
689*4882a593Smuzhiyun         }
690*4882a593Smuzhiyun     }
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun     if (!ignoreKeyEvent)
693*4882a593Smuzhiyun         XkbProcessKeyboardEvent(event, keybd);
694*4882a593Smuzhiyun     return ignoreKeyEvent;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun }                               /* AccessXFilterReleaseEvent */
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun /************************************************************************/
699*4882a593Smuzhiyun /*									*/
700*4882a593Smuzhiyun /* ProcessPointerEvent							*/
701*4882a593Smuzhiyun /*									*/
702*4882a593Smuzhiyun /* This routine merely sets the shiftKeyCount and clears the keyboard   */
703*4882a593Smuzhiyun /* response group timer (if necessary) on a mouse event.  This is so	*/
704*4882a593Smuzhiyun /* multiple shifts with just the mouse and shift-drags with the mouse	*/
705*4882a593Smuzhiyun /* don't accidentally turn on StickyKeys or the Keyboard Response Group.*/
706*4882a593Smuzhiyun /*									*/
707*4882a593Smuzhiyun /************************************************************************/
708*4882a593Smuzhiyun extern int xkbDevicePrivateIndex;
709*4882a593Smuzhiyun void
ProcessPointerEvent(InternalEvent * ev,DeviceIntPtr mouse)710*4882a593Smuzhiyun ProcessPointerEvent(InternalEvent *ev, DeviceIntPtr mouse)
711*4882a593Smuzhiyun {
712*4882a593Smuzhiyun     DeviceIntPtr dev;
713*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = NULL;
714*4882a593Smuzhiyun     unsigned changed = 0;
715*4882a593Smuzhiyun     ProcessInputProc backupproc;
716*4882a593Smuzhiyun     xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(mouse);
717*4882a593Smuzhiyun     DeviceEvent *event = &ev->device_event;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun     dev = IsFloating(mouse) ? mouse : GetMaster(mouse, MASTER_KEYBOARD);
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun     if (dev && dev->key) {
722*4882a593Smuzhiyun         xkbi = dev->key->xkbInfo;
723*4882a593Smuzhiyun         xkbi->shiftKeyCount = 0;
724*4882a593Smuzhiyun         xkbi->lastPtrEventTime = event->time;
725*4882a593Smuzhiyun     }
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun     if (event->type == ET_ButtonPress) {
728*4882a593Smuzhiyun         changed |= XkbPointerButtonMask;
729*4882a593Smuzhiyun     }
730*4882a593Smuzhiyun     else if (event->type == ET_ButtonRelease) {
731*4882a593Smuzhiyun         if (IsMaster(dev)) {
732*4882a593Smuzhiyun             DeviceIntPtr source;
733*4882a593Smuzhiyun             int rc;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun             rc = dixLookupDevice(&source, event->sourceid, serverClient,
736*4882a593Smuzhiyun                     DixWriteAccess);
737*4882a593Smuzhiyun             if (rc != Success)
738*4882a593Smuzhiyun                 ErrorF("[xkb] bad sourceid '%d' on button release event.\n",
739*4882a593Smuzhiyun                         event->sourceid);
740*4882a593Smuzhiyun             else if (!IsXTestDevice(source, GetMaster(dev, MASTER_POINTER))) {
741*4882a593Smuzhiyun                 DeviceIntPtr xtest_device;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun                 xtest_device = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
744*4882a593Smuzhiyun                 if (button_is_down(xtest_device, ev->device_event.detail.button, BUTTON_PROCESSED))
745*4882a593Smuzhiyun                     XkbFakeDeviceButton(dev, FALSE, event->detail.key);
746*4882a593Smuzhiyun             }
747*4882a593Smuzhiyun         }
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun         if (xkbi)
750*4882a593Smuzhiyun             xkbi->lockedPtrButtons &= ~(1 << (event->detail.key & 0x7));
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun         changed |= XkbPointerButtonMask;
753*4882a593Smuzhiyun     }
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun     UNWRAP_PROCESS_INPUT_PROC(mouse, xkbPrivPtr, backupproc);
756*4882a593Smuzhiyun     mouse->public.processInputProc(ev, mouse);
757*4882a593Smuzhiyun     COND_WRAP_PROCESS_INPUT_PROC(mouse, xkbPrivPtr, backupproc, xkbUnwrapProc);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun     if (!xkbi)
760*4882a593Smuzhiyun         return;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun     xkbi->state.ptr_buttons = (mouse->button) ? mouse->button->state : 0;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun     /* clear any latched modifiers */
765*4882a593Smuzhiyun     if (xkbi->state.latched_mods && (event->type == ET_ButtonRelease)) {
766*4882a593Smuzhiyun         unsigned changed_leds;
767*4882a593Smuzhiyun         XkbStateRec oldState;
768*4882a593Smuzhiyun         XkbSrvLedInfoPtr sli;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun         sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
771*4882a593Smuzhiyun         oldState = xkbi->state;
772*4882a593Smuzhiyun         XkbLatchModifiers(dev, 0xFF, 0x00);
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun         XkbComputeDerivedState(xkbi);
775*4882a593Smuzhiyun         changed |= XkbStateChangedFlags(&oldState, &xkbi->state);
776*4882a593Smuzhiyun         if (changed & sli->usedComponents) {
777*4882a593Smuzhiyun             changed_leds = XkbIndicatorsToUpdate(dev, changed, FALSE);
778*4882a593Smuzhiyun             if (changed_leds) {
779*4882a593Smuzhiyun                 XkbEventCauseRec cause;
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun                 XkbSetCauseKey(&cause, (event->detail.key & 0x7), event->type);
782*4882a593Smuzhiyun                 XkbUpdateIndicators(dev, changed_leds, TRUE, NULL, &cause);
783*4882a593Smuzhiyun             }
784*4882a593Smuzhiyun         }
785*4882a593Smuzhiyun     }
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun     if (((xkbi->flags & _XkbStateNotifyInProgress) == 0) && (changed != 0)) {
788*4882a593Smuzhiyun         xkbStateNotify sn;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun         sn.keycode = event->detail.key;
791*4882a593Smuzhiyun         sn.eventType = event->type;
792*4882a593Smuzhiyun         sn.requestMajor = sn.requestMinor = 0;
793*4882a593Smuzhiyun         sn.changed = changed;
794*4882a593Smuzhiyun         XkbSendStateNotify(dev, &sn);
795*4882a593Smuzhiyun     }
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun }                               /* ProcessPointerEvent */
798