xkbevd.c revision db17cd6d
176910425Smrg/* $Xorg: xkbevd.c,v 1.4 2000/08/17 19:54:49 cpqbld Exp $ */
276910425Smrg/************************************************************
376910425Smrg Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
476910425Smrg
576910425Smrg Permission to use, copy, modify, and distribute this
676910425Smrg software and its documentation for any purpose and without
776910425Smrg fee is hereby granted, provided that the above copyright
876910425Smrg notice appear in all copies and that both that copyright
976910425Smrg notice and this permission notice appear in supporting
1076910425Smrg documentation, and that the name of Silicon Graphics not be
1176910425Smrg used in advertising or publicity pertaining to distribution
1276910425Smrg of the software without specific prior written permission.
1376910425Smrg Silicon Graphics makes no representation about the suitability
1476910425Smrg of this software for any purpose. It is provided "as is"
1576910425Smrg without any express or implied warranty.
1676910425Smrg
1776910425Smrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1876910425Smrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1976910425Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
2076910425Smrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2176910425Smrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2276910425Smrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2376910425Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
2476910425Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
2576910425Smrg
2676910425Smrg ********************************************************/
2776910425Smrg/* $XFree86: xc/programs/xkbevd/xkbevd.c,v 3.8 2001/01/17 23:46:09 dawes Exp $ */
2876910425Smrg
2976910425Smrg#define	DEBUG_VAR xkbevdDebug
3076910425Smrg#include <X11/Xosdefs.h>
3176910425Smrg#include <stdlib.h>
3276910425Smrg#include "xkbevd.h"
3376910425Smrg
3476910425Smrg
3576910425Smrg#define	lowbit(x)	((x) & (-(x)))
3676910425Smrg
3776910425Smrg/***====================================================================***/
3876910425Smrg
3976910425Smrg#ifndef DFLT_XKBEVD_CONFIG
4076910425Smrg#define DFLT_XKBEVD_CONFIG "%s/.xkb/xkbevd.cf"
4176910425Smrg#endif /* DFLT_XKBEVD_CONFIG */
4276910425Smrg
4376910425Smrg#ifndef DFLT_XKB_CONFIG_ROOT
4476910425Smrg#define	DFLT_XKB_CONFIG_ROOT "/usr/X11R6/lib/xkb"
4576910425Smrg#endif
4676910425Smrg
4776910425Smrg#ifndef DFLT_SYS_XKBEVD_CONFIG
4876910425Smrg#define DFLT_SYS_XKBEVD_CONFIG "%s/xkbevd.cf"
4976910425Smrg#endif /* DFLT_SYS_XKBEVD_CONFIG */
5076910425Smrg
5176910425Smrg#ifndef DFLT_SOUND_CMD
5276910425Smrg#define	DFLT_SOUND_CMD "/usr/sbin/sfplay -q"
5376910425Smrg#endif /* DFLT_SOUND_CMD */
5476910425Smrg
5576910425Smrg#ifndef DFLT_SOUND_DIR
5676910425Smrg#define	DFLT_SOUND_DIR "/usr/share/data/sounds/prosonus/"
5776910425Smrg#endif /* DFLT_SOUND_DIR */
5876910425Smrg
5976910425Smrg/***====================================================================***/
6076910425Smrg
61db17cd6dSmrgstatic char *	dpyName=	NULL;
6276910425SmrgDisplay *	dpy=		NULL;
63db17cd6dSmrgstatic char *	cfgFileName=	NULL;
6476910425Smrgint		xkbOpcode=	0;
6576910425Smrgint		xkbEventCode=	0;
6676910425SmrgBool		detectableRepeat= False;
6776910425Smrg
68db17cd6dSmrgstatic
6976910425SmrgCfgEntryPtr	config=		NULL;
70db17cd6dSmrgstatic
7176910425Smrgunsigned long	eventMask=	0;
7276910425Smrg
73db17cd6dSmrgstatic Bool	synch=		False;
74db17cd6dSmrgstatic int	verbose=	0;
75db17cd6dSmrgstatic Bool	background=	False;
7676910425Smrg
77db17cd6dSmrgstatic char *	soundCmd=	NULL;
78db17cd6dSmrgstatic char *	soundDir=	NULL;
7976910425Smrg
8076910425SmrgXkbDescPtr	xkb=		NULL;
8176910425Smrg
8276910425Smrg/***====================================================================***/
8376910425Smrg
8476910425Smrg#define	M(m)	fprintf(stderr,(m))
8576910425Smrg#define	M1(m,a)	fprintf(stderr,(m),(a))
8676910425Smrg
8776910425Smrgstatic void
8876910425SmrgUsage(int argc, char *argv[])
8976910425Smrg{
9076910425Smrg    M1("Usage: %s [options]...\n",argv[0]);
9176910425Smrg    M("Legal options:\n");
9276910425Smrg    M("-?,-help             Print this message\n");
9376910425Smrg    M("-cfg <file>          Specify a config file\n");
9476910425Smrg    M("-sc <cmd>            Specify the command to play sounds\n");
9576910425Smrg    M("-sd <dir>            Specify the root directory for sound files\n");
9676910425Smrg    M("-d[isplay] <dpy>     Specify the display to watch\n");
9776910425Smrg    M("-bg                  Run in background\n");
9876910425Smrg    M("-synch               Force synchronization\n");
9976910425Smrg    M("-v                   Print verbose messages\n");
10076910425Smrg    return;
10176910425Smrg}
10276910425Smrg
10376910425Smrg/***====================================================================***/
10476910425Smrg
10576910425Smrgstatic Bool
10676910425SmrgparseArgs(int argc, char *argv[])
10776910425Smrg{
10876910425Smrgregister int i;
10976910425Smrg
11076910425Smrg    for (i=1;i<argc;i++) {
11176910425Smrg	if (strcmp(argv[i],"-bg")==0) {
11276910425Smrg	    background= True;
11376910425Smrg	}
11476910425Smrg	else if (strcmp(argv[i],"-cfg")==0) {
11576910425Smrg	    if (i>=(argc-1)) {
11676910425Smrg		uError("No configuration file specified on command line\n");
11776910425Smrg		uAction("Trailing %s argument ignored\n",argv[i]);
11876910425Smrg	    }
11976910425Smrg	    else {
12076910425Smrg		char *name= argv[++i];
12176910425Smrg		if (cfgFileName!=NULL) {
12276910425Smrg		    if (uStringEqual(cfgFileName,name))
12376910425Smrg			uWarning("Config file \"%s\" specified twice!\n");
12476910425Smrg		    else {
12576910425Smrg			uWarning("Multiple config files on command line\n");
12676910425Smrg			uAction("Using \"%s\", ignoring \"%s\"\n",name,
12776910425Smrg								cfgFileName);
12876910425Smrg		    }
12976910425Smrg		}
13076910425Smrg		cfgFileName= name;
13176910425Smrg	    }
13276910425Smrg	}
13376910425Smrg	else if ((strcmp(argv[i],"-d")==0)||(strcmp(argv[i],"-display")==0)) {
13476910425Smrg	    if (i>=(argc-1)) {
13576910425Smrg		uError("No display specified on command line\n");
13676910425Smrg		uAction("Trailing %s argument ignored\n",argv[i]);
13776910425Smrg	    }
13876910425Smrg	    else {
13976910425Smrg		char *name= argv[++i];
14076910425Smrg		if (dpyName!=NULL) {
14176910425Smrg		    if (uStringEqual(dpyName,name))
14276910425Smrg			uWarning("Display \"%s\" specified twice!\n");
14376910425Smrg		    else {
14476910425Smrg			uWarning("Multiple displays on command line\n");
14576910425Smrg			uAction("Using \"%s\", ignoring \"%s\"\n",name,
14676910425Smrg								dpyName);
14776910425Smrg		    }
14876910425Smrg		}
14976910425Smrg		dpyName= name;
15076910425Smrg	    }
15176910425Smrg	}
15276910425Smrg	else if (strcmp(argv[i],"-sc")==0) {
15376910425Smrg	    if (i>=(argc-1)) {
15476910425Smrg		uError("No sound command specified on command line\n");
15576910425Smrg		uAction("Trailing %s argument ignored\n",argv[i]);
15676910425Smrg	    }
15776910425Smrg	    else {
15876910425Smrg		char *name= argv[++i];
15976910425Smrg		if (soundCmd!=NULL) {
16076910425Smrg		    if (uStringEqual(soundCmd,name))
16176910425Smrg			uWarning("Sound command \"%s\" specified twice!\n");
16276910425Smrg		    else {
16376910425Smrg			uWarning("Multiple sound commands on command line\n");
16476910425Smrg			uAction("Using \"%s\", ignoring \"%s\"\n",name,
16576910425Smrg								soundCmd);
16676910425Smrg		    }
16776910425Smrg		}
16876910425Smrg		soundCmd= name;
16976910425Smrg	    }
17076910425Smrg	}
17176910425Smrg	else if (strcmp(argv[i],"-sd")==0) {
17276910425Smrg	    if (i>=(argc-1)) {
17376910425Smrg		uError("No sound directory specified on command line\n");
17476910425Smrg		uAction("Trailing %s argument ignored\n",argv[i]);
17576910425Smrg	    }
17676910425Smrg	    else {
17776910425Smrg		char *name= argv[++i];
17876910425Smrg		if (soundDir!=NULL) {
17976910425Smrg		    if (uStringEqual(soundDir,name))
18076910425Smrg			uWarning("Sound directory \"%s\" specified twice!\n");
18176910425Smrg		    else {
18276910425Smrg			uWarning("Multiple sound dirs on command line\n");
18376910425Smrg			uAction("Using \"%s\", ignoring \"%s\"\n",name,
18476910425Smrg								soundDir);
18576910425Smrg		    }
18676910425Smrg		}
18776910425Smrg		soundDir= name;
18876910425Smrg	    }
18976910425Smrg	}
19076910425Smrg	else if ((strcmp(argv[i],"-synch")==0)||(strcmp(argv[i],"-s")==0)) {
19176910425Smrg	    synch= True;
19276910425Smrg	}
19376910425Smrg	else if (strcmp(argv[i],"-v")==0) {
19476910425Smrg	    verbose++;
19576910425Smrg	}
19676910425Smrg	else if ((strcmp(argv[i],"-?")==0)||(strcmp(argv[i],"-help")==0)) {
19776910425Smrg	    Usage(argc,argv);
19876910425Smrg	    exit(0);
19976910425Smrg	}
20076910425Smrg	else {
20176910425Smrg	    uError("Unknown flag \"%s\" on command line\n",argv[i]);
20276910425Smrg	    Usage(argc,argv);
20376910425Smrg	    return False;
20476910425Smrg	}
20576910425Smrg    }
206db17cd6dSmrg    if (background == False) {
207db17cd6dSmrg	eventMask = XkbAllEventsMask;
208db17cd6dSmrg	verbose++;
209db17cd6dSmrg    }
210db17cd6dSmrg
21176910425Smrg    return True;
21276910425Smrg}
21376910425Smrg
21476910425Smrgstatic Display *
21576910425SmrgGetDisplay(char *program, char *dpyName, int *opcodeRtrn, int *evBaseRtrn)
21676910425Smrg{
21776910425Smrgint	mjr,mnr,error;
21876910425SmrgDisplay	*dpy;
21976910425Smrg
22076910425Smrg    mjr= XkbMajorVersion;
22176910425Smrg    mnr= XkbMinorVersion;
22276910425Smrg    dpy= XkbOpenDisplay(dpyName,evBaseRtrn,NULL,&mjr,&mnr,&error);
22376910425Smrg    if (dpy==NULL) {
22476910425Smrg	switch (error) {
22576910425Smrg	    case XkbOD_BadLibraryVersion:
22676910425Smrg		uInformation("%s was compiled with XKB version %d.%02d\n",
22776910425Smrg				program,XkbMajorVersion,XkbMinorVersion);
22876910425Smrg		uError("X library supports incompatible version %d.%02d\n",
22976910425Smrg				mjr,mnr);
23076910425Smrg		break;
23176910425Smrg	    case XkbOD_ConnectionRefused:
23276910425Smrg		uError("Cannot open display \"%s\"\n",dpyName);
23376910425Smrg		break;
23476910425Smrg	    case XkbOD_NonXkbServer:
23576910425Smrg		uError("XKB extension not present on %s\n",dpyName);
23676910425Smrg		break;
23776910425Smrg	    case XkbOD_BadServerVersion:
23876910425Smrg		uInformation("%s was compiled with XKB version %d.%02d\n",
23976910425Smrg				program,XkbMajorVersion,XkbMinorVersion);
24076910425Smrg		uError("Server %s uses incompatible version %d.%02d\n",
24176910425Smrg				dpyName,mjr,mnr);
24276910425Smrg		break;
24376910425Smrg	    default:
24476910425Smrg		uInternalError("Unknown error %d from XkbOpenDisplay\n",error);
24576910425Smrg	}
24676910425Smrg    }
24776910425Smrg    else if (synch)
24876910425Smrg	XSynchronize(dpy,True);
24976910425Smrg    if (opcodeRtrn)
25076910425Smrg	XkbQueryExtension(dpy,opcodeRtrn,evBaseRtrn,NULL,&mjr,&mnr);
25176910425Smrg    return dpy;
25276910425Smrg}
25376910425Smrg
25476910425Smrg/***====================================================================***/
25576910425Smrg
25676910425Smrgvoid
25776910425SmrgInterpretConfigs(CfgEntryPtr cfg)
25876910425Smrg{
25976910425Smrgchar *		name;
26076910425Smrgunsigned	priv= 0;
26176910425Smrg
26276910425Smrg    config= cfg;
26376910425Smrg    while (cfg!=NULL) {
26476910425Smrg	name= cfg->name.str;
26576910425Smrg	if (cfg->entry_type==VariableDef) {
26676910425Smrg	    if (uStrCaseEqual(name,"sounddirectory")||
26776910425Smrg					uStrCaseEqual(name,"sounddir")) {
26876910425Smrg		if (soundDir==NULL) {
26976910425Smrg		    soundDir= cfg->action.text;
27076910425Smrg		    cfg->name.str= NULL;
27176910425Smrg		    cfg->action.text= NULL;
27276910425Smrg		}
27376910425Smrg	    }
27476910425Smrg	    else if (uStrCaseEqual(name,"soundcommand")||
27576910425Smrg				uStrCaseEqual(name,"soundcmd")) {
27676910425Smrg		if (soundCmd==NULL) {
27776910425Smrg		    soundCmd= cfg->action.text;
27876910425Smrg		    cfg->name.str= NULL;
27976910425Smrg		    cfg->action.text= NULL;
28076910425Smrg		}
28176910425Smrg	    }
28276910425Smrg	    else {
28376910425Smrg		uWarning("Assignment to unknown variable \"%s\"\n",cfg->name);
28476910425Smrg		uAction("Ignored\n");
28576910425Smrg	    }
28676910425Smrg	}
28776910425Smrg	else if (cfg->entry_type==EventDef) switch (cfg->event_type) {
28876910425Smrg	    case XkbBellNotify:
28976910425Smrg		if (name!=NULL)	cfg->name.atom= XInternAtom(dpy,name,False);
29076910425Smrg		else 		cfg->name.atom= None;
29176910425Smrg		if (name) uFree(name);
29276910425Smrg		break;
29376910425Smrg	    case XkbAccessXNotify:
29476910425Smrg		priv= 0;
29576910425Smrg		if (name==NULL)
29676910425Smrg		     priv= XkbAllNewKeyboardEventsMask;
29776910425Smrg		else if (uStrCaseEqual(name,"skpress"))
29876910425Smrg		     priv= XkbAXN_SKPressMask;
29976910425Smrg		else if (uStrCaseEqual(name,"skaccept"))
30076910425Smrg		     priv= XkbAXN_SKAcceptMask;
30176910425Smrg		else if (uStrCaseEqual(name,"skreject"))
30276910425Smrg		     priv= XkbAXN_SKRejectMask;
30376910425Smrg		else if (uStrCaseEqual(name,"skrelease"))
30476910425Smrg		     priv= XkbAXN_SKReleaseMask;
30576910425Smrg		else if (uStrCaseEqual(name,"bkaccept"))
30676910425Smrg		     priv= XkbAXN_BKAcceptMask;
30776910425Smrg		else if (uStrCaseEqual(name,"bkreject"))
30876910425Smrg		     priv= XkbAXN_BKRejectMask;
30976910425Smrg		else if (uStrCaseEqual(name,"warning"))
31076910425Smrg		     priv= XkbAXN_AXKWarningMask;
31176910425Smrg		if (name)	uFree(name);
31276910425Smrg		cfg->name.priv= priv;
31376910425Smrg		break;
31476910425Smrg	    case XkbActionMessage:
31576910425Smrg		/* nothing to do */
31676910425Smrg		break;
31776910425Smrg	}
31876910425Smrg	eventMask|= (1L<<cfg->event_type);
31976910425Smrg	cfg= cfg->next;
32076910425Smrg    }
32176910425Smrg    while ((config)&&(config->entry_type!=EventDef)) {
32276910425Smrg	CfgEntryPtr next;
32376910425Smrg	if (config->name.str)		uFree(config->name.str);
32476910425Smrg	if (config->action.text)	uFree(config->action.text);
32576910425Smrg	config->name.str= 	NULL;
32676910425Smrg	config->action.text=	NULL;
32776910425Smrg	next= 			config->next;
32876910425Smrg	uFree(config);
32976910425Smrg	config= next;
33076910425Smrg    }
33176910425Smrg    cfg= config;
33276910425Smrg    while ((cfg!=NULL)&&(cfg->next!=NULL)) {
33376910425Smrg	CfgEntryPtr next;
33476910425Smrg	next= cfg->next;
33576910425Smrg	if (next->entry_type!=EventDef) {
33676910425Smrg	    if (next->name.str)		uFree(config->name.str);
33776910425Smrg	    if (next->action.text)	uFree(config->action.text);
33876910425Smrg	    next->name.str=		NULL;
33976910425Smrg	    next->action.text=		NULL;
34076910425Smrg	    cfg->next= 			next->next;
34176910425Smrg	    next->next=			NULL;
34276910425Smrg	    uFree(next);
34376910425Smrg	}
34476910425Smrg	else cfg= next;
34576910425Smrg    }
34676910425Smrg    return;
34776910425Smrg}
34876910425Smrg
34976910425Smrgstatic CfgEntryPtr
35076910425SmrgFindMatchingConfig(XkbEvent *ev)
35176910425Smrg{
35276910425SmrgCfgEntryPtr	cfg,dflt;
35376910425Smrg
35476910425Smrg    dflt= NULL;
35576910425Smrg    for (cfg= config;(cfg!=NULL);cfg=cfg->next) {
35676910425Smrg	if ((ev->type!=xkbEventCode)||(cfg->event_type!=ev->any.xkb_type))
35776910425Smrg	    continue;
35876910425Smrg	switch (ev->any.xkb_type) {
35976910425Smrg	   case XkbBellNotify:
36076910425Smrg		if (ev->bell.name==cfg->name.atom)
36176910425Smrg		    return cfg;
36276910425Smrg		else if ((cfg->name.atom==None)&&(dflt==NULL))
36376910425Smrg		    dflt= cfg;
36476910425Smrg		break;
36576910425Smrg	    case XkbAccessXNotify:
36676910425Smrg		if (cfg->name.priv&(1L<<ev->accessx.detail))
36776910425Smrg		    return cfg;
36876910425Smrg		break;
36976910425Smrg	    case XkbActionMessage:
37076910425Smrg		if (cfg->name.str==NULL)
37176910425Smrg		    dflt= cfg;
37276910425Smrg		else if (strncmp(cfg->name.str,ev->message.message,
37376910425Smrg						XkbActionMessageLength)==0)
37476910425Smrg		    return cfg;
37576910425Smrg		break;
37676910425Smrg	   default:
37776910425Smrg		uInternalError("Can't handle type %d XKB events yet, Sorry.\n");
37876910425Smrg		break;
37976910425Smrg	}
38076910425Smrg    }
38176910425Smrg    return dflt;
38276910425Smrg}
38376910425Smrg
38476910425Smrgstatic Bool
38576910425SmrgProcessMatchingConfig(XkbEvent *ev)
38676910425Smrg{
38776910425SmrgCfgEntryPtr	cfg;
38876910425Smrgchar		buf[1024],*cmd;
38976910425Smrgint		ok;
39076910425Smrg
39176910425Smrg    cfg= FindMatchingConfig(ev);
392db17cd6dSmrg    if (!cfg) {
393db17cd6dSmrg	if (verbose)
394db17cd6dSmrg	    PrintXkbEvent(stdout,ev);
39576910425Smrg	return False;
396db17cd6dSmrg    }
39776910425Smrg    if (cfg->action.type==UnknownAction) {
39876910425Smrg	if (cfg->action.text==NULL)
39976910425Smrg	    cfg->action.type= NoAction;
40076910425Smrg	else if (cfg->action.text[0]=='!') {
40176910425Smrg	    char *tmp;
40276910425Smrg	    cfg->action.type= ShellAction;
40376910425Smrg	    tmp= uStringDup(&cfg->action.text[1]);
40476910425Smrg	    uFree(cfg->action.text);
40576910425Smrg	    cfg->action.text= tmp;
40676910425Smrg	}
40776910425Smrg	else cfg->action.type= SoundAction;
40876910425Smrg    }
40976910425Smrg    switch (cfg->action.type) {
41076910425Smrg	case NoAction:
41176910425Smrg	    return True;
41276910425Smrg	case EchoAction:
41376910425Smrg	    if (cfg->action.text!=NULL) {
414db17cd6dSmrg		sprintf(buf,"%s",cfg->action.text);
41576910425Smrg		cmd= SubstituteEventArgs(buf,ev);
41676910425Smrg		printf("%s",cmd);
41776910425Smrg	    }
41876910425Smrg	    return True;
41976910425Smrg	case PrintEvAction:
42076910425Smrg	    PrintXkbEvent(stdout,ev);
42176910425Smrg	    return True;
42276910425Smrg	case ShellAction:
42376910425Smrg	    if (cfg->action.text==NULL) {
42476910425Smrg		uWarning("Empty shell command!\n");
42576910425Smrg		uAction("Ignored\n");
42676910425Smrg		return True;
42776910425Smrg	    }
42876910425Smrg	    cmd= cfg->action.text;
42976910425Smrg	    break;
43076910425Smrg	case SoundAction:
43176910425Smrg	    if (cfg->action.text==NULL) {
43276910425Smrg		uWarning("Empty sound command!\n");
43376910425Smrg		uAction("Ignored\n");
43476910425Smrg		return True;
43576910425Smrg	    }
43676910425Smrg	    sprintf(buf,"%s %s%s",soundCmd,soundDir,cfg->action.text);
43776910425Smrg	    cmd= buf;
43876910425Smrg	    break;
43976910425Smrg	default:
44076910425Smrg	    uInternalError("Unknown error action type %d\n",cfg->action.type);
44176910425Smrg	    return False;
44276910425Smrg    }
44376910425Smrg    cmd= SubstituteEventArgs(cmd,ev);
44476910425Smrg    if (verbose)
44576910425Smrg	uInformation("Executing shell command \"%s\"\n",cmd);
44676910425Smrg    ok= (system(cmd)==0);
44776910425Smrg    return ok;
44876910425Smrg}
44976910425Smrg
45076910425Smrg/***====================================================================***/
45176910425Smrg
45276910425Smrgint
45376910425Smrgmain(int argc, char *argv[])
45476910425Smrg{
45576910425SmrgFILE 	*	file;
45676910425Smrgstatic char 	buf[1024];
45776910425SmrgXkbEvent	ev;
45876910425SmrgBool		ok;
45976910425Smrg
46076910425Smrg
46176910425Smrg    yyin = stdin;
46276910425Smrg    uSetEntryFile(NullString);
46376910425Smrg    uSetDebugFile(NullString);
46476910425Smrg    uSetErrorFile(NullString);
46576910425Smrg
46676910425Smrg    if (!parseArgs(argc,argv))
46776910425Smrg	exit(1);
46876910425Smrg    file= NULL;
46976910425Smrg    XkbInitAtoms(NULL);
47076910425Smrg    if (cfgFileName==NULL) {
47176910425Smrg	char *home;
47276910425Smrg	home= (char *)getenv("HOME");
47376910425Smrg	sprintf(buf,DFLT_XKBEVD_CONFIG,(home?home:""));
47476910425Smrg	cfgFileName= buf;
47576910425Smrg    }
47676910425Smrg    if (uStringEqual(cfgFileName,"-")) {
47776910425Smrg	static char *in= "stdin";
47876910425Smrg	file= stdin;
47976910425Smrg	cfgFileName= in;
48076910425Smrg    }
48176910425Smrg    else {
48276910425Smrg	file= fopen(cfgFileName,"r");
48376910425Smrg	if (file==NULL) { /* no personal config, try for a system one */
48476910425Smrg	    if (cfgFileName!=buf) { /* user specified a file.  bail */
48576910425Smrg		uError("Can't open config file \"%s\n",cfgFileName);
48676910425Smrg		uAction("Exiting\n");
48776910425Smrg		exit(1);
48876910425Smrg	    }
48976910425Smrg	    sprintf(buf,DFLT_SYS_XKBEVD_CONFIG,DFLT_XKB_CONFIG_ROOT);
49076910425Smrg	    file= fopen(cfgFileName,"r");
491db17cd6dSmrg	    if (file==NULL && !eventMask) {
49276910425Smrg		if (verbose) {
49376910425Smrg		    uError("Couldn't find a config file anywhere\n");
49476910425Smrg		    uAction("Exiting\n");
49576910425Smrg		    exit(1);
49676910425Smrg		}
49776910425Smrg		exit(0);
49876910425Smrg	    }
49976910425Smrg	}
50076910425Smrg    }
50176910425Smrg
50276910425Smrg    if (background) {
50376910425Smrg	if (fork()!=0) {
50476910425Smrg	    if (verbose)
50576910425Smrg		uInformation("Running in the background\n");
50676910425Smrg	    exit(0);
50776910425Smrg	}
50876910425Smrg    }
50976910425Smrg    dpy= GetDisplay(argv[0],dpyName,&xkbOpcode,&xkbEventCode);
51076910425Smrg    if (!dpy)
51176910425Smrg	goto BAILOUT;
51276910425Smrg    ok= True;
51376910425Smrg    setScanState(cfgFileName,1);
51476910425Smrg    CFGParseFile(file);
515db17cd6dSmrg    if (!config && !eventMask) {
51676910425Smrg	uError("No configuration specified in \"%s\"\n",cfgFileName);
51776910425Smrg	goto BAILOUT;
51876910425Smrg    }
51976910425Smrg    if (eventMask==0) {
52076910425Smrg	uError("No events to watch in \"%s\"\n",cfgFileName);
52176910425Smrg	goto BAILOUT;
52276910425Smrg    }
52376910425Smrg    if (!XkbSelectEvents(dpy,XkbUseCoreKbd,eventMask,eventMask)) {
52476910425Smrg	uError("Couldn't select desired XKB events\n");
52576910425Smrg	goto BAILOUT;
52676910425Smrg    }
52776910425Smrg    xkb= XkbGetKeyboard(dpy,XkbGBN_AllComponentsMask,XkbUseCoreKbd);
52876910425Smrg    if (eventMask&XkbBellNotifyMask) {
52976910425Smrg	unsigned ctrls,vals;
53076910425Smrg	if (verbose)
53176910425Smrg	   uInformation("Temporarily disabling the audible bell\n");
53276910425Smrg	if (!XkbChangeEnabledControls(dpy,XkbUseCoreKbd,XkbAudibleBellMask,0)) {
53376910425Smrg	    uError("Couldn't disable audible bell\n");
53476910425Smrg	    goto BAILOUT;
53576910425Smrg	}
53676910425Smrg	ctrls= vals= XkbAudibleBellMask;
53776910425Smrg	if (!XkbSetAutoResetControls(dpy,XkbAudibleBellMask,&ctrls,&vals)) {
53876910425Smrg	    uWarning("Couldn't configure audible bell to reset on exit\n");
53976910425Smrg	    uAction("Audible bell might remain off\n");
54076910425Smrg	}
54176910425Smrg    }
54276910425Smrg    if (soundCmd==NULL)	soundCmd= DFLT_SOUND_CMD;
54376910425Smrg    if (soundDir==NULL)	soundDir= DFLT_SOUND_DIR;
54476910425Smrg    XkbStdBellEvent(dpy,None,0,XkbBI_ImAlive);
54576910425Smrg    while (1) {
54676910425Smrg	XNextEvent(dpy,&ev.core);
54776910425Smrg	if ((!ProcessMatchingConfig(&ev))&&(ev.type==xkbEventCode)&&
54876910425Smrg					(ev.any.xkb_type==XkbBellNotify)) {
54976910425Smrg	    XkbForceDeviceBell(dpy,ev.bell.device,
55076910425Smrg				ev.bell.bell_class,ev.bell.bell_id,
55176910425Smrg				ev.bell.percent);
55276910425Smrg	}
55376910425Smrg    }
55476910425Smrg
55576910425Smrg    XCloseDisplay(dpy);
55676910425Smrg    return (ok==0);
55776910425SmrgBAILOUT:
55876910425Smrg    uAction("Exiting\n");
55976910425Smrg    if (dpy!=NULL)
56076910425Smrg	XCloseDisplay(dpy);
56176910425Smrg    exit(1);
56276910425Smrg}
563