/* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * HISTORY */ #ifdef HAVE_CONFIG_H #include #endif #ifdef REV_INFO #ifndef lint static char rcsid[] = "$XConsortium: MapEvents.c /main/12 1995/09/19 23:05:22 cde-sun $" #endif #endif /* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ /* (c) Copyright 1988 MASSACHUSETTS INSTITUTE OF TECHNOLOGY */ #include #include #include #include #include #include "XmI.h" #include "MapEventsI.h" typedef String (*XmEventParseProc)(String str, unsigned int closure, unsigned long *detail, Boolean *status); typedef struct { XmConst char *event; XrmQuark signature; int eventType; XmEventParseProc parseProc; unsigned int closure; } EventKey; /******** Static Function Declarations ********/ static int StrToHex( String str) ; static int StrToOct( String str) ; static int StrToNum( String str) ; static void FillInQuarks( EventKey *table) ; static Boolean LookupModifier( String name, Modifiers *valueP) ; static String ScanAlphanumeric( register String str) ; static String ScanWhitespace( register String str) ; static String ParseImmed( String str, unsigned int closure, unsigned long *detail, Boolean *status) ; static String ParseKeySym( String str, unsigned int closure, unsigned long *detail, Boolean *status) ; static String ParseModifiers( register String str, Modifiers *modifiers, Boolean *status) ; static String ParseEventType( register String str, EventKey *table, int *eventType, Cardinal *_index, Boolean *status) ; static String _MapEvent( register String str, EventKey *table, int *eventType, unsigned long *detail, Modifiers *modifiers, Boolean *status) ; /******** End Static Function Declarations ********/ static EventKey modifierStrings[] = { /* Modifier, Quark, Mask */ {"None", NULLQUARK, 0, NULL, None}, {"Shift", NULLQUARK, 0, NULL, ShiftMask}, {"Lock", NULLQUARK, 0, NULL, LockMask}, {"Ctrl", NULLQUARK, 0, NULL, ControlMask}, {"Meta", NULLQUARK, 0, NULL, Mod1Mask}, {"Alt", NULLQUARK, 0, NULL, Mod1Mask}, {"Mod1", NULLQUARK, 0, NULL, Mod1Mask}, {"Mod2", NULLQUARK, 0, NULL, Mod2Mask}, {"Mod3", NULLQUARK, 0, NULL, Mod3Mask}, {"Mod4", NULLQUARK, 0, NULL, Mod4Mask}, {"Mod5", NULLQUARK, 0, NULL, Mod5Mask}, {NULL, NULLQUARK, 0, NULL, 0}}; static EventKey buttonEvents[] = { /* Event Name, Quark, Event Type, DetailProc, Closure */ {"Btn1Down", NULLQUARK, ButtonPress, ParseImmed, Button1}, {"Button1", NULLQUARK, ButtonPress, ParseImmed, Button1}, {"Btn1", NULLQUARK, ButtonPress, ParseImmed, Button1}, {"Btn2Down", NULLQUARK, ButtonPress, ParseImmed, Button2}, {"Button2", NULLQUARK, ButtonPress, ParseImmed, Button2}, {"Btn2", NULLQUARK, ButtonPress, ParseImmed, Button2}, {"Btn3Down", NULLQUARK, ButtonPress, ParseImmed, Button3}, {"Button3", NULLQUARK, ButtonPress, ParseImmed, Button3}, {"Btn3", NULLQUARK, ButtonPress, ParseImmed, Button3}, {"Btn4Down", NULLQUARK, ButtonPress, ParseImmed, Button4}, {"Button4", NULLQUARK, ButtonPress, ParseImmed, Button4}, {"Btn4", NULLQUARK, ButtonPress, ParseImmed, Button4}, {"Btn5Down", NULLQUARK, ButtonPress, ParseImmed, Button5}, {"Button5", NULLQUARK, ButtonPress, ParseImmed, Button5}, {"Btn5", NULLQUARK, ButtonPress, ParseImmed, Button5}, {NULL, NULLQUARK, 0, NULL, 0}}; static EventKey keyEvents[] = { /* Event Name, Quark, Event Type, DetailProc Closure */ {"KeyPress", NULLQUARK, KeyPress, ParseKeySym, 0}, {"Key", NULLQUARK, KeyPress, ParseKeySym, 0}, {"KeyDown", NULLQUARK, KeyPress, ParseKeySym, 0}, {"KeyUp", NULLQUARK, KeyRelease, ParseKeySym, 0}, {"KeyRelease", NULLQUARK, KeyRelease, ParseKeySym, 0}, {NULL, NULLQUARK, 0, NULL, 0}}; static XmConst Modifiers buttonModifierMasks[] = { 0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask }; static Boolean initialized = FALSE; /*************************************<->************************************* * * Numeric convertion routines * * Description: * ----------- * StrToHex = Parse an ASCII string as a hexadecimal integer. * StrToOct = Parse an ASCII string as an octal integer. * StrToNum = Parse an ASCII string as a hex, octal or decimal integer * based on leading "0", "0x", or "0X" characters. * * * Inputs: * ------ * str = A null-terminated span of digits. * StrToNum handles C prefix conventions (0d = octal, 0xd = hex), * but no other non-digits are allowed. * * Outputs: * ------- * Returns -1 if conversion fails, otherwise the numeric value. * Empty strings convert to 0. * * Procedures Called * ----------------- * None. * *************************************<->***********************************/ static int StrToHex( String str ) { register char c; register int val = 0; while ((c = *str) != '\0') { if ('0' <= c && c <= '9') val = val*16+c-'0'; else if ('a' <= c && c <= 'f') val = val*16+c-'a'+10; else if ('A' <= c && c <= 'F') val = val*16+c-'A'+10; else return -1; str++; } return val; } static int StrToOct( String str ) { register char c; register int val = 0; while ((c = *str) != '\0') { if ('0' <= c && c <= '7') val = val*8+c-'0'; else return -1; str++; } return val; } static int StrToNum( String str ) { register char c; register int val = 0; if (*str == '0') { str++; if (*str == 'x' || *str == 'X') return StrToHex(++str); else return StrToOct(str); } while ((c = *str) != '\0') { if ('0' <= c && c <= '9') val = val*10+c-'0'; else return -1; str++; } return val; } /*************************************<->************************************* * * FillInQuarks (EventKey *table) * * Description: * ----------- * Converts each string entry in the modifier/event tables to a * quark, thus facilitating faster comparisons. * * * Inputs: * ------ * table[*].event = strings to be converted (NULL at end of table). * * Outputs: * ------- * table[*].signature = quarks for each string. * * Procedures Called * ----------------- * XrmStringToQuark. * *************************************<->***********************************/ static void FillInQuarks( EventKey *table ) { register int i; for (i=0; table[i].event; i++) table[i].signature = XrmPermStringToQuark(table[i].event); } /*************************************<->************************************* * * LookupModifier (name, *valueP) * * Description: * ----------- * Compare the passed in string to the list of valid modifiers. * * * Inputs: * ------ * name = string to be located in the global modiferStrings table. * (modiferStrings = global table of valid modifiers). * * Outputs: * ------- * *valueP = closure of modifierString with a matching signature. * Return value indicates whether a match was found. * * Procedures Called * ----------------- * XrmStringToQuark. * *************************************<->***********************************/ static Boolean LookupModifier( String name, Modifiers *valueP ) { register int i; register XrmQuark signature = XrmStringToQuark(name); for (i=0; modifierStrings[i].event != NULL; i++) if (modifierStrings[i].signature == signature) { *valueP = modifierStrings[i].closure; return TRUE; } return FALSE; } /*************************************<->************************************* * * ScanAlphanumeric (String str) * * Description: * ----------- * Scan string until a non-alphanumeric character is encountered. * * * Inputs: * ------ * str = string to be scanned. * * Outputs: * ------- * Return value points to the first non-alphanumeric character in str. * * Procedures Called * ----------------- * *************************************<->***********************************/ static String ScanAlphanumeric( register String str ) { while ( ('A' <= *str && *str <= 'Z') || ('a' <= *str && *str <= 'z') || ('0' <= *str && *str <= '9')) str++; return str; } /*************************************<->************************************* * * ScanWhitespace (String str) * * Description: * ----------- * Scan the string, skipping over all white space characters. * Whitespace is defined as tab or space. * * * Inputs: * ------ * str = the string to be scanned. * * Outputs: * ------- * Return value points to the first non-whitespace character in str. * * Procedures Called * ----------------- * *************************************<->***********************************/ static String ScanWhitespace( register String str ) { while (*str == ' ' || *str == '\t') str++; return str; } /*************************************<->************************************* * * ParseImmed * * Description: * ----------- * An XmEventParseProc. Copy closure into detail. * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ /* ARGSUSED */ static String ParseImmed( String str, unsigned int closure, unsigned long *detail, Boolean *status) { *detail = closure; *status = TRUE; return str; } /*************************************<->************************************* * * ParseKeySym (parameters) * * Description: * ----------- * An XmeventParseProc. * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ /* ARGSUSED */ static String ParseKeySym( String str, unsigned int closure, unsigned long *detail, Boolean *status) { char keySymName[100]; char *start = str; /* Initialize the return values. */ *detail = NoSymbol; *status = FALSE; str = ScanWhitespace(str); if (*str == '\\') { /* "\x"; interpret "x" as a Keysym. */ str++; keySymName[0] = *str++; keySymName[1] = '\0'; *detail = XStringToKeysym(keySymName); } else if (*str == ',' || *str == ':') { /* No detail; return a failure */ return str; } else { while (*str != ',' && *str != ':' && *str != ' ' && *str != '\t' && *str != '\n' && *str != '\0') str++; (void) strncpy(keySymName, start, str-start); keySymName[str-start] = '\0'; *detail = XStringToKeysym(keySymName); } if (*detail == NoSymbol) { if (( '0' <= keySymName[0]) && (keySymName[0] <= '9')) { int retval = StrToNum(keySymName); if (-1 == retval) { *detail = 0; return str; } else { *detail = retval; *status = TRUE; return str; } } return str; } else { *status = TRUE; return str; } } /*************************************<->************************************* * * ParseModifiers (parameters) * * Description: * ----------- * Parse the string, extracting all modifier specifications. * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ static String ParseModifiers( register String str, Modifiers *modifiers, Boolean *status ) { register String start; char modStr[100]; Boolean notFlag; Modifiers maskBit; /* Initially assume all is going to go well */ *status = TRUE; *modifiers = 0; /* Attempt to parse the first button modifier */ str = ScanWhitespace(str); start = str; str = ScanAlphanumeric(str); if (start != str) { (void) strncpy(modStr, start, str-start); modStr[str-start] = '\0'; if (LookupModifier(modStr, &maskBit)) { if (maskBit== None) { *modifiers = 0; str = ScanWhitespace(str); return str; } } str = start; } /* Keep parsing modifiers, until the event specifier is encountered */ while ((*str != '<') && (*str != '\0')) { if (*str == '~') { notFlag = TRUE; str++; } else notFlag = FALSE; start = str; str = ScanAlphanumeric(str); if (start == str) { /* ERROR: Modifier or '<' missing */ *status = FALSE; return str; } (void) strncpy(modStr, start, str-start); modStr[str-start] = '\0'; if (!LookupModifier(modStr, &maskBit)) { /* Unknown modifier name */ *status = FALSE; return str; } if (notFlag) *modifiers &= ~maskBit; else *modifiers |= maskBit; str = ScanWhitespace(str); } return str; } /*************************************<->************************************* * * ParseEventType (parameters) * * Description: * ----------- * xxxxxxxxxxxxxxxxxxxxxxx * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ static String ParseEventType( register String str, EventKey *table, int *eventType, Cardinal *_index, Boolean *status ) { String start = str; char eventTypeStr[100]; register Cardinal i; register XrmQuark signature; /* Parse out the event string */ str = ScanAlphanumeric(str); (void) strncpy(eventTypeStr, start, str-start); eventTypeStr[str-start] = '\0'; /* Attempt to match the parsed event against our supported event set */ signature = XrmStringToQuark(eventTypeStr); for (i = 0; table[i].signature != NULLQUARK; i++) if (table[i].signature == signature) { *_index = i; *eventType = table[*_index].eventType; *status = TRUE; return str; } /* Unknown event specified */ *status = FALSE; return (str); } /*************************************<->************************************* * * _MapEvent (parameters) * * Description: * ----------- * xxxxxxxxxxxxxxxxxxxxxxx * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ static String _MapEvent( register String str, EventKey *table, int *eventType, unsigned long *detail, Modifiers *modifiers, Boolean *status) { Cardinal index; /* Initialize, if first time called */ _XmProcessLock(); if (!initialized) { initialized = TRUE; FillInQuarks (buttonEvents); FillInQuarks (modifierStrings); FillInQuarks (keyEvents); } _XmProcessUnlock(); /* Parse the modifiers and the '<' */ str = ParseModifiers(str, modifiers, status); if (*str != '<') *status = FALSE; if (*status == FALSE) return str; str++; /* Parse the event type and detail and the '>' */ str = ParseEventType(str, table, eventType, &index, status); if (*str != '>') *status = FALSE; if (*status == FALSE) return str; str++; /* Save the detail */ return ((*(table[index].parseProc))(str, table[index].closure, detail, status)); } /*************************************<->************************************* * * _MapBtnEvent (parameters) * * Description: * ----------- * xxxxxxxxxxxxxxxxxxxxxxx * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ Boolean _XmMapBtnEvent( register String str, int *eventType, unsigned int *button, Modifiers *modifiers ) { Boolean status; unsigned long detail; _MapEvent (str, buttonEvents, eventType, &detail, modifiers, &status); *button = detail; if (status == FALSE) return (FALSE); /* * The following is a fix for an X11 deficiency in regards to * modifiers in grabs. */ if (*eventType == ButtonRelease) { /* the button that is going up will always be in the modifiers... */ *modifiers |= buttonModifierMasks[*button]; } return (TRUE); } /*************************************<->************************************* * * _XmMapKeyEvents (parameters) * * Description: * ----------- * Parse a comma-separated list of key events. * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ int _XmMapKeyEvents(String str, int **eventTypes, KeySym **keysyms, Modifiers **modifiers) { Boolean status = TRUE; int count = 0; char *ptr = str; *eventTypes = NULL; *keysyms = NULL; *modifiers = NULL; while (status) { int tmp_type; unsigned long tmp_sym; Modifiers tmp_mods; /* Parse a single event. */ ptr = _MapEvent(ptr, keyEvents, &tmp_type, &tmp_sym, &tmp_mods, &status); if (!status) break; /* Save this event. */ *eventTypes = (int *) XtRealloc((char*) *eventTypes, (count + 1) * sizeof(int)); (*eventTypes)[count] = tmp_type; *keysyms = (KeySym *) XtRealloc((char*) *keysyms, (count + 1) * sizeof(KeySym)); (*keysyms)[count] = (KeySym)tmp_sym; *modifiers = (Modifiers *) XtRealloc((char*) *modifiers, (count + 1) * sizeof(Modifiers)); (*modifiers)[count] = tmp_mods; count++; /* Skip the separator. */ ptr = ScanWhitespace(ptr); if (*ptr == '\0') break; else if (*ptr == ',') ptr++; else status = FALSE; } /* Discard partial results if something fails. */ if (!status) { count = 0; XtFree((char*) *eventTypes); *eventTypes = NULL; XtFree((char*) *keysyms); *keysyms = NULL; XtFree((char*) *modifiers); *modifiers = NULL; } return count; } /*************************************<->************************************* * * _XmMatchBtnEvent (parameters) * * Description: * ----------- * Compare the passed in event to the event described by the parameter * list. * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ Boolean _XmMatchBtnEvent( XEvent *event, int eventType, unsigned int button, Modifiers modifiers ) { register Modifiers state = event->xbutton.state & (ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask); if (((eventType == XmIGNORE_EVENTTYPE)||(event->type == eventType)) && (event->xbutton.button == button) && ((modifiers == AnyModifier)||(state == modifiers)) ) return (TRUE); else return (FALSE); } /*************************************<->************************************* * * _XmMatchKeyEvent (parameters) * * Description: * ----------- * Compare the passed in event to the event described by the parameter * list. * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ Boolean _XmMatchKeyEvent( XEvent *event, int eventType, unsigned int key, Modifiers modifiers ) { #ifdef FIX_345 register Modifiers state, mods; _XmCheckInitModifiers(); state = event->xkey.state & ~(LockMask|ScrollLockMask|NumLockMask); mods = modifiers & ~(LockMask|ScrollLockMask|NumLockMask); #endif if ((event->type == eventType) && (event->xkey.keycode == key) && #ifdef FIX_345 (state == mods)) #else (event->xkey.state == modifiers)) #endif return (TRUE); else return (FALSE); }