xkbevd.c revision a67f45c3
176910425Smrg/************************************************************
276910425Smrg Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
376910425Smrg
476910425Smrg Permission to use, copy, modify, and distribute this
576910425Smrg software and its documentation for any purpose and without
676910425Smrg fee is hereby granted, provided that the above copyright
776910425Smrg notice appear in all copies and that both that copyright
876910425Smrg notice and this permission notice appear in supporting
99ff100acSmrg documentation, and that the name of Silicon Graphics not be
109ff100acSmrg used in advertising or publicity pertaining to distribution
1176910425Smrg of the software without specific prior written permission.
129ff100acSmrg Silicon Graphics makes no representation about the suitability
1376910425Smrg of this software for any purpose. It is provided "as is"
1476910425Smrg without any express or implied warranty.
159ff100acSmrg
169ff100acSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
179ff100acSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1876910425Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
199ff100acSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
209ff100acSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
219ff100acSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2276910425Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
2376910425Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
2476910425Smrg
2576910425Smrg ********************************************************/
2676910425Smrg
2776910425Smrg#include <X11/Xosdefs.h>
2876910425Smrg#include <stdlib.h>
2976910425Smrg#include "xkbevd.h"
3076910425Smrg
3176910425Smrg/***====================================================================***/
3276910425Smrg
3376910425Smrg#ifndef DFLT_XKBEVD_CONFIG
3476910425Smrg#define DFLT_XKBEVD_CONFIG "%s/.xkb/xkbevd.cf"
3576910425Smrg#endif /* DFLT_XKBEVD_CONFIG */
3676910425Smrg
3776910425Smrg#ifndef DFLT_XKB_CONFIG_ROOT
38a67f45c3Smrg#define	DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb"
3976910425Smrg#endif
4076910425Smrg
4176910425Smrg#ifndef DFLT_SYS_XKBEVD_CONFIG
4276910425Smrg#define DFLT_SYS_XKBEVD_CONFIG "%s/xkbevd.cf"
4376910425Smrg#endif /* DFLT_SYS_XKBEVD_CONFIG */
4476910425Smrg
4576910425Smrg#ifndef DFLT_SOUND_CMD
4676910425Smrg#define	DFLT_SOUND_CMD "/usr/sbin/sfplay -q"
4776910425Smrg#endif /* DFLT_SOUND_CMD */
4876910425Smrg
4976910425Smrg#ifndef DFLT_SOUND_DIR
5076910425Smrg#define	DFLT_SOUND_DIR "/usr/share/data/sounds/prosonus/"
5176910425Smrg#endif /* DFLT_SOUND_DIR */
5276910425Smrg
5376910425Smrg/***====================================================================***/
5476910425Smrg
559ff100acSmrgstatic char *   dpyName = NULL;
569ff100acSmrgDisplay *       dpy = NULL;
579ff100acSmrgstatic const char *cfgFileName = NULL;
589ff100acSmrgint             xkbOpcode = 0;
599ff100acSmrgint             xkbEventCode = 0;
609ff100acSmrgBool            detectableRepeat = False;
6176910425Smrg
629ff100acSmrgstatic CfgEntryPtr config = NULL;
639ff100acSmrgstatic unsigned long eventMask = 0;
6476910425Smrg
659ff100acSmrgstatic Bool     synch = False;
669ff100acSmrgstatic int      verbose = 0;
679ff100acSmrgstatic Bool     background = False;
6876910425Smrg
699ff100acSmrgstatic const char *soundCmd = NULL;
709ff100acSmrgstatic const char *soundDir = NULL;
7176910425Smrg
729ff100acSmrgXkbDescPtr      xkb = NULL;
7376910425Smrg
7476910425Smrg/***====================================================================***/
7576910425Smrg
7676910425Smrgstatic void
7776910425SmrgUsage(int argc, char *argv[])
7876910425Smrg{
799ff100acSmrg    fprintf(stderr, "Usage: %s [options]...\n%s", argv[0],
809ff100acSmrg            "Legal options:\n"
819ff100acSmrg            "-?, -help            Print this message\n"
829ff100acSmrg            "-cfg <file>          Specify a config file\n"
839ff100acSmrg            "-sc <cmd>            Specify the command to play sounds\n"
849ff100acSmrg            "-sd <dir>            Specify the root directory for sound files\n"
859ff100acSmrg            "-d[isplay] <dpy>     Specify the display to watch\n"
869ff100acSmrg            "-bg                  Run in background\n"
879ff100acSmrg            "-synch               Force synchronization\n"
889ff100acSmrg            "-v                   Print verbose messages\n"
899ff100acSmrg            "-version             Print program version\n"
909ff100acSmrg        );
9176910425Smrg    return;
9276910425Smrg}
9376910425Smrg
9476910425Smrg/***====================================================================***/
9576910425Smrg
9676910425Smrgstatic Bool
9776910425SmrgparseArgs(int argc, char *argv[])
9876910425Smrg{
999ff100acSmrg    register int i;
1009ff100acSmrg
1019ff100acSmrg    for (i = 1; i < argc; i++) {
1029ff100acSmrg        if (strcmp(argv[i], "-bg") == 0) {
1039ff100acSmrg            background = True;
1049ff100acSmrg        }
1059ff100acSmrg        else if (strcmp(argv[i], "-cfg") == 0) {
1069ff100acSmrg            if (i >= (argc - 1)) {
1079ff100acSmrg                uError("No configuration file specified on command line\n");
1089ff100acSmrg                uAction("Trailing %s argument ignored\n", argv[i]);
1099ff100acSmrg            }
1109ff100acSmrg            else {
1119ff100acSmrg                char *name = argv[++i];
1129ff100acSmrg
1139ff100acSmrg                if (cfgFileName != NULL) {
1149ff100acSmrg                    if (uStringEqual(cfgFileName, name))
1159ff100acSmrg                        uWarning("Config file \"%s\" specified twice!\n", name);
1169ff100acSmrg                    else {
1179ff100acSmrg                        uWarning("Multiple config files on command line\n");
1189ff100acSmrg                        uAction("Using \"%s\", ignoring \"%s\"\n", name,
1199ff100acSmrg                                cfgFileName);
1209ff100acSmrg                    }
1219ff100acSmrg                }
1229ff100acSmrg                cfgFileName = name;
1239ff100acSmrg            }
1249ff100acSmrg        }
1259ff100acSmrg        else if ((strcmp(argv[i], "-d") == 0) ||
1269ff100acSmrg                 (strcmp(argv[i], "-display") == 0)) {
1279ff100acSmrg            if (i >= (argc - 1)) {
1289ff100acSmrg                uError("No display specified on command line\n");
1299ff100acSmrg                uAction("Trailing %s argument ignored\n", argv[i]);
1309ff100acSmrg            }
1319ff100acSmrg            else {
1329ff100acSmrg                char *name = argv[++i];
1339ff100acSmrg
1349ff100acSmrg                if (dpyName != NULL) {
1359ff100acSmrg                    if (uStringEqual(dpyName, name))
1369ff100acSmrg                        uWarning("Display \"%s\" specified twice!\n", name);
1379ff100acSmrg                    else {
1389ff100acSmrg                        uWarning("Multiple displays on command line\n");
1399ff100acSmrg                        uAction("Using \"%s\", ignoring \"%s\"\n", name,
1409ff100acSmrg                                dpyName);
1419ff100acSmrg                    }
1429ff100acSmrg                }
1439ff100acSmrg                dpyName = name;
1449ff100acSmrg            }
1459ff100acSmrg        }
1469ff100acSmrg        else if (strcmp(argv[i], "-sc") == 0) {
1479ff100acSmrg            if (i >= (argc - 1)) {
1489ff100acSmrg                uError("No sound command specified on command line\n");
1499ff100acSmrg                uAction("Trailing %s argument ignored\n", argv[i]);
1509ff100acSmrg            }
1519ff100acSmrg            else {
1529ff100acSmrg                char *name = argv[++i];
1539ff100acSmrg
1549ff100acSmrg                if (soundCmd != NULL) {
1559ff100acSmrg                    if (uStringEqual(soundCmd, name))
1569ff100acSmrg                        uWarning("Sound command \"%s\" specified twice!\n",
1579ff100acSmrg                                 name);
1589ff100acSmrg                    else {
1599ff100acSmrg                        uWarning("Multiple sound commands on command line\n");
1609ff100acSmrg                        uAction("Using \"%s\", ignoring \"%s\"\n", name,
1619ff100acSmrg                                soundCmd);
1629ff100acSmrg                    }
1639ff100acSmrg                }
1649ff100acSmrg                soundCmd = name;
1659ff100acSmrg            }
1669ff100acSmrg        }
1679ff100acSmrg        else if (strcmp(argv[i], "-sd") == 0) {
1689ff100acSmrg            if (i >= (argc - 1)) {
1699ff100acSmrg                uError("No sound directory specified on command line\n");
1709ff100acSmrg                uAction("Trailing %s argument ignored\n", argv[i]);
1719ff100acSmrg            }
1729ff100acSmrg            else {
1739ff100acSmrg                char *name = argv[++i];
1749ff100acSmrg
1759ff100acSmrg                if (soundDir != NULL) {
1769ff100acSmrg                    if (uStringEqual(soundDir, name))
1779ff100acSmrg                        uWarning("Sound directory \"%s\" specified twice!\n",
1789ff100acSmrg                                 name);
1799ff100acSmrg                    else {
1809ff100acSmrg                        uWarning("Multiple sound dirs on command line\n");
1819ff100acSmrg                        uAction("Using \"%s\", ignoring \"%s\"\n", name,
1829ff100acSmrg                                soundDir);
1839ff100acSmrg                    }
1849ff100acSmrg                }
1859ff100acSmrg                soundDir = name;
1869ff100acSmrg            }
1879ff100acSmrg        }
1889ff100acSmrg        else if ((strcmp(argv[i], "-synch") == 0) ||
1899ff100acSmrg                 (strcmp(argv[i], "-s") == 0)) {
1909ff100acSmrg            synch = True;
1919ff100acSmrg        }
1929ff100acSmrg        else if (strcmp(argv[i], "-v") == 0) {
1939ff100acSmrg            verbose++;
1949ff100acSmrg        }
1959ff100acSmrg        else if (strcmp(argv[i], "-version") == 0) {
1969ff100acSmrg            puts(PACKAGE_STRING);
1979ff100acSmrg            exit(0);
1989ff100acSmrg        }
1999ff100acSmrg        else if ((strcmp(argv[i], "-?") == 0) ||
2009ff100acSmrg                 (strcmp(argv[i], "-help") == 0)) {
2019ff100acSmrg            Usage(argc, argv);
2029ff100acSmrg            exit(0);
2039ff100acSmrg        }
2049ff100acSmrg        else {
2059ff100acSmrg            uError("Unknown flag \"%s\" on command line\n", argv[i]);
2069ff100acSmrg            Usage(argc, argv);
2079ff100acSmrg            return False;
2089ff100acSmrg        }
20976910425Smrg    }
210db17cd6dSmrg    if (background == False) {
2119ff100acSmrg        eventMask = XkbAllEventsMask;
2129ff100acSmrg        verbose++;
213db17cd6dSmrg    }
214db17cd6dSmrg
21576910425Smrg    return True;
21676910425Smrg}
21776910425Smrg
21876910425Smrgstatic Display *
219a67f45c3SmrgGetDisplay(const char *program, const char *displayName,
220a67f45c3Smrg           int *opcodeRtrn, int *evBaseRtrn)
22176910425Smrg{
2229ff100acSmrg    int mjr, mnr, error;
223a67f45c3Smrg    Display *display;
2249ff100acSmrg
2259ff100acSmrg    mjr = XkbMajorVersion;
2269ff100acSmrg    mnr = XkbMinorVersion;
227a67f45c3Smrg    display = XkbOpenDisplay(displayName, evBaseRtrn, NULL, &mjr, &mnr, &error);
228a67f45c3Smrg    if (display == NULL) {
2299ff100acSmrg        switch (error) {
2309ff100acSmrg        case XkbOD_BadLibraryVersion:
2319ff100acSmrg            uInformation("%s was compiled with XKB version %d.%02d\n",
2329ff100acSmrg                         program, XkbMajorVersion, XkbMinorVersion);
2339ff100acSmrg            uError("X library supports incompatible version %d.%02d\n",
2349ff100acSmrg                   mjr, mnr);
2359ff100acSmrg            break;
2369ff100acSmrg        case XkbOD_ConnectionRefused:
237a67f45c3Smrg            uError("Cannot open display \"%s\"\n", displayName);
2389ff100acSmrg            break;
2399ff100acSmrg        case XkbOD_NonXkbServer:
240a67f45c3Smrg            uError("XKB extension not present on %s\n", displayName);
2419ff100acSmrg            break;
2429ff100acSmrg        case XkbOD_BadServerVersion:
2439ff100acSmrg            uInformation("%s was compiled with XKB version %d.%02d\n",
2449ff100acSmrg                         program, XkbMajorVersion, XkbMinorVersion);
2459ff100acSmrg            uError("Server %s uses incompatible version %d.%02d\n",
246a67f45c3Smrg                   displayName, mjr, mnr);
2479ff100acSmrg            break;
2489ff100acSmrg        default:
2499ff100acSmrg            uInternalError("Unknown error %d from XkbOpenDisplay\n", error);
2509ff100acSmrg        }
25176910425Smrg    }
25276910425Smrg    else if (synch)
253a67f45c3Smrg        XSynchronize(display, True);
25476910425Smrg    if (opcodeRtrn)
255a67f45c3Smrg        XkbQueryExtension(display, opcodeRtrn, evBaseRtrn, NULL, &mjr, &mnr);
256a67f45c3Smrg    return display;
25776910425Smrg}
25876910425Smrg
25976910425Smrg/***====================================================================***/
26076910425Smrg
26176910425Smrgvoid
26276910425SmrgInterpretConfigs(CfgEntryPtr cfg)
26376910425Smrg{
2649ff100acSmrg    config = cfg;
2659ff100acSmrg    while (cfg != NULL) {
266a67f45c3Smrg        char *name = cfg->name.str;
2679ff100acSmrg        if (cfg->entry_type == VariableDef) {
2689ff100acSmrg            if (uStrCaseEqual(name, "sounddirectory") ||
2699ff100acSmrg                uStrCaseEqual(name, "sounddir")) {
2709ff100acSmrg                if (soundDir == NULL) {
2719ff100acSmrg                    soundDir = cfg->action.text;
2729ff100acSmrg                    cfg->name.str = NULL;
2739ff100acSmrg                    cfg->action.text = NULL;
2749ff100acSmrg                }
2759ff100acSmrg            }
2769ff100acSmrg            else if (uStrCaseEqual(name, "soundcommand") ||
2779ff100acSmrg                     uStrCaseEqual(name, "soundcmd")) {
2789ff100acSmrg                if (soundCmd == NULL) {
2799ff100acSmrg                    soundCmd = cfg->action.text;
2809ff100acSmrg                    cfg->name.str = NULL;
2819ff100acSmrg                    cfg->action.text = NULL;
2829ff100acSmrg                }
2839ff100acSmrg            }
2849ff100acSmrg            else {
2859ff100acSmrg                uWarning("Assignment to unknown variable \"%s\"\n", name);
2869ff100acSmrg                uAction("Ignored\n");
2879ff100acSmrg            }
2889ff100acSmrg        }
289a67f45c3Smrg        else if (cfg->entry_type == EventDef) {
290a67f45c3Smrg            unsigned int priv;
291a67f45c3Smrg
2929ff100acSmrg            switch (cfg->event_type) {
2939ff100acSmrg            case XkbBellNotify:
2949ff100acSmrg                if (name != NULL)
2959ff100acSmrg                    cfg->name.atom = XInternAtom(dpy, name, False);
2969ff100acSmrg                else
2979ff100acSmrg                    cfg->name.atom = None;
2989ff100acSmrg                if (name)
2999ff100acSmrg                    free(name);
3009ff100acSmrg                break;
3019ff100acSmrg            case XkbAccessXNotify:
3029ff100acSmrg                priv = 0;
3039ff100acSmrg                if (name == NULL)
3049ff100acSmrg                    priv = XkbAllNewKeyboardEventsMask;
3059ff100acSmrg                else if (uStrCaseEqual(name, "skpress"))
3069ff100acSmrg                    priv = XkbAXN_SKPressMask;
3079ff100acSmrg                else if (uStrCaseEqual(name, "skaccept"))
3089ff100acSmrg                    priv = XkbAXN_SKAcceptMask;
3099ff100acSmrg                else if (uStrCaseEqual(name, "skreject"))
3109ff100acSmrg                    priv = XkbAXN_SKRejectMask;
3119ff100acSmrg                else if (uStrCaseEqual(name, "skrelease"))
3129ff100acSmrg                    priv = XkbAXN_SKReleaseMask;
3139ff100acSmrg                else if (uStrCaseEqual(name, "bkaccept"))
3149ff100acSmrg                    priv = XkbAXN_BKAcceptMask;
3159ff100acSmrg                else if (uStrCaseEqual(name, "bkreject"))
3169ff100acSmrg                    priv = XkbAXN_BKRejectMask;
3179ff100acSmrg                else if (uStrCaseEqual(name, "warning"))
3189ff100acSmrg                    priv = XkbAXN_AXKWarningMask;
3199ff100acSmrg                if (name)
3209ff100acSmrg                    free(name);
3219ff100acSmrg                cfg->name.priv = priv;
3229ff100acSmrg                break;
3239ff100acSmrg            case XkbActionMessage:
3249ff100acSmrg                /* nothing to do */
3259ff100acSmrg                break;
3269ff100acSmrg            }
327a67f45c3Smrg        }
3289ff100acSmrg        eventMask |= (1L << cfg->event_type);
3299ff100acSmrg        cfg = cfg->next;
33076910425Smrg    }
3319ff100acSmrg    while ((config) && (config->entry_type != EventDef)) {
3329ff100acSmrg        CfgEntryPtr next;
3339ff100acSmrg
3349ff100acSmrg        if (config->name.str)
3359ff100acSmrg            free(config->name.str);
3369ff100acSmrg        if (config->action.text)
3379ff100acSmrg            free(config->action.text);
3389ff100acSmrg        config->name.str = NULL;
3399ff100acSmrg        config->action.text = NULL;
3409ff100acSmrg        next = config->next;
3419ff100acSmrg        free(config);
3429ff100acSmrg        config = next;
34376910425Smrg    }
3449ff100acSmrg    cfg = config;
3459ff100acSmrg    while ((cfg != NULL) && (cfg->next != NULL)) {
3469ff100acSmrg        CfgEntryPtr next;
3479ff100acSmrg
3489ff100acSmrg        next = cfg->next;
3499ff100acSmrg        if (next->entry_type != EventDef) {
3509ff100acSmrg            if (next->name.str)
3519ff100acSmrg                free(config->name.str);
3529ff100acSmrg            if (next->action.text)
3539ff100acSmrg                free(config->action.text);
3549ff100acSmrg            next->name.str = NULL;
3559ff100acSmrg            next->action.text = NULL;
3569ff100acSmrg            cfg->next = next->next;
3579ff100acSmrg            next->next = NULL;
3589ff100acSmrg            free(next);
3599ff100acSmrg        }
3609ff100acSmrg        else
3619ff100acSmrg            cfg = next;
36276910425Smrg    }
36376910425Smrg    return;
36476910425Smrg}
36576910425Smrg
36676910425Smrgstatic CfgEntryPtr
3679ff100acSmrgFindMatchingConfig(XkbEvent * ev)
36876910425Smrg{
3699ff100acSmrg    CfgEntryPtr cfg, dflt;
3709ff100acSmrg
3719ff100acSmrg    dflt = NULL;
3729ff100acSmrg    for (cfg = config; (cfg != NULL); cfg = cfg->next) {
3739ff100acSmrg        if ((ev->type != xkbEventCode) || (cfg->event_type != ev->any.xkb_type))
3749ff100acSmrg            continue;
3759ff100acSmrg        switch (ev->any.xkb_type) {
3769ff100acSmrg        case XkbBellNotify:
3779ff100acSmrg            if (ev->bell.name == cfg->name.atom)
3789ff100acSmrg                return cfg;
3799ff100acSmrg            else if ((cfg->name.atom == None) && (dflt == NULL))
3809ff100acSmrg                dflt = cfg;
3819ff100acSmrg            break;
3829ff100acSmrg        case XkbAccessXNotify:
3839ff100acSmrg            if (cfg->name.priv & (1L << ev->accessx.detail))
3849ff100acSmrg                return cfg;
3859ff100acSmrg            break;
3869ff100acSmrg        case XkbActionMessage:
3879ff100acSmrg            if (cfg->name.str == NULL)
3889ff100acSmrg                dflt = cfg;
3899ff100acSmrg            else if (strncmp(cfg->name.str, ev->message.message,
3909ff100acSmrg                             XkbActionMessageLength) == 0)
3919ff100acSmrg                return cfg;
3929ff100acSmrg            break;
3939ff100acSmrg        default:
3949ff100acSmrg            uInternalError("Can't handle type %d XKB events yet, Sorry.\n",
3959ff100acSmrg                           ev->any.xkb_type);
3969ff100acSmrg            break;
3979ff100acSmrg        }
39876910425Smrg    }
39976910425Smrg    return dflt;
40076910425Smrg}
40176910425Smrg
40276910425Smrgstatic Bool
4039ff100acSmrgProcessMatchingConfig(XkbEvent * ev)
40476910425Smrg{
4059ff100acSmrg    CfgEntryPtr cfg;
4069ff100acSmrg    char buf[1024], *cmd;
4079ff100acSmrg    int ok;
40876910425Smrg
4099ff100acSmrg    cfg = FindMatchingConfig(ev);
410db17cd6dSmrg    if (!cfg) {
4119ff100acSmrg        if (verbose)
4129ff100acSmrg            PrintXkbEvent(stdout, ev);
4139ff100acSmrg        return False;
414db17cd6dSmrg    }
4159ff100acSmrg    if (cfg->action.type == UnknownAction) {
4169ff100acSmrg        if (cfg->action.text == NULL)
4179ff100acSmrg            cfg->action.type = NoAction;
4189ff100acSmrg        else if (cfg->action.text[0] == '!') {
4199ff100acSmrg            char *tmp;
4209ff100acSmrg
4219ff100acSmrg            cfg->action.type = ShellAction;
4229ff100acSmrg            tmp = uStringDup(&cfg->action.text[1]);
4239ff100acSmrg            free(cfg->action.text);
4249ff100acSmrg            cfg->action.text = tmp;
4259ff100acSmrg        }
4269ff100acSmrg        else
4279ff100acSmrg            cfg->action.type = SoundAction;
42876910425Smrg    }
42976910425Smrg    switch (cfg->action.type) {
4309ff100acSmrg    case NoAction:
4319ff100acSmrg        return True;
4329ff100acSmrg    case EchoAction:
4339ff100acSmrg        if (cfg->action.text != NULL) {
4349ff100acSmrg            snprintf(buf, sizeof(buf), "%s", cfg->action.text);
4359ff100acSmrg            cmd = SubstituteEventArgs(buf, ev);
4369ff100acSmrg            printf("%s", cmd);
4379ff100acSmrg        }
4389ff100acSmrg        return True;
4399ff100acSmrg    case PrintEvAction:
4409ff100acSmrg        PrintXkbEvent(stdout, ev);
4419ff100acSmrg        return True;
4429ff100acSmrg    case ShellAction:
4439ff100acSmrg        if (cfg->action.text == NULL) {
4449ff100acSmrg            uWarning("Empty shell command!\n");
4459ff100acSmrg            uAction("Ignored\n");
4469ff100acSmrg            return True;
4479ff100acSmrg        }
4489ff100acSmrg        cmd = cfg->action.text;
4499ff100acSmrg        break;
4509ff100acSmrg    case SoundAction:
4519ff100acSmrg        if (cfg->action.text == NULL) {
4529ff100acSmrg            uWarning("Empty sound command!\n");
4539ff100acSmrg            uAction("Ignored\n");
4549ff100acSmrg            return True;
4559ff100acSmrg        }
4569ff100acSmrg        snprintf(buf, sizeof(buf), "%s %s%s", soundCmd, soundDir,
4579ff100acSmrg                 cfg->action.text);
4589ff100acSmrg        cmd = buf;
4599ff100acSmrg        break;
4609ff100acSmrg    default:
4619ff100acSmrg        uInternalError("Unknown error action type %d\n", cfg->action.type);
4629ff100acSmrg        return False;
46376910425Smrg    }
4649ff100acSmrg    cmd = SubstituteEventArgs(cmd, ev);
46576910425Smrg    if (verbose)
4669ff100acSmrg        uInformation("Executing shell command \"%s\"\n", cmd);
4679ff100acSmrg    ok = (system(cmd) == 0);
46876910425Smrg    return ok;
46976910425Smrg}
47076910425Smrg
47176910425Smrg/***====================================================================***/
47276910425Smrg
47376910425Smrgint
47476910425Smrgmain(int argc, char *argv[])
47576910425Smrg{
4769ff100acSmrg    FILE *      file;
4779ff100acSmrg    static char buf[1024];
4789ff100acSmrg    XkbEvent    ev;
4799ff100acSmrg    Bool        ok;
48076910425Smrg
48176910425Smrg    yyin = stdin;
48276910425Smrg    uSetErrorFile(NullString);
48376910425Smrg
4849ff100acSmrg    if (!parseArgs(argc, argv))
4859ff100acSmrg        exit(1);
4869ff100acSmrg    file = NULL;
48776910425Smrg    XkbInitAtoms(NULL);
4889ff100acSmrg    if (cfgFileName == NULL) {
4899ff100acSmrg        char *home = getenv("HOME");
4909ff100acSmrg        snprintf(buf, sizeof(buf), DFLT_XKBEVD_CONFIG, (home ? home : ""));
4919ff100acSmrg        cfgFileName = buf;
49276910425Smrg    }
4939ff100acSmrg    if (uStringEqual(cfgFileName, "-")) {
4949ff100acSmrg        static const char *in = "stdin";
4959ff100acSmrg
4969ff100acSmrg        file = stdin;
4979ff100acSmrg        cfgFileName = in;
49876910425Smrg    }
49976910425Smrg    else {
5009ff100acSmrg        file = fopen(cfgFileName, "r");
5019ff100acSmrg        if (file == NULL) {     /* no personal config, try for a system one */
5029ff100acSmrg            if (cfgFileName != buf) {   /* user specified a file.  bail */
5039ff100acSmrg                uError("Can't open config file \"%s\n", cfgFileName);
5049ff100acSmrg                uAction("Exiting\n");
5059ff100acSmrg                exit(1);
5069ff100acSmrg            }
5079ff100acSmrg            snprintf(buf, sizeof(buf), DFLT_SYS_XKBEVD_CONFIG,
5089ff100acSmrg                     DFLT_XKB_CONFIG_ROOT);
5099ff100acSmrg            file = fopen(cfgFileName, "r");
5109ff100acSmrg            if (file == NULL && !eventMask) {
5119ff100acSmrg                if (verbose) {
5129ff100acSmrg                    uError("Couldn't find a config file anywhere\n");
5139ff100acSmrg                    uAction("Exiting\n");
5149ff100acSmrg                    exit(1);
5159ff100acSmrg                }
5169ff100acSmrg                exit(0);
5179ff100acSmrg            }
5189ff100acSmrg        }
51976910425Smrg    }
52076910425Smrg
52176910425Smrg    if (background) {
5229ff100acSmrg        if (fork() != 0) {
5239ff100acSmrg            if (verbose)
5249ff100acSmrg                uInformation("Running in the background\n");
5259ff100acSmrg            exit(0);
5269ff100acSmrg        }
52776910425Smrg    }
5289ff100acSmrg    dpy = GetDisplay(argv[0], dpyName, &xkbOpcode, &xkbEventCode);
52976910425Smrg    if (!dpy)
5309ff100acSmrg        goto BAILOUT;
5319ff100acSmrg    ok = True;
5329ff100acSmrg    setScanState(cfgFileName, 1);
53376910425Smrg    CFGParseFile(file);
534db17cd6dSmrg    if (!config && !eventMask) {
5359ff100acSmrg        uError("No configuration specified in \"%s\"\n", cfgFileName);
5369ff100acSmrg        goto BAILOUT;
53776910425Smrg    }
5389ff100acSmrg    if (eventMask == 0) {
5399ff100acSmrg        uError("No events to watch in \"%s\"\n", cfgFileName);
5409ff100acSmrg        goto BAILOUT;
54176910425Smrg    }
5429ff100acSmrg    if (!XkbSelectEvents(dpy, XkbUseCoreKbd, eventMask, eventMask)) {
5439ff100acSmrg        uError("Couldn't select desired XKB events\n");
5449ff100acSmrg        goto BAILOUT;
54576910425Smrg    }
5469ff100acSmrg    xkb = XkbGetKeyboard(dpy, XkbGBN_AllComponentsMask, XkbUseCoreKbd);
5479ff100acSmrg    if (eventMask & XkbBellNotifyMask) {
5489ff100acSmrg        unsigned ctrls, vals;
5499ff100acSmrg
5509ff100acSmrg        if (verbose)
5519ff100acSmrg            uInformation("Temporarily disabling the audible bell\n");
5529ff100acSmrg        if (!XkbChangeEnabledControls
5539ff100acSmrg            (dpy, XkbUseCoreKbd, XkbAudibleBellMask, 0)) {
5549ff100acSmrg            uError("Couldn't disable audible bell\n");
5559ff100acSmrg            goto BAILOUT;
5569ff100acSmrg        }
5579ff100acSmrg        ctrls = vals = XkbAudibleBellMask;
5589ff100acSmrg        if (!XkbSetAutoResetControls(dpy, XkbAudibleBellMask, &ctrls, &vals)) {
5599ff100acSmrg            uWarning("Couldn't configure audible bell to reset on exit\n");
5609ff100acSmrg            uAction("Audible bell might remain off\n");
5619ff100acSmrg        }
56276910425Smrg    }
5639ff100acSmrg    if (soundCmd == NULL)
5649ff100acSmrg        soundCmd = DFLT_SOUND_CMD;
5659ff100acSmrg    if (soundDir == NULL)
5669ff100acSmrg        soundDir = DFLT_SOUND_DIR;
5679ff100acSmrg    XkbStdBellEvent(dpy, None, 0, XkbBI_ImAlive);
56876910425Smrg    while (1) {
5699ff100acSmrg        XNextEvent(dpy, &ev.core);
5709ff100acSmrg        if ((!ProcessMatchingConfig(&ev)) && (ev.type == xkbEventCode) &&
5719ff100acSmrg            (ev.any.xkb_type == XkbBellNotify)) {
5729ff100acSmrg            XkbForceDeviceBell(dpy, ev.bell.device,
5739ff100acSmrg                               ev.bell.bell_class, ev.bell.bell_id,
5749ff100acSmrg                               ev.bell.percent);
5759ff100acSmrg        }
57676910425Smrg    }
57776910425Smrg
57876910425Smrg    XCloseDisplay(dpy);
5799ff100acSmrg    return (ok == 0);
5809ff100acSmrg BAILOUT:
58176910425Smrg    uAction("Exiting\n");
5829ff100acSmrg    if (dpy != NULL)
5839ff100acSmrg        XCloseDisplay(dpy);
58476910425Smrg    exit(1);
58576910425Smrg}
586