/* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ #ifdef REV_INFO #ifndef lint static char rcsid[] = "$TOG: VirtKeys.c /main/22 1999/06/02 14:45:52 samborn $" #endif #endif /* (c) Copyright 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ /* (c) Copyright 1990 MOTOROLA, INC. */ #ifndef X_NOT_STDC_ENV #include #endif #include #include #include #include #include #include #include #include #include "MapEventsI.h" #include "VirtKeysI.h" #include "XmosI.h" #include "XmI.h" #define defaultFallbackBindings _XmVirtKeys_fallbackBindingString #define BUFFERSIZE 2048 #define MAXLINE 256 /******** Static Function Declarations ********/ static Boolean CvtStringToVirtualBinding(Display *dpy, XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *closure_ret); static void FillBindingsFromDB(Display *dpy, XrmDatabase rdb, XmVKeyBinding *keys, Cardinal *num_keys); static Boolean GetBindingsProperty(Display *display, String property, String *binding); static void FindVirtKey(Display *dpy, KeyCode keycode, Modifiers modifiers, Modifiers *modifiers_return, KeySym *keysym_return); static Modifiers EffectiveStdModMask(Display *dpy, KeySym *kc_map, int ks_per_kc); static void LoadVendorBindings(Display *display, char *path, FILE *fp, String *binding); /******** End Static Function Declarations ********/ static XmConst XmVirtualKeysymRec virtualKeysyms[] = { { XmVosfActivate, osfXK_Activate }, { XmVosfAddMode, osfXK_AddMode }, { XmVosfBackSpace, osfXK_BackSpace }, { XmVosfBackTab, osfXK_BackTab }, /* Defunct */ { XmVosfBeginData, osfXK_BeginData }, /* Defunct */ { XmVosfBeginLine, osfXK_BeginLine }, { XmVosfCancel, osfXK_Cancel }, { XmVosfClear, osfXK_Clear }, { XmVosfCopy, osfXK_Copy }, { XmVosfCut, osfXK_Cut }, { XmVosfDelete, osfXK_Delete }, { XmVosfDeselectAll, osfXK_DeselectAll }, { XmVosfDown, osfXK_Down }, { XmVosfEndData, osfXK_EndData }, /* Defunct */ { XmVosfEndLine, osfXK_EndLine }, { XmVosfEscape, osfXK_Escape }, /* Defunct */ { XmVosfExtend, osfXK_Extend }, /* Defunct */ { XmVosfHelp, osfXK_Help }, { XmVosfInsert, osfXK_Insert }, { XmVosfLeft, osfXK_Left }, { XmVosfLeftLine, osfXK_LeftLine }, /* X11R6 */ { XmVosfMenu, osfXK_Menu }, { XmVosfMenuBar, osfXK_MenuBar }, { XmVosfNext, osfXK_Next }, /* X11R6 */ { XmVosfNextField, osfXK_NextField }, /* Defunct */ { XmVosfNextMenu, osfXK_NextMenu }, /* Defunct */ { XmVosfNextMinor, osfXK_NextMinor }, /* X11R6 */ { XmVosfPageDown, osfXK_PageDown }, { XmVosfPageLeft, osfXK_PageLeft }, { XmVosfPageRight, osfXK_PageRight }, { XmVosfPageUp, osfXK_PageUp }, { XmVosfPaste, osfXK_Paste }, { XmVosfPrevField, osfXK_PrevField }, /* Defunct */ { XmVosfPrevMenu, osfXK_PrevMenu }, /* Defunct */ { XmVosfPrimaryPaste, osfXK_PrimaryPaste }, { XmVosfPrior, osfXK_Prior }, /* X11R6 */ { XmVosfPriorMinor, osfXK_PriorMinor }, /* X11R6 */ { XmVosfQuickPaste, osfXK_QuickPaste }, { XmVosfReselect, osfXK_Reselect }, { XmVosfRestore, osfXK_Restore }, { XmVosfRight, osfXK_Right }, { XmVosfRightLine, osfXK_RightLine }, /* X11R6 */ { XmVosfSelect, osfXK_Select }, { XmVosfSelectAll, osfXK_SelectAll }, { XmVosfSwitchDirection, osfXK_SwitchDirection }, /* X11R6 */ { XmVosfUndo, osfXK_Undo }, { XmVosfUp, osfXK_Up } }; static XmConst XmDefaultBindingStringRec fallbackBindingStrings[] = { { "Acorn Computers Ltd", _XmVirtKeys_acornFallbackBindingString }, { "Apollo Computer Inc.", _XmVirtKeys_apolloFallbackBindingString }, { "DECWINDOWS DigitalEquipmentCorp.", _XmVirtKeys_decFallbackBindingString }, { "Data General Corporation Rev 04", _XmVirtKeys_dgFallbackBindingString }, { "Double Click Imaging, Inc. KeyX", _XmVirtKeys_dblclkFallbackBindingString }, { "Hewlett-Packard Company", _XmVirtKeys_hpFallbackBindingString }, { "International Business Machines", _XmVirtKeys_ibmFallbackBindingString }, { "Intergraph Corporation", _XmVirtKeys_ingrFallbackBindingString }, { "Megatek Corporation", _XmVirtKeys_megatekFallbackBindingString }, { "Motorola Inc. (Microcomputer Division) ", _XmVirtKeys_motorolaFallbackBindingString }, { "Silicon Graphics Inc.", _XmVirtKeys_sgiFallbackBindingString }, { "Silicon Graphics", _XmVirtKeys_sgiFallbackBindingString }, { "Siemens Munich by SP-4's Hacker Crew", _XmVirtKeys_siemensWx200FallbackBindingString }, { "Siemens Munich (SP-4's hacker-clan)", _XmVirtKeys_siemens9733FallbackBindingString }, { "Sun Microsystems, Inc.", _XmVirtKeys_sunFallbackBindingString }, { "X11/NeWS - Sun Microsystems Inc.", _XmVirtKeys_sunFallbackBindingString }, { "Tektronix, Inc.", _XmVirtKeys_tekFallbackBindingString } }; /*ARGSUSED*/ static Boolean CvtStringToVirtualBinding(Display *dpy, XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *closure_ret ) { char *str = (char *)fromVal->addr; XKeyEvent event; int count, tmp; int *eventTypes; KeySym *keysyms; unsigned int *modifiers; int j; int codes_per_sym; KeyCode minK; Modifiers used_mods; /* Lookup codes_per_sym, and let Xt cache the result instead of */ /* always downloading a new copy with XGetKeyboardMapping(). */ /* This also initializes Xt's per-display data structures, so */ /* we can use XtTranslateKey() instead of XLookupString(). */ (void) XtGetKeysymTable(dpy, &minK, &codes_per_sym); count = _XmMapKeyEvents(str, &eventTypes, &keysyms, &modifiers); if (count > 0) { Boolean fini; for (tmp = 0; tmp < count; tmp++) { fini = False; /* * Here's a nasty bit of code. If some vendor defines one of * the standard modifiers to be the mode switch mod, the * keysym returned by XtTranslateKey is the mode-shifted * one. This may or may not be bogus, but we have to live * with it :-(. Soo, we need to translate the keysym to a * keycode, then ask someone to translate the combo for us. */ event.display = dpy; event.keycode = XKeysymToKeycode(dpy, keysyms[tmp]); /* * In case the guy specifies a symbol that is modified (like * HP's Del which is ), we'll find the implied * modifers and 'OR' it together with the explicitly stated * modifers. */ event.state = 0; if (XKeycodeToKeysym(dpy, event.keycode, 0) != keysyms[tmp]) for (j = 1; j < codes_per_sym; j++) if (XKeycodeToKeysym(dpy, event.keycode, j) == keysyms[tmp]) { /* * Gross Hack for Hobo keyboard .. * Assumptions: * 1. Hobo keyboard has XK_Return as the first entry * and XK_KP_Enter as the 4th entry in its * keycode to keysym key map. * 2. This fix is only designed to work for the precise * combination of the Sun server with vendor * string "Sun Microsystems, Inc." and the Hobo * keyboard, as the fix assumes knowledge of the * server keycode to keysym key map. */ if ((keysyms[tmp] == XK_KP_Enter) && (j == 4) && (XKeycodeToKeysym(dpy, event.keycode, 0) == XK_Return) && (strcmp("Sun Microsystems, Inc.", ServerVendor(dpy)) == 0)) { fini = True; } else event.state = 1 << (j-1); break; } if (!fini) { event.state |= modifiers[tmp]; XtTranslateKey(dpy, event.keycode, event.state, &used_mods, keysyms + tmp); } } /* Fail if insufficient storage was provided. */ if ((toVal->addr != NULL) && (toVal->size < sizeof(XmKeyBindingRec) * count)) { toVal->size = sizeof(XmKeyBindingRec) * count; XtFree((char*) eventTypes); XtFree((char*) keysyms); XtFree((char*) modifiers); return False; } /* Allocate storage if none was provided. */ toVal->size = sizeof(XmKeyBindingRec) * count; if (toVal->addr == NULL) toVal->addr = XtMalloc(toVal->size); /* Copy the data. */ for (tmp = 0; tmp < count; tmp++) { ((XmKeyBinding) toVal->addr)[tmp].keysym = keysyms[tmp]; ((XmKeyBinding) toVal->addr)[tmp].modifiers = modifiers[tmp]; } XtFree((char*) eventTypes); XtFree((char*) keysyms); XtFree((char*) modifiers); return True; } /* The value supplied could not be converted. */ XtDisplayStringConversionWarning(dpy, str, XmRVirtualBinding); return False; } static void FillBindingsFromDB(Display *dpy, XrmDatabase rdb, XmVKeyBinding *keys, Cardinal *num_keys) { XrmName xrm_name[2]; XrmClass xrm_class[2]; XrmRepresentation rep_type; XrmValue value; Cardinal vk_num; XrmQuark XmQVirtualBinding = XrmPermStringToQuark(XmRVirtualBinding); XrmQuark XmQString = XrmPermStringToQuark(XmRString); xrm_class[0] = XmQVirtualBinding; xrm_class[1] = 0; /* Previously entries in display.bindings corresponded exactly to */ /* entries in virtualKeysyms. Since multiple keysyms can be bound */ /* to a single virtual key, display.num_bindings and the virtkey */ /* field in XmVKeyBindingRec were added. This also allows us to */ /* remove null bindings from the table, improving search times. */ /* Allocate the initial arrays. */ *num_keys = 0; *keys = NULL; /* Process each known virtual key. */ for (vk_num = 0; vk_num < XtNumber(virtualKeysyms); vk_num++) { Boolean free_keys = False; XmKeyBinding new_keys = NULL; Cardinal new_num = 0; xrm_name[0] = XrmPermStringToQuark(virtualKeysyms[vk_num].name); xrm_name[1] = 0; if (XrmQGetResource(rdb, xrm_name, xrm_class, &rep_type, &value)) { if (rep_type == XmQVirtualBinding) { /* Resource already exists in the desired format? */ new_keys = (XmKeyBinding) value.addr; new_num = value.size / sizeof(XmKeyBindingRec); } else if (rep_type == XmQString) { /* Convert String resource to key bindings. */ XrmValue toVal; toVal.addr = NULL; toVal.size = 0; if (XtCallConverter(dpy, CvtStringToVirtualBinding, NULL, 0, &value, &toVal, NULL)) { new_keys = (XmKeyBinding) toVal.addr; new_num = toVal.size / sizeof(XmKeyBindingRec); free_keys = True; } } /* Append the new bindings to the end of the table. */ if (new_num > 0) { int tmp; *keys = (XmVKeyBinding) XtRealloc((char*) *keys, (*num_keys + new_num) * sizeof(XmVKeyBindingRec)); for (tmp = 0; tmp < new_num; tmp++) { (*keys)[*num_keys + tmp].keysym = new_keys[tmp].keysym; (*keys)[*num_keys + tmp].modifiers = new_keys[tmp].modifiers; (*keys)[*num_keys + tmp].virtkey = virtualKeysyms[vk_num].keysym; } *num_keys += new_num; } if (free_keys) XtFree((char *)new_keys); } } } static Boolean GetBindingsProperty(Display *display, String property, String *binding) { char *prop = NULL; Atom actual_type; int actual_format; unsigned long num_items; unsigned long bytes_after; if ( binding == NULL ) return False; XGetWindowProperty (display, RootWindow(display, 0), XInternAtom(display, property, FALSE), 0, (long)1000000, FALSE, XA_STRING, &actual_type, &actual_format, &num_items, &bytes_after, (unsigned char **) &prop); if ((actual_type != XA_STRING) || (actual_format != 8) || (num_items == 0)) { if (prop != NULL) XFree(prop); return False; } else { *binding = prop; return True; } } /* * This routine is called by the XmDisplay Initialize method to set * up the virtual bindings table, XtKeyProc, and event handler. */ void _XmVirtKeysInitialize(Widget widget) { XmDisplay xmDisplay = (XmDisplay) widget; Display *dpy = XtDisplay(xmDisplay); XrmDatabase keyDB; String bindingsString; String fallbackString = NULL; Boolean needXFree = False; if (!XmIsDisplay(widget)) return; bindingsString = xmDisplay->display.bindingsString; xmDisplay->display.lastKeyEvent = NULL; if (bindingsString == NULL) { /* XmNdefaultVirtualBindings not set, try _MOTIF_BINDINGS */ if (GetBindingsProperty(XtDisplay(xmDisplay), XmS_MOTIF_BINDINGS, &bindingsString) == True) { needXFree = True; } else if (GetBindingsProperty(XtDisplay(xmDisplay), XmS_MOTIF_DEFAULT_BINDINGS, &bindingsString) == True) { needXFree = True; } else { /* property not set, find a useful fallback */ _XmVirtKeysLoadFallbackBindings(XtDisplay(xmDisplay), &fallbackString); bindingsString = fallbackString; } } XtSetTypeConverter(XmRString, XmRVirtualBinding, CvtStringToVirtualBinding, NULL, 0, XtCacheNone, (XtDestructor)NULL); keyDB = XrmGetStringDatabase( bindingsString ); FillBindingsFromDB (XtDisplay(xmDisplay), keyDB, &xmDisplay->display.bindings, &xmDisplay->display.num_bindings); XrmDestroyDatabase(keyDB); if (needXFree) XFree (bindingsString); if (fallbackString) XtFree (fallbackString); XtSetKeyTranslator(dpy, (XtKeyProc)XmTranslateKey); } /* * This routine is called by the XmDisplay Destroy method to free * up the virtual bindings table. */ void _XmVirtKeysDestroy(Widget widget) { XmDisplay xmDisplay = (XmDisplay) widget; XtFree((char*)xmDisplay->display.lastKeyEvent); XtFree((char*)xmDisplay->display.bindings); } static void FindVirtKey(Display *dpy, KeyCode keycode, Modifiers modifiers, Modifiers *modifiers_return, KeySym *keysym_return ) { Cardinal i; XmDisplay xmDisplay = (XmDisplay) XmGetXmDisplay( dpy); XmVKeyBinding keyBindings = xmDisplay->display.bindings; KeyCode min_kcode; int ks_per_kc; KeySym *ks_table = XtGetKeysymTable( dpy, &min_kcode, &ks_per_kc); KeySym *kc_map = &ks_table[(keycode - min_kcode) * ks_per_kc]; Modifiers EffectiveSMMask = EffectiveStdModMask( dpy, kc_map, ks_per_kc); /* Get the modifiers from the actual event */ Modifiers VirtualStdMods = 0; Modifiers StdModMask; for (i = 0; i < xmDisplay->display.num_bindings; i++) { unsigned j = ks_per_kc; KeySym vks = keyBindings[i].keysym; if (vks) { while (j--) { /* Want to walk through keymap (containing all possible * keysyms generated by this keycode) to compare against * virtual key keysyms. Any keycode that can possibly * generate a virtual keysym must be sure to return all * modifiers that are in the virtual key binding, since * this means that those modifiers are now part of the * "standard modifiers" for this keycode. (A "standard * modifier" is a modifier that can affect which keysym * is generated from a particular keycode.) */ if ((j == 1) && (kc_map[j] == NoSymbol)) { KeySym uc, lc; XtConvertCase( dpy, kc_map[0], &lc, &uc); if ((vks == lc) || (vks == uc)) VirtualStdMods |= keyBindings[i].modifiers; break; } else if (vks == kc_map[j]) { /* The keysym generated by this keycode can possibly * be influenced by the virtual key modifier(s), so must * add the modifier(s) associated with this virtual * key to the returned list of "standard modifiers". * The Intrinsics requires that the set of modifiers * returned by the keyproc is constant for a given * keycode. */ VirtualStdMods |= keyBindings[i].modifiers; break; } } } } /* Don't want to return standard modifiers that do not * impact the keysym selected for a particular keycode, * since this blocks matching of translation productions * which use ":" style translations with the returned * standard modifier in the production. The ":" style * of production is essential for proper matching of * Motif translations (PC numeric pad, for instance). * * Recent fixes to the Intrinsics should have included this * change to the set of standard modifiers returned from * the default key translation routine, but could not be * done for reasons of backwards compatibility (which is * not an issue for Xm, since we do not export this facility). * So, we do the extra masking here after the return from * the call to XtTranslateKey. */ *modifiers_return &= EffectiveSMMask; /* Modifiers present in the virtual binding table for the * keysyms associated with this keycode, which are or might * have been used to change the keysym generated by this * keycode (to a virtual keysym), must be included in the * returned set of standard modifiers. Remember that "standard * modifiers" for a keycode are those modifiers that can affect * which keysym is generated by that keycode. */ *modifiers_return |= VirtualStdMods; /* Effective standard modifiers that are set in the event * will be 0 in the following bit mask, which will be used * to collapse conflicting modifiers in the virtual * key binding table, as described below. */ StdModMask = ~(modifiers & EffectiveSMMask); for (i = 0; i < xmDisplay->display.num_bindings; i++) { XmVKeyBinding currBinding = &keyBindings[i]; KeySym vks = currBinding->keysym; /* The null binding should not be interpreted as a match * keysym is zero (e.g. pre-edit terminator) */ /* Those modifiers that are effective standard modifiers and * that are set in the event will be ignored in the following * conditional (i.e., the state designated in the virtual key * binding will not be considered), since these modifiers have * already had their affect in the determination of the value * of *keysym_return. This allows matching that is consistent * with industry-standard interpretation for keys such as * those of the PC-style numeric pad. This apparent loss of * binding semantics is an unavoidable consequence of specifying * a modifier in the virtual binding table that is already being * used to select one of several keysyms associated with a * particular keycode (usually as printed on the keycap). * The disambiguation of the collapsing of key bindings * is based on "first match" in the virtual key binding table. */ if (vks && (vks == *keysym_return) && ((currBinding->modifiers & StdModMask) == (modifiers & VirtualStdMods & StdModMask))) { *keysym_return = currBinding->virtkey; break; } } } static Modifiers EffectiveStdModMask(Display *dpy, KeySym *kc_map, int ks_per_kc) { /* This routine determines which set of modifiers can possibly * impact the keysym that is generated by the keycode associated * with the keymap passed in. The basis of the algorithm used * here is described in section 12.7 "Keyboard Encoding" of the * R5 "Xlib - C Language X Interface" specification. */ KeySym uc; KeySym lc; /* Since the group modifier can be any of Mod1-Mod5 or Control, we will * return all of these bits if the group modifier is found to be effective. * Lock will always be returned (for backwards compatibility with * productions assuming that Lock is always a "don't care" modifier * for non-alphabetic keys). Shift will be returned unless it has * no effect on the selection of keysyms within either group. */ Modifiers esm_mask = (Mod5Mask | Mod4Mask | Mod3Mask | Mod2Mask | Mod1Mask | ControlMask | LockMask | ShiftMask); switch (ks_per_kc) { default: /* CR 8799: Ignore non-standard modifier groups. */ case 4: if (kc_map[3] != NoSymbol) { /* The keysym in position 4 is selected when the group * modifier is set and the Shift (or Lock) modifier is * set, so both Shift/Lock and the group modifiers are * all "effective" standard modifiers. */ break; } case 3: if (kc_map[2] == NoSymbol) { /* Both Group 2 keysyms are NoSymbol, so the group * modifier has no effect; only Shift and Lock remain * as possible effective modifiers. */ esm_mask = ShiftMask | LockMask; } else { XtConvertCase( dpy, kc_map[2], &lc, &uc); if (lc != uc) { /* The Group 2 keysym is case-sensitive, so group * modifiers and Shift/Lock modifiers are effective. */ break; } } /* At this fall-through, the group modifier bits have been * decided, while the case is still out on Shift/Lock. */ case 2: if (kc_map[1] != NoSymbol) { /* Shift/Lock modifier selects keysym from Group 1, * so leave those bits in the mask. The group modifier * was determined above, so leave those bits in the mask. */ break; } case 1: if (kc_map[0] != NoSymbol) { XtConvertCase( dpy, kc_map[0], &lc, &uc); if (lc != uc) { /* The Group 1 keysym is case-sensitive, so Shift/Lock * modifiers are effective. */ break; } } /* If we did not break out of the switch before this, then * the Shift modifier is not effective; mask it out. */ esm_mask &= ~ShiftMask; case 0: break; } return esm_mask; } void XmTranslateKey(Display *dpy, #if NeedWidePrototypes unsigned int keycode, #else KeyCode keycode, #endif /* NeedWidePrototypes */ Modifiers modifiers, Modifiers *modifiers_return, KeySym *keysym_return ) { _XmDisplayToAppContext(dpy); _XmAppLock(app); XtTranslateKey(dpy, keycode, modifiers, modifiers_return, keysym_return); FindVirtKey(dpy, keycode, modifiers, modifiers_return, keysym_return); _XmAppUnlock(app); } int XmeVirtualToActualKeysyms(Display *dpy, KeySym virtKeysym, XmKeyBinding *actualKeyData) { int matches; Cardinal index; XmDisplay xmDisplay = (XmDisplay)XmGetXmDisplay (dpy); XmVKeyBinding keyBindings = xmDisplay->display.bindings; _XmDisplayToAppContext(dpy); _XmAppLock(app); /* Initialize the return parameters. */ *actualKeyData = NULL; /* Count the number of matches. */ matches = 0; for (index = 0; index < xmDisplay->display.num_bindings; index++) if (keyBindings[index].virtkey == virtKeysym) matches++; /* Allocate the return array. */ if (matches > 0) { *actualKeyData = (XmKeyBinding) XtMalloc(matches * sizeof(XmKeyBindingRec)); matches = 0; for (index = 0; index < xmDisplay->display.num_bindings; index++) if (keyBindings[index].virtkey == virtKeysym) { (*actualKeyData)[matches].keysym = keyBindings[index].keysym; (*actualKeyData)[matches].modifiers = keyBindings[index].modifiers; matches++; } } _XmAppUnlock(app); return matches; } Boolean _XmVirtKeysLoadFileBindings(char *fileName, String *binding ) { FILE *fileP; int buffersize; int count; int firsttime; char line[256]; Boolean skip; if ((fileP = fopen (fileName, "r")) != NULL) { skip = False; count = 0; buffersize = 1; firsttime = 1; while (fgets(line, sizeof(line), fileP) != NULL) { /* handle '!' comments; they can extend across mutliple reads */ if (skip) { if (line[strlen(line) - 1] == '\n') skip = False; continue; } if (line[0] == '!') { if (line[strlen(line) - 1] == '\n') continue; else { skip = True; continue; } } /* must be >=, because buffersize is always 1 bigger for '\0' */ if (count + strlen(line) >= buffersize) { buffersize += BUFFERSIZE; *binding = XtRealloc(*binding, buffersize); /* always make sure that the end of *binding is null terminated */ if (firsttime) { *binding[0] = '\0'; firsttime = 0; } } count += strlen(line); strcat(*binding, line); } /* trim unused buffer space */ *binding = XtRealloc (*binding, count + 1); fclose (fileP); return True; } return False; } static void LoadVendorBindings(Display *display, char *path, FILE *fp, String *binding ) { char buffer[MAXLINE]; char *bindFile; char *vendor; char *vendorV; char *ptr; char *start; vendor = ServerVendor(display); vendorV = XtMalloc (strlen(vendor) + 20); /* assume rel.# is < 19 digits */ sprintf (vendorV, "%s %d", vendor, VendorRelease(display)); while (fgets (buffer, MAXLINE, fp) != NULL) { ptr = buffer; while (*ptr != '"' && *ptr != '!' && *ptr != '\0') ptr++; if (*ptr != '"') continue; start = ++ptr; while (*ptr != '"' && *ptr != '\0') ptr++; if (*ptr != '"') continue; *ptr = '\0'; if ((strcmp (start, vendor) == 0) || (strcmp (start, vendorV) == 0)) { ptr++; while (isspace((unsigned char)*ptr) && *ptr) ptr++; if (*ptr == '\0') continue; start = ptr; while (!isspace((unsigned char)*ptr) && *ptr != '\n' && *ptr) ptr++; *ptr = '\0'; bindFile = _XmOSBuildFileName (path, start); if (_XmVirtKeysLoadFileBindings (bindFile, binding)) { XtFree (bindFile); break; } XtFree (bindFile); } } XtFree (vendorV); } int _XmVirtKeysLoadFallbackBindings(Display *display, String *binding ) { enum { XmA_MOTIF_BINDINGS, XmA_MOTIF_DEFAULT_BINDINGS, NUM_ATOMS }; static char *atom_names[] = {XmS_MOTIF_BINDINGS, XmS_MOTIF_DEFAULT_BINDINGS}; XmConst XmDefaultBindingStringRec *currDefault; int i; FILE *fp; char *homeDir; char *fileName; char *bindDir; static XmConst char xmbinddir_fallback[] = XMBINDDIR_FALLBACK; Atom atoms[XtNumber(atom_names)]; *binding = NULL; assert(XtNumber(atom_names) == NUM_ATOMS); XInternAtoms(display, atom_names, XtNumber(atom_names), False, atoms); /* Load .motifbind - necessary, if mwm and xmbind are not used */ homeDir = XmeGetHomeDirName(); fileName = _XmOSBuildFileName(homeDir, MOTIFBIND); _XmVirtKeysLoadFileBindings(fileName, binding); XtFree(fileName); /* Look for a match in the user's xmbind.alias */ if (*binding == NULL) { fileName = _XmOSBuildFileName (homeDir, XMBINDFILE); if ((fp = fopen (fileName, "r")) != NULL) { LoadVendorBindings (display, homeDir, fp, binding); fclose (fp); } XtFree (fileName); } if (*binding != NULL) { /* Set the user property for future Xm applications. */ XChangeProperty (display, RootWindow(display, 0), atoms[XmA_MOTIF_BINDINGS], XA_STRING, 8, PropModeReplace, (unsigned char *)*binding, strlen(*binding)); return 0; } /* Look for a match in the system xmbind.alias */ if (*binding == NULL) { if ((bindDir = getenv(XMBINDDIR)) == NULL) bindDir = (char*) xmbinddir_fallback; fileName = _XmOSBuildFileName (bindDir, XMBINDFILE); if ((fp = fopen (fileName, "r")) != NULL) { LoadVendorBindings (display, bindDir, fp, binding); fclose (fp); } XtFree (fileName); } /* Check hardcoded fallbacks (for 1.1 bc) */ if (*binding == NULL) { for (i = 0, currDefault = fallbackBindingStrings; i < XtNumber(fallbackBindingStrings); i++, currDefault++) { if (strcmp(currDefault->vendorName, ServerVendor(display)) == 0) { *binding = XtMalloc (strlen (currDefault->defaults) + 1); strcpy (*binding, currDefault->defaults); break; } } } /* Use generic fallback bindings */ if (*binding == NULL) { *binding = XtMalloc (strlen (defaultFallbackBindings) + 1); strcpy (*binding, defaultFallbackBindings); } /* Set the fallback property for future Xm applications */ XChangeProperty (display, RootWindow(display, 0), atoms[XmA_MOTIF_DEFAULT_BINDINGS], XA_STRING, 8, PropModeReplace, (unsigned char *)*binding, strlen(*binding)); return 0; }