/* $Id: keys.c,v 1.14 2005/09/15 15:03:17 cegger Exp $ ****************************************************************************** This LibGIC module is a very simple parser for KeyPress Events. Copyright (C) 1999 Andreas Beck [becka@ggi-project.org] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************** */ #include #include #include #include #include #include #include /* for snprintf() */ struct keypress { enum mode { LABEL, BUTTON, SYMBOL, NUM_MODES } mode; uint32_t value; }; static char modemap[NUM_MODES] = "LBS"; static int key_check(gic_handle_t hand, gic_recognizer *ctrl, gii_event *event,gic_feature *feature,int recnum); static int key_get_name(gic_handle_t hand, gic_recognizer *ctrl, char *string,size_t maxlen); static int key_write_pvtdata(gic_handle_t hand, gic_recognizer *ctrl, char *string,int maxlen); static int key_read_pvtdata(gic_handle_t hand, gic_recognizer *ctrl, const char *string); static void key_free_pvtdata(gic_handle_t hand, gic_recognizer *ctrl); static int key_train(gic_handle_t hand, gic_recognizer **ctrl,gii_event *event); static int key_check_conflict(gic_handle_t hand, gic_recognizer *ctrl, gic_recognizer *ctrl2); static int key_get_opposite(gic_handle_t hand, gic_recognizer *recognizer, gic_recognizer **opposite); static gic_recognizerdriver mycontrols= { "Key", key_check, key_get_name, key_write_pvtdata, key_read_pvtdata, key_free_pvtdata, key_train, key_check_conflict, key_get_opposite, }; static int chkkey(struct keypress *kp,gii_event *event) { DPRINT_LIBS("Keys: keyEvent L%04x,B%04xS%04x [want %c,%04x].\n", event->key.label,event->key.button,event->key.sym, modemap[kp->mode],kp->value); switch(kp->mode) { case LABEL: return (event->key.label == (unsigned)kp->value); case BUTTON: return (event->key.button == (unsigned)kp->value); case SYMBOL: return (event->key.sym == (unsigned)kp->value); default: return 0; } return 0; } static int key_check(gic_handle_t hand, gic_recognizer *ctrl, gii_event *event,gic_feature *feature,int recnum) { DPRINT_LIBS("Keys: Check with %p,%p.\n",ctrl,event); switch(event->any.type) { case evKeyPress: case evKeyRepeat: if (chkkey(ctrl->privdata,event)) { gicFeatureActivate(hand, feature, GIC_STATE_MAX, 0, recnum); return 1; } break; case evKeyRelease: if (chkkey(ctrl->privdata,event)) { gicFeatureActivate(hand, feature, GIC_STATE_MIN, 0, recnum); return 1; } break; } return 0; } static int keys_register(gic_handle_t hand, gic_recognizer **ctrl,struct keypress *kp,gic_state state) { gic_recognizer *rl; struct keypress *mkp; for (rl=*ctrl; rl != NULL; rl=rl->next) { struct keypress *cur = (struct keypress *) rl->privdata; if ((cur->mode == kp->mode) && (cur->value == kp->value)) { /* Duplicate entry -- just update the confidence * value. */ if (state > rl->confidence) { rl->confidence = state; /* !!! MOVE UP */ } return 1; } } rl = malloc(sizeof(gic_recognizer)); if (rl == NULL) return GGI_ENOMEM; mkp = malloc(sizeof(struct keypress)); if (mkp == NULL) { free(rl); return GGI_ENOMEM; } memcpy(mkp,kp,sizeof(struct keypress)); rl->driver=&mycontrols; rl->confidence=state; rl->privdata=mkp; gicRecognizerTrainAdd(hand,ctrl,rl); return 1; } static struct trainingstate { int label,button,sym; } trainingstate; #define CONFIDENCE(percent) \ (GIC_STATE_MIN + (GIC_STATE_MAX-GIC_STATE_MIN)/100 * (percent)) static int key_train(gic_handle_t hand, gic_recognizer **ctrl,gii_event *event) { struct keypress kp; int rc; DPRINT_LIBS("Keys: Training with %p,%p.\n",ctrl,event); rc=0; if (event) { DPRINT_LIBS("Keys: Analyzing event ...\n"); switch(event->any.type) { case evKeyPress: /* O.K. remember the press */ trainingstate.label =event->key.label; trainingstate.button=event->key.button; trainingstate.sym =event->key.sym; DPRINT_LIBS("Keys: Remembering last pressed key ...\n"); return 0; case evKeyRelease: DPRINT_LIBS("Keys: Checking released key ...\n"); if ((unsigned)trainingstate.label == event->key.label && trainingstate.label != GIIK_VOID) { kp.mode=LABEL; kp.value=event->key.label; rc+=keys_register(hand, ctrl,&kp,CONFIDENCE(100)); DPRINT_LIBS("Keys: register label mode ...\n"); } if ((unsigned)trainingstate.sym == event->key.sym && trainingstate.sym != GIIK_VOID) { kp.mode=SYMBOL; kp.value=event->key.sym; rc+=keys_register(hand, ctrl,&kp,CONFIDENCE(90)); DPRINT_LIBS("Keys: register symbol mode ...\n"); } if ((unsigned)trainingstate.button == event->key.button && trainingstate.button != GIIK_VOID) { kp.mode=BUTTON; kp.value=event->key.button; rc+=keys_register(hand, ctrl,&kp,CONFIDENCE(80)); DPRINT_LIBS("Keys: register button mode ...\n"); } } } else { trainingstate.sym= trainingstate.label= trainingstate.button=GIIK_VOID; DPRINT_LIBS("Keys: Initialized training state.\n"); } return rc; } /* * Privatedata format is : * mode (0-2) value (hex, 4 digits) * modes are : KeyLabel (0), Keycode (1), KeySymbol (2) * value is the appropriate value of the corresponding field. */ static int key_write_pvtdata(gic_handle_t hand, gic_recognizer *ctrl, char *string,int maxlen) { struct keypress *keyp=ctrl->privdata; if (maxlen < 7) { *string='\0'; return GGI_ENOSPACE; } sprintf(string,"%c %04x",modemap[keyp->mode],keyp->value); return 0; } static int key_read_pvtdata(gic_handle_t hand, gic_recognizer *ctrl, const char *string) { struct keypress *keyp; char hlp; int x; keyp=ctrl->privdata=malloc(sizeof(struct keypress)); sscanf(string,"%c %x",&hlp,&keyp->value); for(x=0;xmode=x; break; } } return 0; } static void key_free_pvtdata(gic_handle_t hand, gic_recognizer *ctrl) { struct keypress *keyp=ctrl->privdata; free(keyp);ctrl->privdata=NULL; return; } static const char *name_of_key(uint32_t value, int is_label, int want_short) { static char namebuf[40]; if (GII_KTYP(value) == GII_KT_LATIN1) { int c = GII_KVAL(value); switch(value) { case GIIUC_BackSpace: return ""; case GIIUC_Tab: return ""; case GIIUC_Linefeed: return ""; case GIIUC_Return: return ""; case GIIUC_Escape: return ""; case GIIUC_Delete: return ""; case GIIUC_Space: return ""; case GIIUC_NoBreakSpace: return ""; } if (c < 32) { snprintf(namebuf, 40, " ^%c", c+64); return namebuf; } if (((0x21 <= c) && (c <= 0x7e)) || ((0xA1 <= c) && (c <= 0xff))) { snprintf(namebuf, 40, " %c", c); return namebuf; } } else if (GII_KTYP(value) == GII_KT_FN) { snprintf(namebuf, 40, "", GII_KVAL(value)); return namebuf; } else if (GII_KTYP(value) == GII_KT_MOD) { if (is_label) switch (value) { case GIIK_ShiftL: return ""; case GIIK_ShiftR: return ""; case GIIK_CtrlL: return ""; case GIIK_CtrlR: return ""; case GIIK_AltL: return ""; case GIIK_AltR: return ""; case GIIK_MetaL: return ""; case GIIK_MetaR: return ""; case GIIK_SuperL: return ""; case GIIK_SuperR: return ""; case GIIK_HyperL: return ""; case GIIK_HyperR: return ""; default: break; } else switch (value) { case GIIK_Shift: return ""; case GIIK_Ctrl: return ""; case GIIK_Alt: return ""; case GIIK_Meta: return ""; case GIIK_Super: return ""; case GIIK_Hyper: return ""; case GIIK_AltGr: return ""; case GIIK_Caps: return ""; case GIIK_Num: return ""; case GIIK_Scroll: return ""; default: break; } } else switch(value) { case GIIUC_BackSpace: return ""; case GIIK_ShiftLock: return ""; case GIIK_CtrlLock: return ""; case GIIK_AltLock: return ""; case GIIK_MetaLock: return ""; case GIIK_SuperLock: return ""; case GIIK_HyperLock: return ""; case GIIK_AltGrLock: return ""; case GIIK_CapsLock: return ""; case GIIK_NumLock: return ""; case GIIK_ScrollLock: return ""; case GIIK_ScrollForw: return ""; case GIIK_ScrollBack: return ""; case GIIK_Undo: return ""; case GIIK_Redo: return ""; case GIIK_Menu: return ""; case GIIK_Cancel: return ""; case GIIK_PrintScreen: return ""; case GIIK_Execute: return ""; case GIIK_Find: return ""; case GIIK_Begin: return ""; case GIIK_Clear: return ""; case GIIK_Insert: return ""; case GIIK_Select: return "