ddxBeep.c revision 706f2543
1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32#include <X11/X.h>
33#include <X11/Xproto.h>
34#include <X11/keysym.h>
35#include "inputstr.h"
36#include "scrnintstr.h"
37#include "windowstr.h"
38#include <xkbsrv.h>
39#include <X11/extensions/XI.h>
40
41/*#define FALLING_TONE	1*/
42/*#define RISING_TONE	1*/
43#define FALLING_TONE	10
44#define RISING_TONE	10
45#define	SHORT_TONE	50
46#define	SHORT_DELAY	60
47#define	LONG_TONE	75
48#define	VERY_LONG_TONE	100
49#define	LONG_DELAY	85
50#define CLICK_DURATION	1
51
52#define	DEEP_PITCH	250
53#define	LOW_PITCH	500
54#define	MID_PITCH	1000
55#define	HIGH_PITCH	2000
56#define CLICK_PITCH	1500
57
58static	unsigned long	atomGeneration= 0;
59static	Atom	featureOn;
60static	Atom	featureOff;
61static	Atom	featureChange;
62static	Atom	ledOn;
63static	Atom	ledOff;
64static	Atom	ledChange;
65static	Atom	slowWarn;
66static	Atom	slowPress;
67static	Atom	slowReject;
68static	Atom	slowAccept;
69static	Atom	slowRelease;
70static	Atom	stickyLatch;
71static	Atom	stickyLock;
72static	Atom	stickyUnlock;
73static	Atom	bounceReject;
74static  char 	doesPitch = 1;
75
76#define	FEATURE_ON	"AX_FeatureOn"
77#define	FEATURE_OFF	"AX_FeatureOff"
78#define	FEATURE_CHANGE	"AX_FeatureChange"
79#define	LED_ON		"AX_IndicatorOn"
80#define	LED_OFF		"AX_IndicatorOff"
81#define	LED_CHANGE	"AX_IndicatorChange"
82#define	SLOW_WARN	"AX_SlowKeysWarning"
83#define	SLOW_PRESS	"AX_SlowKeyPress"
84#define	SLOW_REJECT	"AX_SlowKeyReject"
85#define	SLOW_ACCEPT	"AX_SlowKeyAccept"
86#define	SLOW_RELEASE	"AX_SlowKeyRelease"
87#define	STICKY_LATCH	"AX_StickyLatch"
88#define	STICKY_LOCK	"AX_StickyLock"
89#define	STICKY_UNLOCK	"AX_StickyUnlock"
90#define	BOUNCE_REJECT	"AX_BounceKeyReject"
91
92#define	MAKE_ATOM(a)	MakeAtom(a,sizeof(a)-1,TRUE)
93
94static void
95_XkbDDXBeepInitAtoms(void)
96{
97    featureOn= 		MAKE_ATOM(FEATURE_ON);
98    featureOff= 	MAKE_ATOM(FEATURE_OFF);
99    featureChange= 	MAKE_ATOM(FEATURE_CHANGE);
100    ledOn= 		MAKE_ATOM(LED_ON);
101    ledOff= 		MAKE_ATOM(LED_OFF);
102    ledChange= 		MAKE_ATOM(LED_CHANGE);
103    slowWarn= 		MAKE_ATOM(SLOW_WARN);
104    slowPress= 		MAKE_ATOM(SLOW_PRESS);
105    slowReject= 	MAKE_ATOM(SLOW_REJECT);
106    slowAccept= 	MAKE_ATOM(SLOW_ACCEPT);
107    slowRelease= 	MAKE_ATOM(SLOW_RELEASE);
108    stickyLatch= 	MAKE_ATOM(STICKY_LATCH);
109    stickyLock=		MAKE_ATOM(STICKY_LOCK);
110    stickyUnlock= 	MAKE_ATOM(STICKY_UNLOCK);
111    bounceReject= 	MAKE_ATOM(BOUNCE_REJECT);
112    return;
113}
114
115static CARD32
116_XkbDDXBeepExpire(OsTimerPtr timer,CARD32 now,pointer arg)
117{
118DeviceIntPtr	dev= (DeviceIntPtr)arg;
119KbdFeedbackPtr	feed;
120KeybdCtrl *	ctrl;
121XkbSrvInfoPtr	xkbInfo;
122CARD32		next;
123int		pitch,duration;
124int		oldPitch,oldDuration;
125Atom		name;
126
127    if ((dev==NULL)||(dev->key==NULL)||(dev->key->xkbInfo==NULL)||
128	(dev->kbdfeed==NULL))
129	return 0;
130    if (atomGeneration!=serverGeneration) {
131	_XkbDDXBeepInitAtoms();
132	atomGeneration= serverGeneration;
133    }
134
135    feed= dev->kbdfeed;
136    ctrl= &feed->ctrl;
137    xkbInfo= dev->key->xkbInfo;
138    next= 0;
139    pitch= oldPitch= ctrl->bell_pitch;
140    duration= oldDuration= ctrl->bell_duration;
141    name= None;
142    switch (xkbInfo->beepType) {
143	default:
144	    ErrorF("[xkb] Unknown beep type %d\n",xkbInfo->beepType);
145	case _BEEP_NONE:
146	    duration= 0;
147	    break;
148
149	/* When an LED is turned on, we want a high-pitched beep.
150	 * When the LED it turned off, we want a low-pitched beep.
151	 * If we cannot do pitch, we want a single beep for on and two
152	 * beeps for off.
153         */
154	case _BEEP_LED_ON:
155	    if (name==None)	name= ledOn;
156	    duration= SHORT_TONE;
157	    pitch= HIGH_PITCH;
158	    break;
159	case _BEEP_LED_OFF:
160	    if (name==None)	name= ledOff;
161	    duration= SHORT_TONE;
162	    pitch= LOW_PITCH;
163	    if (!doesPitch && xkbInfo->beepCount<1)
164		next = SHORT_DELAY;
165	    break;
166
167	/* When a Feature is turned on, we want an up-siren.
168	 * When a Feature is turned off, we want a down-siren.
169	 * If we cannot do pitch, we want a single beep for on and two
170	 * beeps for off.
171         */
172	case _BEEP_FEATURE_ON:
173	    if (name==None)	name= featureOn;
174	    if (xkbInfo->beepCount<1) {
175		pitch= LOW_PITCH;
176		duration= VERY_LONG_TONE;
177		if (doesPitch)
178		    next= SHORT_DELAY;
179	    }
180	    else {
181		pitch= MID_PITCH;
182		duration= SHORT_TONE;
183	    }
184	    break;
185
186	case _BEEP_FEATURE_OFF:
187	    if (name==None)	name= featureOff;
188	    if (xkbInfo->beepCount<1) {
189		pitch= MID_PITCH;
190		if (doesPitch)
191		     duration= VERY_LONG_TONE;
192		else duration= SHORT_TONE;
193		next= SHORT_DELAY;
194	    }
195	    else {
196		pitch= LOW_PITCH;
197		duration= SHORT_TONE;
198	    }
199	    break;
200
201	/* Two high beeps indicate an LED or Feature changed
202	 * state, but that another LED or Feature is also on.
203	 * [[[WDW - This is not in AccessDOS ]]]
204	 */
205	case _BEEP_LED_CHANGE:
206            if (name==None)	name= ledChange;
207	case _BEEP_FEATURE_CHANGE:
208	    if (name==None)	name= featureChange;
209	    duration= SHORT_TONE;
210	    pitch= HIGH_PITCH;
211	    if (xkbInfo->beepCount<1) {
212		next= SHORT_DELAY;
213	    }
214            break;
215
216	/* Three high-pitched beeps are the warning that SlowKeys
217	 * is going to be turned on or off.
218	 */
219	case _BEEP_SLOW_WARN:
220	    if (name==None)	name= slowWarn;
221	    duration= SHORT_TONE;
222	    pitch= HIGH_PITCH;
223	    if (xkbInfo->beepCount<2)
224		next= SHORT_DELAY;
225	    break;
226
227	/* Click on SlowKeys press and accept.
228	 * Deep pitch when a SlowKey or BounceKey is rejected.
229	 * [[[WDW - Rejects are not in AccessDOS ]]]
230	 * If we cannot do pitch, we want single beeps.
231	 */
232        case _BEEP_SLOW_PRESS:
233	    if (name==None)	name= slowPress;
234	case _BEEP_SLOW_ACCEPT:
235	    if (name==None)	name= slowAccept;
236	case _BEEP_SLOW_RELEASE:
237	    if (name==None)	name= slowRelease;
238	    duration= CLICK_DURATION;
239	    pitch= CLICK_PITCH;
240	    break;
241	case _BEEP_BOUNCE_REJECT:
242	    if (name==None)	name= bounceReject;
243	case _BEEP_SLOW_REJECT:
244	    if (name==None)	name= slowReject;
245	    duration= SHORT_TONE;
246	    pitch= DEEP_PITCH;
247	    break;
248
249	/* Low followed by high pitch when a StickyKey is latched.
250	 * High pitch when a StickyKey is locked.
251	 * Low pitch when unlocked.
252         * If we cannot do pitch, two beeps for latch, nothing for
253	 * lock, and two for unlock.
254	 */
255	case _BEEP_STICKY_LATCH:
256	    if (name==None)	name= stickyLatch;
257	    duration= SHORT_TONE;
258	    if (xkbInfo->beepCount<1) {
259		next= SHORT_DELAY;
260		pitch= LOW_PITCH;
261	    }
262	    else pitch= HIGH_PITCH;
263	    break;
264	case _BEEP_STICKY_LOCK:
265	    if (name==None)	name= stickyLock;
266	    if (doesPitch) {
267		duration= SHORT_TONE;
268		pitch= HIGH_PITCH;
269            }
270	    break;
271	case _BEEP_STICKY_UNLOCK:
272	    if (name==None)	name= stickyUnlock;
273	    duration= SHORT_TONE;
274	    pitch= LOW_PITCH;
275	    if (!doesPitch && xkbInfo->beepCount<1)
276		next = SHORT_DELAY;
277	    break;
278    }
279    if (timer == NULL && duration>0) {
280	CARD32		starttime = GetTimeInMillis();
281	CARD32		elapsedtime;
282
283	ctrl->bell_duration= duration;
284	ctrl->bell_pitch= pitch;
285	if (xkbInfo->beepCount==0) {
286	     XkbHandleBell(0,0,dev,ctrl->bell,(pointer)ctrl,KbdFeedbackClass,name,None,
287									NULL);
288	}
289	else if (xkbInfo->desc->ctrls->enabled_ctrls&XkbAudibleBellMask) {
290	    (*dev->kbdfeed->BellProc)(ctrl->bell,dev,(pointer)ctrl,KbdFeedbackClass);
291	}
292	ctrl->bell_duration= oldDuration;
293	ctrl->bell_pitch= oldPitch;
294	xkbInfo->beepCount++;
295
296	/* Some DDX schedule the beep and return immediately, others don't
297	   return until the beep is completed.  We measure the time and if
298	   it's less than the beep duration, make sure not to schedule the
299	   next beep until after the current one finishes. */
300
301	elapsedtime = GetTimeInMillis();
302	if (elapsedtime > starttime) { /* watch out for millisecond counter
303					  overflow! */
304	    elapsedtime -= starttime;
305	} else {
306	    elapsedtime = 0;
307	}
308	if (elapsedtime < duration) {
309	    next += duration - elapsedtime;
310	}
311
312    }
313    return next;
314}
315
316int
317XkbDDXAccessXBeep(DeviceIntPtr dev,unsigned what,unsigned which)
318{
319XkbSrvInfoRec	*xkbInfo= dev->key->xkbInfo;
320CARD32		 next;
321
322    xkbInfo->beepType= what;
323    xkbInfo->beepCount= 0;
324    next= _XkbDDXBeepExpire(NULL,0,(pointer)dev);
325    if (next>0) {
326	xkbInfo->beepTimer= TimerSet(xkbInfo->beepTimer,
327					0, next,
328					_XkbDDXBeepExpire, (pointer)dev);
329    }
330    return 1;
331}
332