#include #include #include #include #include #include #include Display *theDisplay; XtAppContext appContext; int xkbEventBase; Widget topLevel; Widget leds[XkbNumIndicators]; Atom ledAtoms[XkbNumIndicators]; XmString ledNames[XkbNumIndicators]; XkbDescPtr xkb_desc; void valueChangedProc(Widget,XtPointer,XmToggleButtonCallbackStruct *); XtCallbackRec valueChangedCB[2]={(XtCallbackProc)valueChangedProc,NULL}; /************************************************************************/ /* */ /* Application Resources */ /* */ /************************************************************************/ #define YES 1 #define NO 0 #define DONT_CARE -1 typedef struct { int wanted; int wantAutomatic; int wantExplicit; int wantNamed; int wantReal; int wantVirtual; int useUnion; } OptionsRec; OptionsRec options; #define Offset(field) XtOffsetOf(OptionsRec,field) XtResource resources[] = { {"wanted", "Wanted", XtRInt, sizeof(int), Offset(wanted), XtRImmediate, (XtPointer) DONT_CARE }, {"wantAutomatic", "WantAutomatic", XtRInt, sizeof(int), Offset(wantAutomatic), XtRImmediate, (XtPointer) DONT_CARE}, {"wantExplicit", "WantExplicit", XtRInt, sizeof(int), Offset(wantExplicit), XtRImmediate, (XtPointer) DONT_CARE}, {"wantNamed", "WantNamed", XtRInt, sizeof(int), Offset(wantNamed), XtRImmediate, (XtPointer) DONT_CARE}, {"wantReal", "WantReal", XtRInt, sizeof(int), Offset(wantReal), XtRImmediate, (XtPointer) DONT_CARE}, {"wantVirtual", "WantVirtual", XtRInt, sizeof(int), Offset(wantVirtual), XtRImmediate, (XtPointer) DONT_CARE}, {"useUnion", "UseUnion", XtRInt, sizeof(int), Offset(useUnion), XtRImmediate, (XtPointer) YES}, NULL }; #undef Offset String fallbackResources[] = { "*mainWindow.width: 100", "*mainWindow.height: 50", NULL }; XrmOptionDescRec optionDesc[] = { {"-watch", "*wanted", XrmoptionSepArg, (XtPointer) "0"}, {"-automatic", "*wantAutomatic", XrmoptionNoArg, (XtPointer) "0"}, {"+automatic", "*wantAutomatic", XrmoptionNoArg, (XtPointer) "1"}, {"-explicit", "*wantExplicit", XrmoptionNoArg, (XtPointer) "0"}, {"+explicit", "*wantExplicit", XrmoptionNoArg, (XtPointer) "1"}, {"-named", "*wantNamed", XrmoptionNoArg, (XtPointer) "0"}, {"+named", "*wantNamed", XrmoptionNoArg, (XtPointer) "1"}, {"-real", "*wantReal", XrmoptionNoArg, (XtPointer) "0"}, {"+real", "*wantReal", XrmoptionNoArg, (XtPointer) "1"}, {"-virtual", "*wantVirtual", XrmoptionNoArg, (XtPointer) "0"}, {"+virtual", "*wantVirtual", XrmoptionNoArg, (XtPointer) "1"}, {"-intersection", "*useUnion", XrmoptionNoArg, (XtPointer) "0"}, {"-union", "*useUnion", XrmoptionNoArg, (XtPointer) "1"} }; /************************************************************************/ /* */ /* usage */ /* */ /************************************************************************/ void usage(char *program) { printf("Usage: %s \n",program); printf("Legal options include the usual X toolkit options plus:\n"); printf(" -help Print this message\n"); printf(" -indpy Name of display to watch\n"); printf(" -watch Mask of LEDs to watch\n"); printf(" [-+]automatic (Don't) watch automatic LEDs\n"); printf(" [-+]explicit (Don't) watch explicit LEDs\n"); printf(" [-+]named (Don't) watch named LEDs\n"); printf(" [-+]real (Don't) watch real LEDs\n"); printf(" [-+]virtual (Don't) watch virtual LEDs\n"); printf(" -intersection Watch only LEDs in all desired sets\n"); printf(" -union Watch LEDs in any desired sets\n"); printf("The default set of LEDs is -intersection +named +virtual\n"); return; } /************************************************************************/ /* */ /* XkbEventHandler */ /* */ /* DESCRIPTION: */ /* */ /* Handles events generated by the Xkb server extension. */ /* */ /************************************************************************/ Boolean XkbEventHandler(XEvent *event) { XkbEvent *xkbEv = (XkbEvent *) event; if (xkbEv->any.xkb_type==XkbIndicatorStateNotify) { register int i; register unsigned bit; for (i=0,bit=1;iindicators.state_changed&bit)&&(leds[i])) { if (xkbEv->indicators.state&bit) XmToggleButtonSetState(leds[i],True,False); else XmToggleButtonSetState(leds[i],False,False); } } else if (xkbEv->any.xkb_type==XkbIndicatorMapNotify) { unsigned change= xkbEv->indicators.map_changed; if (XkbGetIndicatorMap(theDisplay,change,xkb_desc)!=Success) fprintf(stderr,"Couldn't get changed indicator maps\n"); } return True; } /* XkbEventHandler */ /************************************************************************/ /* */ /* InitXkb */ /* */ /************************************************************************/ Boolean InitXkb(Display *theDisplay) { int i,opcode,errorBase,major,minor; XkbDescPtr xkb; unsigned int bit; unsigned int real,virtual,named,explicit,automatic; char *name; if (!XkbQueryExtension(theDisplay, &opcode, &xkbEventBase, &errorBase, &major, &minor)) return False; if (!XkbUseExtension(theDisplay,&major,&minor)) return False; XkbSelectEvents(theDisplay, XkbUseCoreKbd, XkbIndicatorStateNotifyMask|XkbIndicatorMapNotifyMask, XkbIndicatorStateNotifyMask|XkbIndicatorMapNotifyMask); XtSetEventDispatcher(theDisplay, xkbEventBase+XkbEventCode, XkbEventHandler); xkb=XkbGetMap(theDisplay,0,XkbUseCoreKbd); real=virtual=named=explicit=automatic=0; if (!xkb) { fprintf(stderr,"Couldn't get keymap\n"); return False; } if (XkbGetIndicatorMap(theDisplay,XkbAllIndicatorsMask,xkb)!=Success) { fprintf(stderr,"Couldn't read indicator map\n"); XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return False; } real=virtual=named=explicit=automatic=0; if (XkbGetNames(theDisplay,XkbIndicatorNamesMask,xkb)!=Success) { fprintf(stderr,"Couldn't read indicator names\n"); XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return False; } real=virtual=named=explicit=automatic=0; for (i=0,bit=1;iindicators->maps[i]; name = NULL; if (xkb->names->indicators[i]!=None) { named|= bit; name = XGetAtomName(theDisplay,xkb->names->indicators[i]); } if (name != NULL) { ledAtoms[i] = xkb->names->indicators[i]; ledNames[i] = XmStringCreate(name,XmSTRING_DEFAULT_CHARSET); } else { char temp[12]; sprintf(temp,"led%d\0",i+1); ledAtoms[i] = None; ledNames[i] = XmStringCreate(temp,XmSTRING_DEFAULT_CHARSET); } if (xkb->indicators->phys_indicators&bit) real|= bit; if ((((map->which_groups!=0)&&(map->groups!=0))|| ((map->which_mods!=0)&& ((map->mods.real_mods!=0)||(map->mods.vmods!=0)))|| (map->ctrls!=0))&& ((map->flags&XkbIM_NoAutomatic)==0)) { automatic|= bit; } else explicit|= bit; } virtual = ~real; if (options.useUnion) { if ((options.wantReal==NO) || (options.wantReal==DONT_CARE)) real = 0; if ((options.wantVirtual==NO) || (options.wantVirtual==DONT_CARE)) virtual = 0; if ((options.wantNamed==NO) || (options.wantNamed==DONT_CARE)) named = 0; if ((options.wantAutomatic==NO) || (options.wantAutomatic==DONT_CARE)) automatic = 0; if ((options.wantExplicit==NO) || (options.wantExplicit==DONT_CARE)) explicit = 0; options.wanted |= real|virtual|named|automatic|explicit; } else { if (options.wanted == DONT_CARE) options.wanted = ~0; if (options.wantReal==NO) real = ~real; else if (options.wantReal==DONT_CARE) real = ~0; if (options.wantVirtual==NO) virtual = ~virtual; else if (options.wantVirtual==DONT_CARE) virtual = ~0; if (options.wantNamed==NO) named = ~named; else if (options.wantNamed==DONT_CARE) named = ~0; if (options.wantAutomatic==NO) automatic = ~automatic; else if (options.wantAutomatic==DONT_CARE) automatic = ~0; if (options.wantExplicit==NO) explicit = ~explicit; else if (options.wantExplicit==DONT_CARE) explicit = ~0; options.wanted &= real&virtual&named&automatic&explicit; } XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return True; } /* InitXkb */ /************************************************************************/ /* */ /* valueChangedProc - called when a toggle button is pressed. */ /* */ /************************************************************************/ void valueChangedProc(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *callbackData) { int led = (int) clientData; XkbDescPtr xkb; xkb = XkbGetMap(theDisplay,0,XkbUseCoreKbd); if (!xkb) { fprintf(stderr,"XkbGetMap failed\n"); return; } if (XkbGetIndicatorMap(theDisplay,XkbAllIndicatorsMask,xkb)!=Success) { fprintf(stderr,"GetIndicatorMap failed\n"); XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return; } /* The 'flags' field tells whether this indicator is automatic * (XkbIM_NoExplicit - 0x80), explicit (XkbIM_NoAutomatic - 0x40), * or neither (both - 0xC0). * * If NoAutomatic is set, the server ignores the rest of the * fields in the indicator map (i.e. it disables automatic control * of the LED). If NoExplicit is set, the server prevents clients * from explicitly changing the value of the LED (using the core * protocol *or* XKB). If NoAutomatic *and* NoExplicit are set, * the LED cannot be changed (unless you change the map first). * If neither NoAutomatic nor NoExplicit are set, the server will * change the LED according to the indicator map, but clients can * override that (until the next automatic change) using the core * protocol or XKB. */ switch (xkb->indicators->maps[led].flags & (XkbIM_NoExplicit|XkbIM_NoAutomatic)) { case XkbIM_NoExplicit|XkbIM_NoAutomatic: { XmToggleButtonSetState(w,!callbackData->set,FALSE); XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return; } case XkbIM_NoAutomatic: { if (ledAtoms[led] != None) XkbSetNamedIndicator(theDisplay,XkbUseCoreKbd, ledAtoms[led],&callbackData->set, FALSE,NULL); else { XKeyboardControl xkc; xkc.led= led; if (callbackData->set) xkc.led_mode= LedModeOn; else xkc.led_mode= LedModeOff; XChangeKeyboardControl(theDisplay,KBLed|KBLedMode,&xkc); XSync(theDisplay,0); } XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return; } case XkbIM_NoExplicit: break; } /* The 'ctrls' field tells what controls tell this indicator to * to turn on: RepeatKeys (0x1), SlowKeys (0x2), BounceKeys (0x4), * StickyKeys (0x8), MouseKeys (0x10), AccessXKeys (0x20), * TimeOut (0x40), Feedback (0x80), ToggleKeys (0x100), * Overlay1 (0x200), Overlay2 (0x400), GroupsWrap (0x800), * InternalMods (0x1000), IgnoreLockMods (0x2000), * PerKeyRepeat (0x3000), or ControlsEnabled (0x4000) */ if (xkb->indicators->maps[led].ctrls) { unsigned long which = xkb->indicators->maps[led].ctrls; XkbGetControls(theDisplay,XkbAllControlsMask,xkb); if (callbackData->set) xkb->ctrls->enabled_ctrls |= which; else xkb->ctrls->enabled_ctrls &= ~which; XkbSetControls(theDisplay,which|XkbControlsEnabledMask,xkb); } /* The 'which_groups' field tells when this indicator turns on * for the 'groups' field: base (0x1), latched (0x2), locked (0x4), * or effective (0x8). */ if (xkb->indicators->maps[led].groups) { int i; unsigned int group = 1; /* Turning on a group indicator is kind of tricky. For * now, we will just Latch or Lock the first group we find * if that is what this indicator does. Otherwise, we're * just going to punt and get out of here. */ if (callbackData->set) { for (i = XkbNumKbdGroups-1; i >= 0; i--) if ((1 << i) & xkb->indicators->maps[led].groups) group = i; if (xkb->indicators->maps[led].which_groups & (XkbIM_UseLocked | XkbIM_UseEffective)) XkbLockGroup(theDisplay,XkbUseCoreKbd,group); else if (xkb->indicators->maps[led].which_groups&XkbIM_UseLatched) XkbLatchGroup(theDisplay,XkbUseCoreKbd,group); else { XmToggleButtonSetState(w,!callbackData->set,FALSE); XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return; } } /* Turning off a group indicator will mean that we just * Lock the first group that this indicator doesn't watch. */ else { for (i = XkbNumKbdGroups-1; i >= 0; i--) if (!((1 << i) & xkb->indicators->maps[led].groups)) group = i; XkbLockGroup(theDisplay,XkbUseCoreKbd,group); } } /* The 'which_mods' field tells when this indicator turns on * for the modifiers: base (0x1), latched (0x2), locked (0x4), * or effective (0x8). * * The 'real_mods' field tells whether this turns on when one of * the real X modifiers is set: Shift (0x1), Lock (0x2), Control (0x4), * Mod1 (0x8), Mod2 (0x10), Mod3 (0x20), Mod4 (0x40), or Mod5 (0x80). * * The 'virtual_mods' field tells whether this turns on when one of * the virtual modifiers is set. * * The 'mask' field tells what real X modifiers the virtual_modifiers * map to? */ if (xkb->indicators->maps[led].mods.real_mods || xkb->indicators->maps[led].mods.mask) { XkbStateRec state; unsigned int affect,mods; affect = (xkb->indicators->maps[led].mods.real_mods | xkb->indicators->maps[led].mods.mask); if (callbackData->set) mods = affect; else mods = 0; if (xkb->indicators->maps[led].which_mods & (XkbIM_UseLocked | XkbIM_UseEffective)) XkbLockModifiers(theDisplay,XkbUseCoreKbd,affect,mods); else if (xkb->indicators->maps[led].which_mods & XkbIM_UseLatched) XkbLatchModifiers(theDisplay,XkbUseCoreKbd,affect,mods); else { XmToggleButtonSetState(w,!callbackData->set,FALSE); XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); return; } } XkbFreeKeyboard(xkb,XkbAllComponentsMask,True); } /* valueChangedProc */ /************************************************************************/ /* */ /* InitializeUI */ /* */ /************************************************************************/ void InitializeUI(Widget topLevel) { Arg argList[3]; char buf[256]; int i; unsigned int bit,n; Widget mainWindow,rowColumn; XmString tempString; mainWindow = (Widget) XmCreateMainWindow(topLevel,"mainWindow",NULL,0); XtManageChild(mainWindow); rowColumn = (Widget) XmCreateRowColumn(mainWindow,"rowColumn",NULL,0); XtManageChild(rowColumn); XkbGetIndicatorState(theDisplay,XkbUseCoreKbd,&n); for (i=0,bit=1;i 1) { usage(argv[0]); exit(0); } /* Defaults */ if ((options.wanted == DONT_CARE) && (options.wantReal == DONT_CARE) && (options.wantVirtual == DONT_CARE) && (options.wantNamed == DONT_CARE) && (options.wantAutomatic == DONT_CARE) && (options.wantExplicit == DONT_CARE) && (options.useUnion == YES)) { options.wanted = 0; options.wantReal = YES; options.wantNamed = YES; options.wantAutomatic = YES; } /********************************************************************/ /* */ /* See if the server has XKB. */ /* */ /********************************************************************/ theDisplay = XtDisplay(topLevel); if (!InitXkb(theDisplay)) { fprintf(stderr,"Could not initialize XKB extension.\n"); exit(0); } if (options.wanted == 0) { fprintf(stderr,"No LED's were selected.\n\n"); usage(argv[0]); exit(0); } /********************************************************************/ /* */ /* Set up the UI and go. */ /* */ /********************************************************************/ XtRealizeWidget(topLevel); InitializeUI(topLevel); XtAppMainLoop(appContext); /* NOT REACHED */ exit(0L); }