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 <X11/X.h>
33706f2543Smrg#include <X11/Xproto.h>
34706f2543Smrg#include <X11/keysym.h>
35706f2543Smrg#include "inputstr.h"
36706f2543Smrg#include "scrnintstr.h"
37706f2543Smrg#include "windowstr.h"
38706f2543Smrg#include <xkbsrv.h>
39706f2543Smrg#include <X11/extensions/XI.h>
40706f2543Smrg
41706f2543Smrg/*#define FALLING_TONE	1*/
42706f2543Smrg/*#define RISING_TONE	1*/
43706f2543Smrg#define FALLING_TONE	10
44706f2543Smrg#define RISING_TONE	10
45706f2543Smrg#define	SHORT_TONE	50
46706f2543Smrg#define	SHORT_DELAY	60
47706f2543Smrg#define	LONG_TONE	75
48706f2543Smrg#define	VERY_LONG_TONE	100
49706f2543Smrg#define	LONG_DELAY	85
50706f2543Smrg#define CLICK_DURATION	1
51706f2543Smrg
52706f2543Smrg#define	DEEP_PITCH	250
53706f2543Smrg#define	LOW_PITCH	500
54706f2543Smrg#define	MID_PITCH	1000
55706f2543Smrg#define	HIGH_PITCH	2000
56706f2543Smrg#define CLICK_PITCH	1500
57706f2543Smrg
58706f2543Smrgstatic	unsigned long	atomGeneration= 0;
59706f2543Smrgstatic	Atom	featureOn;
60706f2543Smrgstatic	Atom	featureOff;
61706f2543Smrgstatic	Atom	featureChange;
62706f2543Smrgstatic	Atom	ledOn;
63706f2543Smrgstatic	Atom	ledOff;
64706f2543Smrgstatic	Atom	ledChange;
65706f2543Smrgstatic	Atom	slowWarn;
66706f2543Smrgstatic	Atom	slowPress;
67706f2543Smrgstatic	Atom	slowReject;
68706f2543Smrgstatic	Atom	slowAccept;
69706f2543Smrgstatic	Atom	slowRelease;
70706f2543Smrgstatic	Atom	stickyLatch;
71706f2543Smrgstatic	Atom	stickyLock;
72706f2543Smrgstatic	Atom	stickyUnlock;
73706f2543Smrgstatic	Atom	bounceReject;
74706f2543Smrgstatic  char 	doesPitch = 1;
75706f2543Smrg
76706f2543Smrg#define	FEATURE_ON	"AX_FeatureOn"
77706f2543Smrg#define	FEATURE_OFF	"AX_FeatureOff"
78706f2543Smrg#define	FEATURE_CHANGE	"AX_FeatureChange"
79706f2543Smrg#define	LED_ON		"AX_IndicatorOn"
80706f2543Smrg#define	LED_OFF		"AX_IndicatorOff"
81706f2543Smrg#define	LED_CHANGE	"AX_IndicatorChange"
82706f2543Smrg#define	SLOW_WARN	"AX_SlowKeysWarning"
83706f2543Smrg#define	SLOW_PRESS	"AX_SlowKeyPress"
84706f2543Smrg#define	SLOW_REJECT	"AX_SlowKeyReject"
85706f2543Smrg#define	SLOW_ACCEPT	"AX_SlowKeyAccept"
86706f2543Smrg#define	SLOW_RELEASE	"AX_SlowKeyRelease"
87706f2543Smrg#define	STICKY_LATCH	"AX_StickyLatch"
88706f2543Smrg#define	STICKY_LOCK	"AX_StickyLock"
89706f2543Smrg#define	STICKY_UNLOCK	"AX_StickyUnlock"
90706f2543Smrg#define	BOUNCE_REJECT	"AX_BounceKeyReject"
91706f2543Smrg
92706f2543Smrg#define	MAKE_ATOM(a)	MakeAtom(a,sizeof(a)-1,TRUE)
93706f2543Smrg
94706f2543Smrgstatic void
95706f2543Smrg_XkbDDXBeepInitAtoms(void)
96706f2543Smrg{
97706f2543Smrg    featureOn= 		MAKE_ATOM(FEATURE_ON);
98706f2543Smrg    featureOff= 	MAKE_ATOM(FEATURE_OFF);
99706f2543Smrg    featureChange= 	MAKE_ATOM(FEATURE_CHANGE);
100706f2543Smrg    ledOn= 		MAKE_ATOM(LED_ON);
101706f2543Smrg    ledOff= 		MAKE_ATOM(LED_OFF);
102706f2543Smrg    ledChange= 		MAKE_ATOM(LED_CHANGE);
103706f2543Smrg    slowWarn= 		MAKE_ATOM(SLOW_WARN);
104706f2543Smrg    slowPress= 		MAKE_ATOM(SLOW_PRESS);
105706f2543Smrg    slowReject= 	MAKE_ATOM(SLOW_REJECT);
106706f2543Smrg    slowAccept= 	MAKE_ATOM(SLOW_ACCEPT);
107706f2543Smrg    slowRelease= 	MAKE_ATOM(SLOW_RELEASE);
108706f2543Smrg    stickyLatch= 	MAKE_ATOM(STICKY_LATCH);
109706f2543Smrg    stickyLock=		MAKE_ATOM(STICKY_LOCK);
110706f2543Smrg    stickyUnlock= 	MAKE_ATOM(STICKY_UNLOCK);
111706f2543Smrg    bounceReject= 	MAKE_ATOM(BOUNCE_REJECT);
112706f2543Smrg    return;
113706f2543Smrg}
114706f2543Smrg
115706f2543Smrgstatic CARD32
116706f2543Smrg_XkbDDXBeepExpire(OsTimerPtr timer,CARD32 now,pointer arg)
117706f2543Smrg{
118706f2543SmrgDeviceIntPtr	dev= (DeviceIntPtr)arg;
119706f2543SmrgKbdFeedbackPtr	feed;
120706f2543SmrgKeybdCtrl *	ctrl;
121706f2543SmrgXkbSrvInfoPtr	xkbInfo;
122706f2543SmrgCARD32		next;
123706f2543Smrgint		pitch,duration;
124706f2543Smrgint		oldPitch,oldDuration;
125706f2543SmrgAtom		name;
126706f2543Smrg
127706f2543Smrg    if ((dev==NULL)||(dev->key==NULL)||(dev->key->xkbInfo==NULL)||
128706f2543Smrg	(dev->kbdfeed==NULL))
129706f2543Smrg	return 0;
130706f2543Smrg    if (atomGeneration!=serverGeneration) {
131706f2543Smrg	_XkbDDXBeepInitAtoms();
132706f2543Smrg	atomGeneration= serverGeneration;
133706f2543Smrg    }
134706f2543Smrg
135706f2543Smrg    feed= dev->kbdfeed;
136706f2543Smrg    ctrl= &feed->ctrl;
137706f2543Smrg    xkbInfo= dev->key->xkbInfo;
138706f2543Smrg    next= 0;
139706f2543Smrg    pitch= oldPitch= ctrl->bell_pitch;
140706f2543Smrg    duration= oldDuration= ctrl->bell_duration;
141706f2543Smrg    name= None;
142706f2543Smrg    switch (xkbInfo->beepType) {
143706f2543Smrg	default:
144706f2543Smrg	    ErrorF("[xkb] Unknown beep type %d\n",xkbInfo->beepType);
145706f2543Smrg	case _BEEP_NONE:
146706f2543Smrg	    duration= 0;
147706f2543Smrg	    break;
148706f2543Smrg
149706f2543Smrg	/* When an LED is turned on, we want a high-pitched beep.
150706f2543Smrg	 * When the LED it turned off, we want a low-pitched beep.
151706f2543Smrg	 * If we cannot do pitch, we want a single beep for on and two
152706f2543Smrg	 * beeps for off.
153706f2543Smrg         */
154706f2543Smrg	case _BEEP_LED_ON:
155706f2543Smrg	    if (name==None)	name= ledOn;
156706f2543Smrg	    duration= SHORT_TONE;
157706f2543Smrg	    pitch= HIGH_PITCH;
158706f2543Smrg	    break;
159706f2543Smrg	case _BEEP_LED_OFF:
160706f2543Smrg	    if (name==None)	name= ledOff;
161706f2543Smrg	    duration= SHORT_TONE;
162706f2543Smrg	    pitch= LOW_PITCH;
163706f2543Smrg	    if (!doesPitch && xkbInfo->beepCount<1)
164706f2543Smrg		next = SHORT_DELAY;
165706f2543Smrg	    break;
166706f2543Smrg
167706f2543Smrg	/* When a Feature is turned on, we want an up-siren.
168706f2543Smrg	 * When a Feature is turned off, we want a down-siren.
169706f2543Smrg	 * If we cannot do pitch, we want a single beep for on and two
170706f2543Smrg	 * beeps for off.
171706f2543Smrg         */
172706f2543Smrg	case _BEEP_FEATURE_ON:
173706f2543Smrg	    if (name==None)	name= featureOn;
174706f2543Smrg	    if (xkbInfo->beepCount<1) {
175706f2543Smrg		pitch= LOW_PITCH;
176706f2543Smrg		duration= VERY_LONG_TONE;
177706f2543Smrg		if (doesPitch)
178706f2543Smrg		    next= SHORT_DELAY;
179706f2543Smrg	    }
180706f2543Smrg	    else {
181706f2543Smrg		pitch= MID_PITCH;
182706f2543Smrg		duration= SHORT_TONE;
183706f2543Smrg	    }
184706f2543Smrg	    break;
185706f2543Smrg
186706f2543Smrg	case _BEEP_FEATURE_OFF:
187706f2543Smrg	    if (name==None)	name= featureOff;
188706f2543Smrg	    if (xkbInfo->beepCount<1) {
189706f2543Smrg		pitch= MID_PITCH;
190706f2543Smrg		if (doesPitch)
191706f2543Smrg		     duration= VERY_LONG_TONE;
192706f2543Smrg		else duration= SHORT_TONE;
193706f2543Smrg		next= SHORT_DELAY;
194706f2543Smrg	    }
195706f2543Smrg	    else {
196706f2543Smrg		pitch= LOW_PITCH;
197706f2543Smrg		duration= SHORT_TONE;
198706f2543Smrg	    }
199706f2543Smrg	    break;
200706f2543Smrg
201706f2543Smrg	/* Two high beeps indicate an LED or Feature changed
202706f2543Smrg	 * state, but that another LED or Feature is also on.
203706f2543Smrg	 * [[[WDW - This is not in AccessDOS ]]]
204706f2543Smrg	 */
205706f2543Smrg	case _BEEP_LED_CHANGE:
206706f2543Smrg            if (name==None)	name= ledChange;
207706f2543Smrg	case _BEEP_FEATURE_CHANGE:
208706f2543Smrg	    if (name==None)	name= featureChange;
209706f2543Smrg	    duration= SHORT_TONE;
210706f2543Smrg	    pitch= HIGH_PITCH;
211706f2543Smrg	    if (xkbInfo->beepCount<1) {
212706f2543Smrg		next= SHORT_DELAY;
213706f2543Smrg	    }
214706f2543Smrg            break;
215706f2543Smrg
216706f2543Smrg	/* Three high-pitched beeps are the warning that SlowKeys
217706f2543Smrg	 * is going to be turned on or off.
218706f2543Smrg	 */
219706f2543Smrg	case _BEEP_SLOW_WARN:
220706f2543Smrg	    if (name==None)	name= slowWarn;
221706f2543Smrg	    duration= SHORT_TONE;
222706f2543Smrg	    pitch= HIGH_PITCH;
223706f2543Smrg	    if (xkbInfo->beepCount<2)
224706f2543Smrg		next= SHORT_DELAY;
225706f2543Smrg	    break;
226706f2543Smrg
227706f2543Smrg	/* Click on SlowKeys press and accept.
228706f2543Smrg	 * Deep pitch when a SlowKey or BounceKey is rejected.
229706f2543Smrg	 * [[[WDW - Rejects are not in AccessDOS ]]]
230706f2543Smrg	 * If we cannot do pitch, we want single beeps.
231706f2543Smrg	 */
232706f2543Smrg        case _BEEP_SLOW_PRESS:
233706f2543Smrg	    if (name==None)	name= slowPress;
234706f2543Smrg	case _BEEP_SLOW_ACCEPT:
235706f2543Smrg	    if (name==None)	name= slowAccept;
236706f2543Smrg	case _BEEP_SLOW_RELEASE:
237706f2543Smrg	    if (name==None)	name= slowRelease;
238706f2543Smrg	    duration= CLICK_DURATION;
239706f2543Smrg	    pitch= CLICK_PITCH;
240706f2543Smrg	    break;
241706f2543Smrg	case _BEEP_BOUNCE_REJECT:
242706f2543Smrg	    if (name==None)	name= bounceReject;
243706f2543Smrg	case _BEEP_SLOW_REJECT:
244706f2543Smrg	    if (name==None)	name= slowReject;
245706f2543Smrg	    duration= SHORT_TONE;
246706f2543Smrg	    pitch= DEEP_PITCH;
247706f2543Smrg	    break;
248706f2543Smrg
249706f2543Smrg	/* Low followed by high pitch when a StickyKey is latched.
250706f2543Smrg	 * High pitch when a StickyKey is locked.
251706f2543Smrg	 * Low pitch when unlocked.
252706f2543Smrg         * If we cannot do pitch, two beeps for latch, nothing for
253706f2543Smrg	 * lock, and two for unlock.
254706f2543Smrg	 */
255706f2543Smrg	case _BEEP_STICKY_LATCH:
256706f2543Smrg	    if (name==None)	name= stickyLatch;
257706f2543Smrg	    duration= SHORT_TONE;
258706f2543Smrg	    if (xkbInfo->beepCount<1) {
259706f2543Smrg		next= SHORT_DELAY;
260706f2543Smrg		pitch= LOW_PITCH;
261706f2543Smrg	    }
262706f2543Smrg	    else pitch= HIGH_PITCH;
263706f2543Smrg	    break;
264706f2543Smrg	case _BEEP_STICKY_LOCK:
265706f2543Smrg	    if (name==None)	name= stickyLock;
266706f2543Smrg	    if (doesPitch) {
267706f2543Smrg		duration= SHORT_TONE;
268706f2543Smrg		pitch= HIGH_PITCH;
269706f2543Smrg            }
270706f2543Smrg	    break;
271706f2543Smrg	case _BEEP_STICKY_UNLOCK:
272706f2543Smrg	    if (name==None)	name= stickyUnlock;
273706f2543Smrg	    duration= SHORT_TONE;
274706f2543Smrg	    pitch= LOW_PITCH;
275706f2543Smrg	    if (!doesPitch && xkbInfo->beepCount<1)
276706f2543Smrg		next = SHORT_DELAY;
277706f2543Smrg	    break;
278706f2543Smrg    }
279706f2543Smrg    if (timer == NULL && duration>0) {
280706f2543Smrg	CARD32		starttime = GetTimeInMillis();
281706f2543Smrg	CARD32		elapsedtime;
282706f2543Smrg
283706f2543Smrg	ctrl->bell_duration= duration;
284706f2543Smrg	ctrl->bell_pitch= pitch;
285706f2543Smrg	if (xkbInfo->beepCount==0) {
286706f2543Smrg	     XkbHandleBell(0,0,dev,ctrl->bell,(pointer)ctrl,KbdFeedbackClass,name,None,
287706f2543Smrg									NULL);
288706f2543Smrg	}
289706f2543Smrg	else if (xkbInfo->desc->ctrls->enabled_ctrls&XkbAudibleBellMask) {
290706f2543Smrg	    (*dev->kbdfeed->BellProc)(ctrl->bell,dev,(pointer)ctrl,KbdFeedbackClass);
291706f2543Smrg	}
292706f2543Smrg	ctrl->bell_duration= oldDuration;
293706f2543Smrg	ctrl->bell_pitch= oldPitch;
294706f2543Smrg	xkbInfo->beepCount++;
295706f2543Smrg
296706f2543Smrg	/* Some DDX schedule the beep and return immediately, others don't
297706f2543Smrg	   return until the beep is completed.  We measure the time and if
298706f2543Smrg	   it's less than the beep duration, make sure not to schedule the
299706f2543Smrg	   next beep until after the current one finishes. */
300706f2543Smrg
301706f2543Smrg	elapsedtime = GetTimeInMillis();
302706f2543Smrg	if (elapsedtime > starttime) { /* watch out for millisecond counter
303706f2543Smrg					  overflow! */
304706f2543Smrg	    elapsedtime -= starttime;
305706f2543Smrg	} else {
306706f2543Smrg	    elapsedtime = 0;
307706f2543Smrg	}
308706f2543Smrg	if (elapsedtime < duration) {
309706f2543Smrg	    next += duration - elapsedtime;
310706f2543Smrg	}
311706f2543Smrg
312706f2543Smrg    }
313706f2543Smrg    return next;
314706f2543Smrg}
315706f2543Smrg
316706f2543Smrgint
317706f2543SmrgXkbDDXAccessXBeep(DeviceIntPtr dev,unsigned what,unsigned which)
318706f2543Smrg{
319706f2543SmrgXkbSrvInfoRec	*xkbInfo= dev->key->xkbInfo;
320706f2543SmrgCARD32		 next;
321706f2543Smrg
322706f2543Smrg    xkbInfo->beepType= what;
323706f2543Smrg    xkbInfo->beepCount= 0;
324706f2543Smrg    next= _XkbDDXBeepExpire(NULL,0,(pointer)dev);
325706f2543Smrg    if (next>0) {
326706f2543Smrg	xkbInfo->beepTimer= TimerSet(xkbInfo->beepTimer,
327706f2543Smrg					0, next,
328706f2543Smrg					_XkbDDXBeepExpire, (pointer)dev);
329706f2543Smrg    }
330706f2543Smrg    return 1;
331706f2543Smrg}
332