1
/* $Xorg: xkbevd.c,v 1.4 2000/08/17 19:54:49 cpqbld Exp $ */
2
/************************************************************
3
Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
5
Permission to use, copy, modify, and distribute this
6
software and its documentation for any purpose and without
7
fee is hereby granted, provided that the above copyright
8
notice appear in all copies and that both that copyright
9
notice and this permission notice appear in supporting
10
documentation, and that the name of Silicon Graphics not be
11
used in advertising or publicity pertaining to distribution
12
of the software without specific prior written permission.
13
Silicon Graphics makes no representation about the suitability
14
of this software for any purpose. It is provided "as is"
15
without any express or implied warranty.
17
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
24
THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
********************************************************/
27
/* $XFree86: xc/programs/xkbevd/xkbevd.c,v 3.9 2001/07/25 15:05:25 dawes Exp $ */
29
#define DEBUG_VAR xkbevdDebug
30
#include <X11/Xosdefs.h>
35
#define lowbit(x) ((x) & (-(x)))
37
/***====================================================================***/
39
#ifndef DFLT_XKBEVD_CONFIG
40
#define DFLT_XKBEVD_CONFIG "%s/.xkb/xkbevd.cf"
41
#endif /* DFLT_XKBEVD_CONFIG */
43
#ifndef DFLT_XKB_CONFIG_ROOT
44
#define DFLT_XKB_CONFIG_ROOT "/usr/X11R6/lib/xkb"
47
#ifndef DFLT_SYS_XKBEVD_CONFIG
48
#define DFLT_SYS_XKBEVD_CONFIG "%s/xkbevd.cf"
49
#endif /* DFLT_SYS_XKBEVD_CONFIG */
51
#ifndef DFLT_SOUND_CMD
52
#define DFLT_SOUND_CMD "/usr/sbin/sfplay -q"
53
#endif /* DFLT_SOUND_CMD */
55
#ifndef DFLT_SOUND_DIR
56
#define DFLT_SOUND_DIR "/usr/share/data/sounds/prosonus/"
57
#endif /* DFLT_SOUND_DIR */
59
/***====================================================================***/
63
char * cfgFileName= NULL;
66
Bool detectableRepeat= False;
68
CfgEntryPtr config= NULL;
69
unsigned long eventMask= 0;
73
Bool background= False;
75
char * soundCmd= NULL;
76
char * soundDir= NULL;
80
/***====================================================================***/
82
#define M(m) fprintf(stderr,(m))
83
#define M1(m,a) fprintf(stderr,(m),(a))
86
Usage(int argc, char *argv[])
88
M1("Usage: %s [options]...\n",argv[0]);
89
M("Legal options:\n");
90
M("-?,-help Print this message\n");
91
M("-cfg <file> Specify a config file\n");
92
M("-sc <cmd> Specify the command to play sounds\n");
93
M("-sd <dir> Specify the root directory for sound files\n");
94
M("-d[isplay] <dpy> Specify the display to watch\n");
95
M("-bg Run in background\n");
96
M("-synch Force synchronization\n");
97
M("-v Print verbose messages\n");
101
/***====================================================================***/
104
parseArgs(int argc, char *argv[])
108
for (i=1;i<argc;i++) {
109
if (strcmp(argv[i],"-bg")==0) {
112
else if (strcmp(argv[i],"-cfg")==0) {
114
uError("No configuration file specified on command line\n");
115
uAction("Trailing %s argument ignored\n",argv[i]);
118
char *name= argv[++i];
119
if (cfgFileName!=NULL) {
120
if (uStringEqual(cfgFileName,name))
121
uWarning("Config file \"%s\" specified twice!\n");
123
uWarning("Multiple config files on command line\n");
124
uAction("Using \"%s\", ignoring \"%s\"\n",name,
131
else if ((strcmp(argv[i],"-d")==0)||(strcmp(argv[i],"-display")==0)) {
133
uError("No display specified on command line\n");
134
uAction("Trailing %s argument ignored\n",argv[i]);
137
char *name= argv[++i];
139
if (uStringEqual(dpyName,name))
140
uWarning("Display \"%s\" specified twice!\n");
142
uWarning("Multiple displays on command line\n");
143
uAction("Using \"%s\", ignoring \"%s\"\n",name,
150
else if (strcmp(argv[i],"-sc")==0) {
152
uError("No sound command specified on command line\n");
153
uAction("Trailing %s argument ignored\n",argv[i]);
156
char *name= argv[++i];
157
if (soundCmd!=NULL) {
158
if (uStringEqual(soundCmd,name))
159
uWarning("Sound command \"%s\" specified twice!\n");
161
uWarning("Multiple sound commands on command line\n");
162
uAction("Using \"%s\", ignoring \"%s\"\n",name,
169
else if (strcmp(argv[i],"-sd")==0) {
171
uError("No sound directory specified on command line\n");
172
uAction("Trailing %s argument ignored\n",argv[i]);
175
char *name= argv[++i];
176
if (soundDir!=NULL) {
177
if (uStringEqual(soundDir,name))
178
uWarning("Sound directory \"%s\" specified twice!\n");
180
uWarning("Multiple sound dirs on command line\n");
181
uAction("Using \"%s\", ignoring \"%s\"\n",name,
188
else if ((strcmp(argv[i],"-synch")==0)||(strcmp(argv[i],"-s")==0)) {
191
else if (strcmp(argv[i],"-v")==0) {
194
else if ((strcmp(argv[i],"-?")==0)||(strcmp(argv[i],"-help")==0)) {
199
uError("Unknown flag \"%s\" on command line\n",argv[i]);
208
GetDisplay(char *program, char *dpyName, int *opcodeRtrn, int *evBaseRtrn)
213
mjr= XkbMajorVersion;
214
mnr= XkbMinorVersion;
215
dpy= XkbOpenDisplay(dpyName,evBaseRtrn,NULL,&mjr,&mnr,&error);
218
case XkbOD_BadLibraryVersion:
219
uInformation("%s was compiled with XKB version %d.%02d\n",
220
program,XkbMajorVersion,XkbMinorVersion);
221
uError("X library supports incompatible version %d.%02d\n",
224
case XkbOD_ConnectionRefused:
225
uError("Cannot open display \"%s\"\n",dpyName);
227
case XkbOD_NonXkbServer:
228
uError("XKB extension not present on %s\n",dpyName);
230
case XkbOD_BadServerVersion:
231
uInformation("%s was compiled with XKB version %d.%02d\n",
232
program,XkbMajorVersion,XkbMinorVersion);
233
uError("Server %s uses incompatible version %d.%02d\n",
237
uInternalError("Unknown error %d from XkbOpenDisplay\n",error);
241
XSynchronize(dpy,True);
243
XkbQueryExtension(dpy,opcodeRtrn,evBaseRtrn,NULL,&mjr,&mnr);
247
/***====================================================================***/
250
InterpretConfigs(CfgEntryPtr cfg)
258
if (cfg->entry_type==VariableDef) {
259
if (uStrCaseEqual(name,"sounddirectory")||
260
uStrCaseEqual(name,"sounddir")) {
261
if (soundDir==NULL) {
262
soundDir= cfg->action.text;
264
cfg->action.text= NULL;
267
else if (uStrCaseEqual(name,"soundcommand")||
268
uStrCaseEqual(name,"soundcmd")) {
269
if (soundCmd==NULL) {
270
soundCmd= cfg->action.text;
272
cfg->action.text= NULL;
276
uWarning("Assignment to unknown variable \"%s\"\n",cfg->name);
277
uAction("Ignored\n");
280
else if (cfg->entry_type==EventDef) switch (cfg->event_type) {
282
if (name!=NULL) cfg->name.atom= XInternAtom(dpy,name,False);
283
else cfg->name.atom= None;
284
if (name) uFree(name);
286
case XkbAccessXNotify:
289
priv= XkbAllNewKeyboardEventsMask;
290
else if (uStrCaseEqual(name,"skpress"))
291
priv= XkbAXN_SKPressMask;
292
else if (uStrCaseEqual(name,"skaccept"))
293
priv= XkbAXN_SKAcceptMask;
294
else if (uStrCaseEqual(name,"skreject"))
295
priv= XkbAXN_SKRejectMask;
296
else if (uStrCaseEqual(name,"skrelease"))
297
priv= XkbAXN_SKReleaseMask;
298
else if (uStrCaseEqual(name,"bkaccept"))
299
priv= XkbAXN_BKAcceptMask;
300
else if (uStrCaseEqual(name,"bkreject"))
301
priv= XkbAXN_BKRejectMask;
302
else if (uStrCaseEqual(name,"warning"))
303
priv= XkbAXN_AXKWarningMask;
304
if (name) uFree(name);
305
cfg->name.priv= priv;
307
case XkbActionMessage:
311
eventMask|= (1L<<cfg->event_type);
314
while ((config)&&(config->entry_type!=EventDef)) {
316
if (config->name.str) uFree(config->name.str);
317
if (config->action.text) uFree(config->action.text);
318
config->name.str= NULL;
319
config->action.text= NULL;
325
while ((cfg!=NULL)&&(cfg->next!=NULL)) {
328
if (next->entry_type!=EventDef) {
329
if (next->name.str) uFree(config->name.str);
330
if (next->action.text) uFree(config->action.text);
331
next->name.str= NULL;
332
next->action.text= NULL;
333
cfg->next= next->next;
343
FindMatchingConfig(XkbEvent *ev)
345
CfgEntryPtr cfg,dflt;
348
for (cfg= config;(cfg!=NULL);cfg=cfg->next) {
349
if ((ev->type!=xkbEventCode)||(cfg->event_type!=ev->any.xkb_type))
351
switch (ev->any.xkb_type) {
353
if (ev->bell.name==cfg->name.atom)
355
else if ((cfg->name.atom==None)&&(dflt==NULL))
358
case XkbAccessXNotify:
359
if (cfg->name.priv&(1L<<ev->accessx.detail))
362
case XkbActionMessage:
363
if (cfg->name.str==NULL)
365
else if (strncmp(cfg->name.str,ev->message.message,
366
XkbActionMessageLength)==0)
370
uInternalError("Can't handle type %d XKB events yet, Sorry.\n");
378
ProcessMatchingConfig(XkbEvent *ev)
384
cfg= FindMatchingConfig(ev);
387
if (cfg->action.type==UnknownAction) {
388
if (cfg->action.text==NULL)
389
cfg->action.type= NoAction;
390
else if (cfg->action.text[0]=='!') {
392
cfg->action.type= ShellAction;
393
tmp= uStringDup(&cfg->action.text[1]);
394
uFree(cfg->action.text);
395
cfg->action.text= tmp;
397
else cfg->action.type= SoundAction;
399
switch (cfg->action.type) {
403
if (cfg->action.text!=NULL) {
404
sprintf(buf,cfg->action.text);
405
cmd= SubstituteEventArgs(buf,ev);
410
PrintXkbEvent(stdout,ev);
413
if (cfg->action.text==NULL) {
414
uWarning("Empty shell command!\n");
415
uAction("Ignored\n");
418
cmd= cfg->action.text;
421
if (cfg->action.text==NULL) {
422
uWarning("Empty sound command!\n");
423
uAction("Ignored\n");
426
sprintf(buf,"%s %s%s",soundCmd,soundDir,cfg->action.text);
430
uInternalError("Unknown error action type %d\n",cfg->action.type);
433
cmd= SubstituteEventArgs(cmd,ev);
435
uInformation("Executing shell command \"%s\"\n",cmd);
436
ok= (system(cmd)==0);
440
/***====================================================================***/
443
main(int argc, char *argv[])
446
static char buf[1024];
452
uSetEntryFile(NullString);
453
uSetDebugFile(NullString);
454
uSetErrorFile(NullString);
456
if (!parseArgs(argc,argv))
460
if (cfgFileName==NULL) {
462
home= (char *)getenv("HOME");
463
sprintf(buf,DFLT_XKBEVD_CONFIG,(home?home:""));
466
if (uStringEqual(cfgFileName,"-")) {
467
static char *in= "stdin";
472
file= fopen(cfgFileName,"r");
473
if (file==NULL) { /* no personal config, try for a system one */
474
if (cfgFileName!=buf) { /* user specified a file. bail */
475
uError("Can't open config file \"%s\n",cfgFileName);
476
uAction("Exiting\n");
479
sprintf(buf,DFLT_SYS_XKBEVD_CONFIG,DFLT_XKB_CONFIG_ROOT);
480
file= fopen(cfgFileName,"r");
483
uError("Couldn't find a config file anywhere\n");
484
uAction("Exiting\n");
495
uInformation("Running in the background\n");
499
dpy= GetDisplay(argv[0],dpyName,&xkbOpcode,&xkbEventCode);
503
setScanState(cfgFileName,1);
506
uError("No configuration specified in \"%s\"\n",cfgFileName);
510
uError("No events to watch in \"%s\"\n",cfgFileName);
513
if (!XkbSelectEvents(dpy,XkbUseCoreKbd,eventMask,eventMask)) {
514
uError("Couldn't select desired XKB events\n");
517
xkb= XkbGetKeyboard(dpy,XkbGBN_AllComponentsMask,XkbUseCoreKbd);
518
if (eventMask&XkbBellNotifyMask) {
521
uInformation("Temporarily disabling the audible bell\n");
522
if (!XkbChangeEnabledControls(dpy,XkbUseCoreKbd,XkbAudibleBellMask,0)) {
523
uError("Couldn't disable audible bell\n");
526
ctrls= vals= XkbAudibleBellMask;
527
if (!XkbSetAutoResetControls(dpy,XkbAudibleBellMask,&ctrls,&vals)) {
528
uWarning("Couldn't configure audible bell to reset on exit\n");
529
uAction("Audible bell might remain off\n");
532
if (soundCmd==NULL) soundCmd= DFLT_SOUND_CMD;
533
if (soundDir==NULL) soundDir= DFLT_SOUND_DIR;
534
XkbStdBellEvent(dpy,None,0,XkbBI_ImAlive);
536
XNextEvent(dpy,&ev.core);
537
if ((!ProcessMatchingConfig(&ev))&&(ev.type==xkbEventCode)&&
538
(ev.any.xkb_type==XkbBellNotify)) {
539
XkbForceDeviceBell(dpy,ev.bell.device,
540
ev.bell.bell_class,ev.bell.bell_id,
548
uAction("Exiting\n");