int lk_add_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index, int keycode) { struct lk_array *map; unsigned int code = keycode + 1; if (keycode == CODE_FOR_UNKNOWN_KSYM) { /* is safer not to be silent in this case, * it can be caused by coding errors as well. */ ERR(ctx, _("lk_add_key called with bad keycode %d"), keycode); return -1; } if (!k_index && keycode == K_NOSUCHMAP) return 0; map = lk_array_get_ptr(ctx->keymap, k_table); if (!map) { if (ctx->keywords & LK_KEYWORD_KEYMAPS) { ERR(ctx, _("adding map %d violates explicit keymaps line"), k_table); return -1; } if (lk_add_map(ctx, k_table) < 0) return -1; } if ((ctx->keywords & LK_KEYWORD_ALTISMETA) && keycode == K_HOLE && lk_key_exists(ctx, k_table, k_index)) return 0; map = lk_array_get_ptr(ctx->keymap, k_table); if (lk_array_set(map, k_index, &code) < 0) { ERR(ctx, _("unable to set key %d for table %d"), k_index, k_table); return -1; } if (ctx->keywords & LK_KEYWORD_ALTISMETA) { unsigned int alttable = k_table | M_ALT; int type = KTYP(keycode); int val = KVAL(keycode); if (alttable != k_table && lk_map_exists(ctx, alttable) && !lk_key_exists(ctx, alttable, k_index) && (type == KT_LATIN || type == KT_LETTER) && val < 128) { if (lk_add_key(ctx, alttable, k_index, K(KT_META, val)) < 0) return -1; } } return 0; }
static DFBInputDeviceKeyIdentifier keyboard_get_identifier( int code, unsigned short value ) { unsigned char type = KTYP(value); unsigned char index = KVAL(value); if (type == KT_PAD) { if (index <= 9) return DIKI_KP_0 + index; switch (value) { case K_PSLASH: return DIKI_KP_DIV; case K_PSTAR: return DIKI_KP_MULT; case K_PMINUS: return DIKI_KP_MINUS; case K_PPLUS: return DIKI_KP_PLUS; case K_PENTER: return DIKI_KP_ENTER; case K_PCOMMA: case K_PDOT: return DIKI_KP_DECIMAL; } } /* Looks like a hack, but don't know a better way yet. */ switch (code) { case 12: return DIKI_MINUS_SIGN; case 13: return DIKI_EQUALS_SIGN; case 26: return DIKI_BRACKET_LEFT; case 27: return DIKI_BRACKET_RIGHT; case 39: return DIKI_SEMICOLON; case 40: return DIKI_QUOTE_RIGHT; case 41: return DIKI_QUOTE_LEFT; case 43: return DIKI_BACKSLASH; case 51: return DIKI_COMMA; case 52: return DIKI_PERIOD; case 53: return DIKI_SLASH; case 54: return DIKI_SHIFT_R; case 97: return DIKI_CONTROL_R; case 100: return DIKI_ALT_R; default: ; } /* special keys not in the map, hack? */ if (code == 124) /* keypad equal key */ return DIKI_KP_EQUAL; if (code == 125) /* left windows key */ return DIKI_META_L; if (code == 126) /* right windows key */ return DIKI_META_R; if (code == 127) /* context menu key */ return DIKI_SUPER_R; return DIKI_UNKNOWN; }
/* * Fetch one entry from the kernel keymap. */ static DFBResult driver_get_keymap_entry( CoreInputDevice *device, void *driver_data, DFBInputDeviceKeymapEntry *entry ) { int code = entry->code; unsigned short value; DFBInputDeviceKeyIdentifier identifier; /* fetch the base level */ value = keyboard_read_value( driver_data, K_NORMTAB, code ); /* get the identifier for basic mapping */ identifier = keyboard_get_identifier( code, value ); /* is CapsLock effective? */ if (KTYP(value) == KT_LETTER) entry->locks |= DILS_CAPS; /* is NumLock effective? */ if (identifier >= DIKI_KP_DECIMAL && identifier <= DIKI_KP_9) entry->locks |= DILS_NUM; /* write identifier to entry */ entry->identifier = identifier; /* write base level symbol to entry */ entry->symbols[DIKSI_BASE] = keyboard_get_symbol( code, value, DIKSI_BASE ); /* fetch the shifted base level */ value = keyboard_read_value( driver_data, K_SHIFTTAB, entry->code ); /* write shifted base level symbol to entry */ entry->symbols[DIKSI_BASE_SHIFT] = keyboard_get_symbol( code, value, DIKSI_BASE_SHIFT ); /* fetch the alternative level */ value = keyboard_read_value( driver_data, K_ALTTAB, entry->code ); /* write alternative level symbol to entry */ entry->symbols[DIKSI_ALT] = keyboard_get_symbol( code, value, DIKSI_ALT ); /* fetch the shifted alternative level */ value = keyboard_read_value( driver_data, K_ALTSHIFTTAB, entry->code ); /* write shifted alternative level symbol to entry */ entry->symbols[DIKSI_ALT_SHIFT] = keyboard_get_symbol( code, value, DIKSI_ALT_SHIFT ); return DFB_OK; }
/* * Generate ascii -> ebcdic translation table from kbd_data. */ void kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc) { unsigned short *keymap, keysym; int i, j, k; memset(ascebc, 0x40, 256); for (i = 0; i < ARRAY_SIZE(key_maps); i++) { keymap = kbd->key_maps[i]; if (!keymap) continue; for (j = 0; j < NR_KEYS; j++) { k = ((i & 1) << 7) + j; keysym = keymap[j]; if (KTYP(keysym) == (KT_LATIN | 0xf0) || KTYP(keysym) == (KT_LETTER | 0xf0)) ascebc[KVAL(keysym)] = k; else if (KTYP(keysym) == (KT_DEAD | 0xf0)) ascebc[ret_diacr[KVAL(keysym)]] = k; } } }
/* * Generate ebcdic -> ascii translation table from kbd_data. */ void kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) { unsigned short *keymap, keysym; int i, j, k; memset(ebcasc, ' ', 256); for (i = 0; i < ARRAY_SIZE(key_maps); i++) { keymap = kbd->key_maps[i]; if (!keymap) continue; for (j = 0; j < NR_KEYS; j++) { keysym = keymap[j]; k = ((i & 1) << 7) + j; if (KTYP(keysym) == (KT_LATIN | 0xf0) || KTYP(keysym) == (KT_LETTER | 0xf0)) ebcasc[k] = KVAL(keysym); else if (KTYP(keysym) == (KT_DEAD | 0xf0)) ebcasc[k] = ret_diacr[KVAL(keysym)]; } } }
static int do_constant_key(struct lk_ctx *ctx, int i, unsigned short key) { int typ, val; unsigned int j; typ = KTYP(key); val = KVAL(key); if ((typ == KT_LATIN || typ == KT_LETTER) && ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z'))) { unsigned short defs[16]; defs[0] = K(KT_LETTER, val); defs[1] = K(KT_LETTER, val ^ 32); defs[2] = defs[0]; defs[3] = defs[1]; for (j = 4; j < 8; j++) defs[j] = K(KT_LATIN, val & ~96); for (j = 8; j < 16; j++) defs[j] = K(KT_META, KVAL(defs[j - 8])); for (j = 0; j < ctx->keymap->total; j++) { if (!lk_map_exists(ctx, j)) continue; if (j > 0 && lk_key_exists(ctx, j, i)) continue; if (lk_add_key(ctx, j, i, defs[j % 16]) < 0) return -1; } } else { /* do this also for keys like Escape, as promised in the man page */ for (j = 1; j < ctx->keymap->total; j++) { if (!lk_map_exists(ctx, j)) continue; if (lk_key_exists(ctx, j, i)) continue; if (lk_add_key(ctx, j, i, key) < 0) return -1; } } return 0; }
dword TranslateUnicode(dword keycode) { int m = 0; if(modkeys & KMOD_SHIFT) m |= (1<<KG_SHIFT); if(modkeys & KMOD_CTRL) m |= (1<<KG_CTRL); if(modkeys & KMOD_LALT) m |= (1<<KG_ALT); if(modkeys & KMOD_RALT) m |= (1<<KG_ALTGR); //CAPS changes shift meaning in both directions if((modkeys & KMOD_CAPS) && KTYP(kmap[m][keycode]) == KT_LETTER ) m ^= (1<<KG_SHIFT); //num pad handling stays same so far if((modkeys & KMOD_NUM) && KTYP(kmap[m][keycode]) == KT_PAD ) return KVAL(kmap[m][keycode]); else return KVAL(kmap[m][keycode]); }
void handle_scancode(unsigned char scancode, int down) { unsigned char keycode; char up_flag = down ? 0 : 0200; /* * Convert scancode to keycode */ if (!kbd_translate(scancode, &keycode)) goto out; /* * Repeat a key only if the input buffers are empty or the * characters get echoed locally. This makes key repeat usable * with slow applications and under heavy loads. */ if (1) { u_short keysym; u_char type; ushort *key_map = key_maps[shift_state]; if (key_map != NULL) { keysym = key_map[keycode]; type = KTYP(keysym); // printf("keycode = %d\n",keycode); // printf("[kbd] keysym %x\n", keysym); if (type >= 0xf0) { type -= 0xf0; if (type == KT_LETTER) { type = KT_LATIN; } if (*key_handler[type]) { (*key_handler[type]) (keysym & 0xff, up_flag); } } } } out:; }
/* called after returning from RAW mode or when changing consoles - recompute k_down[] and shift_state from key_down[] */ void compute_shiftstate(void) { int i, j, k, sym, val; shift_state = 0; for(i=0; i < SIZE(k_down); i++) k_down[i] = 0; for(i=0; i < SIZE(key_down); i++) if(key_down[i]) { /* skip this word if not a single bit on */ k = (i<<5); for(j=0; j<32; j++,k++) if(test_bit(k, key_down)) { sym = key_map[0][k]; if(KTYP(sym) == KT_SHIFT) { val = KVAL(sym); k_down[val]++; shift_state |= (1<<val); } } } }
unsigned short keypad_keysym_redirect(unsigned short keysym) { if (applic_keypad || KTYP(keysym) != KT_PAD || KVAL(keysym) >= NR_PAD) return keysym; #define KL(val) K(KT_LATIN, val) static const unsigned short num_map[] = { KL('0'), KL('1'), KL('2'), KL('3'), KL('4'), KL('5'), KL('6'), KL('7'), KL('8'), KL('9'), KL('+'), KL('-'), KL('*'), KL('/'), K_ENTER, KL(','), KL('.'), KL('?'), KL('('), KL(')'), KL('#') }; static const unsigned short fn_map[] = { K_INSERT, K_SELECT, K_DOWN, K_PGDN, K_LEFT, K_P5, K_RIGHT, K_FIND, K_UP, K_PGUP, KL('+'), KL('-'), KL('*'), KL('/'), K_ENTER, K_REMOVE, K_REMOVE, KL('?'), KL('('), KL(')'), KL('#') }; if (lock_state & K_NUMLOCK) return num_map[keysym - K_P0]; return fn_map[keysym - K_P0]; }
/* maybe called when keymap is undefined, so that shiftkey release is seen */ void sun_compute_shiftstate(void) { int i, j, k, sym, val; shift_state = 0; for(i=0; i < SIZE(k_down); i++) k_down[i] = 0; for(i=0; i < SIZE(key_down); i++) if(key_down[i]) { /* skip this word if not a single bit on */ k = i*BITS_PER_LONG; for(j=0; j<BITS_PER_LONG; j++,k++) if(test_bit(k, key_down)) { sym = U(plain_map[k]); if(KTYP(sym) == KT_SHIFT) { val = KVAL(sym); if (val == KVAL(K_CAPSSHIFT)) val = KVAL(K_SHIFT); k_down[val]++; shift_state |= (1<<val); } } } }
MMSKeySymbol MMSInputLISThread::getSymbol(int code, unsigned short value) { unsigned char type = KTYP(value); unsigned char index = KVAL(value); TRACEOUT("MMSINPUT", "KEYCODE: TYPE=%d(0x%x), INDEX=%d(0x%x), value=%d(0x%x)", type, type, index, index, value, value); switch (type) { case KT_FN: if (index < 12) return (MMSKeySymbol)(MMSKEY_F1 + index); break; case KT_LETTER: case KT_LATIN: switch (index) { case 0x1c: return MMSKEY_PRINT; case 0x7f: return MMSKEY_BACKSPACE; case 0x08: return MMSKEY_BACKSPACE; case 0x09: return MMSKEY_TAB; case 0x0d: return MMSKEY_RETURN; case 0x18: return MMSKEY_CANCEL; case 0x1b: return MMSKEY_ESCAPE; case 0x20: return MMSKEY_SPACE; case 0x21: return MMSKEY_EXCLAMATION_MARK; case 0x22: return MMSKEY_QUOTATION; case 0x23: return MMSKEY_NUMBER_SIGN; case 0x24: return MMSKEY_DOLLAR_SIGN; case 0x25: return MMSKEY_PERCENT_SIGN; case 0x26: return MMSKEY_AMPERSAND; case 0x27: return MMSKEY_APOSTROPHE; case 0x28: return MMSKEY_PARENTHESIS_LEFT; case 0x29: return MMSKEY_PARENTHESIS_RIGHT; case 0x2a: return MMSKEY_ASTERISK; case 0x2b: return MMSKEY_PLUS_SIGN; case 0x2c: return MMSKEY_COMMA; case 0x2d: return MMSKEY_MINUS_SIGN; case 0x2e: return MMSKEY_PERIOD; case 0x2f: return MMSKEY_SLASH; case 0x30: return MMSKEY_0; case 0x31: return MMSKEY_1; case 0x32: return MMSKEY_2; case 0x33: return MMSKEY_3; case 0x34: return MMSKEY_4; case 0x35: return MMSKEY_5; case 0x36: return MMSKEY_6; case 0x37: return MMSKEY_7; case 0x38: return MMSKEY_8; case 0x39: return MMSKEY_9; case 0x3a: return MMSKEY_COLON; case 0x3b: return MMSKEY_SEMICOLON; case 0x3c: return MMSKEY_LESS_THAN_SIGN; case 0x3d: return MMSKEY_EQUALS_SIGN; case 0x3e: return MMSKEY_GREATER_THAN_SIGN; case 0x3f: return MMSKEY_QUESTION_MARK; case 0x40: return MMSKEY_AT; case 0x41: return MMSKEY_CAPITAL_A; case 0x42: return MMSKEY_CAPITAL_B; case 0x43: return MMSKEY_CAPITAL_C; case 0x44: return MMSKEY_CAPITAL_D; case 0x45: return MMSKEY_CAPITAL_E; case 0x46: return MMSKEY_CAPITAL_F; case 0x47: return MMSKEY_CAPITAL_G; case 0x48: return MMSKEY_CAPITAL_H; case 0x49: return MMSKEY_CAPITAL_I; case 0x4a: return MMSKEY_CAPITAL_J; case 0x4b: return MMSKEY_CAPITAL_K; case 0x4c: return MMSKEY_CAPITAL_L; case 0x4d: return MMSKEY_CAPITAL_M; case 0x4e: return MMSKEY_CAPITAL_N; case 0x4f: return MMSKEY_CAPITAL_O; case 0x50: return MMSKEY_CAPITAL_P; case 0x51: return MMSKEY_CAPITAL_Q; case 0x52: return MMSKEY_CAPITAL_R; case 0x53: return MMSKEY_CAPITAL_S; case 0x54: return MMSKEY_CAPITAL_T; case 0x55: return MMSKEY_CAPITAL_U; case 0x56: return MMSKEY_CAPITAL_V; case 0x57: return MMSKEY_CAPITAL_W; case 0x58: return MMSKEY_CAPITAL_X; case 0x59: return MMSKEY_CAPITAL_Y; case 0x5a: return MMSKEY_CAPITAL_Z; case 0x5b: return MMSKEY_SQUARE_BRACKET_LEFT; case 0x5c: return MMSKEY_BACKSLASH; case 0x5d: return MMSKEY_SQUARE_BRACKET_RIGHT; case 0x5e: return MMSKEY_CIRCUMFLEX_ACCENT; case 0x5f: return MMSKEY_UNDERSCORE; case 0x60: return MMSKEY_GRAVE_ACCENT; case 0x61: return MMSKEY_SMALL_A; case 0x62: return MMSKEY_SMALL_B; case 0x63: return MMSKEY_SMALL_C; case 0x64: return MMSKEY_SMALL_D; case 0x65: return MMSKEY_SMALL_E; case 0x66: return MMSKEY_SMALL_F; case 0x67: return MMSKEY_SMALL_G; case 0x68: return MMSKEY_SMALL_H; case 0x69: return MMSKEY_SMALL_I; case 0x6a: return MMSKEY_SMALL_J; case 0x6b: return MMSKEY_SMALL_K; case 0x6c: return MMSKEY_SMALL_L; case 0x6d: return MMSKEY_SMALL_M; case 0x6e: return MMSKEY_SMALL_N; case 0x6f: return MMSKEY_SMALL_O; case 0x70: return MMSKEY_SMALL_P; case 0x71: return MMSKEY_SMALL_Q; case 0x72: return MMSKEY_SMALL_R; case 0x73: return MMSKEY_SMALL_S; case 0x74: return MMSKEY_SMALL_T; case 0x75: return MMSKEY_SMALL_U; case 0x76: return MMSKEY_SMALL_V; case 0x77: return MMSKEY_SMALL_W; case 0x78: return MMSKEY_SMALL_X; case 0x79: return MMSKEY_SMALL_Y; case 0x7a: return MMSKEY_SMALL_Z; case 0x7b: return MMSKEY_CURLY_BRACKET_LEFT; case 0x7c: return MMSKEY_VERTICAL_BAR; case 0x7d: return MMSKEY_CURLY_BRACKET_RIGHT; case 0x7e: return MMSKEY_TILDE; default: return MMSKEY_UNKNOWN; } break; case KT_PAD: switch (value) { case K_P0: return MMSKEY_0; case K_P1: return MMSKEY_1; case K_P2: return MMSKEY_2; case K_P3: return MMSKEY_3; case K_P4: return MMSKEY_4; case K_P5: return MMSKEY_5; case K_P6: return MMSKEY_6; case K_P7: return MMSKEY_7; case K_P8: return MMSKEY_8; case K_P9: return MMSKEY_9; case K_PPLUS: return MMSKEY_PLUS_SIGN; case K_PMINUS: return MMSKEY_MINUS_SIGN; case K_PSTAR: return MMSKEY_ASTERISK; case K_PSLASH: return MMSKEY_SLASH; case K_PENTER: return MMSKEY_RETURN; case K_PCOMMA: return MMSKEY_COMMA; case K_PDOT: return MMSKEY_PERIOD; case K_PPARENL: return MMSKEY_PARENTHESIS_LEFT; case K_PPARENR: return MMSKEY_PARENTHESIS_RIGHT; default: return MMSKEY_UNKNOWN; } break; } switch (value) { case K_LEFT: return MMSKEY_CURSOR_LEFT; case K_RIGHT: return MMSKEY_CURSOR_RIGHT; case K_UP: return MMSKEY_CURSOR_UP; case K_DOWN: return MMSKEY_CURSOR_DOWN; case K_ENTER: return MMSKEY_RETURN; case K_CTRL: return MMSKEY_CONTROL; case K_SHIFT: return MMSKEY_SHIFT; case K_ALT: return MMSKEY_ALT; case K_ALTGR: return MMSKEY_ALTGR; case K_INSERT: return MMSKEY_INSERT; case K_REMOVE: return MMSKEY_DELETE; case K_FIND: return MMSKEY_HOME; case K_SELECT: return MMSKEY_END; case K_PGUP: return MMSKEY_PAGE_UP; case K_PGDN: return MMSKEY_PAGE_DOWN; case K_NUM: return MMSKEY_NUM_LOCK; case K_HOLD: return MMSKEY_SCROLL_LOCK; case K_PAUSE: return MMSKEY_PAUSE; case K_BREAK: return MMSKEY_BREAK; case K_CAPS: return MMSKEY_CAPS_LOCK; case K_P0: return MMSKEY_INSERT; case K_P1: return MMSKEY_END; case K_P2: return MMSKEY_CURSOR_DOWN; case K_P3: return MMSKEY_PAGE_DOWN; case K_P4: return MMSKEY_CURSOR_LEFT; case K_P5: return MMSKEY_BEGIN; case K_P6: return MMSKEY_CURSOR_RIGHT; case K_P7: return MMSKEY_HOME; case K_P8: return MMSKEY_CURSOR_UP; case K_P9: return MMSKEY_PAGE_UP; case K_PPLUS: return MMSKEY_PLUS_SIGN; case K_PMINUS: return MMSKEY_MINUS_SIGN; case K_PSTAR: return MMSKEY_ASTERISK; case K_PSLASH: return MMSKEY_SLASH; case K_PENTER: return MMSKEY_RETURN; case K_PCOMMA: return MMSKEY_COMMA; case K_PDOT: return MMSKEY_PERIOD; case K_PPARENL: return MMSKEY_PARENTHESIS_LEFT; case K_PPARENR: return MMSKEY_PARENTHESIS_RIGHT; } return MMSKEY_UNKNOWN; }
static uint8_t process_keyboard(inode_t* inode, struct tty_context* tio, int fd, int* pos) { keyboard_t k; if(sys_read(fd, &k, sizeof(keyboard_t)) == 0) { errno = EIO; return 0; } switch(k.vkey) { case KEY_LEFTALT: tty_keys = !!(k.down) ? tty_keys | K_ALT : tty_keys & ~K_ALT; return 0; case KEY_RIGHTALT: tty_keys = !!(k.down) ? tty_keys | K_ALTGR : tty_keys & ~K_ALTGR; return 0; case KEY_LEFTSHIFT: case KEY_RIGHTSHIFT: tty_keys = !!(k.down) ? tty_keys | K_SHIFT : tty_keys & ~K_SHIFT; return 0; case KEY_LEFTCTRL: case KEY_RIGHTCTRL: tty_keys = !!(k.down) ? tty_keys | K_CTRL : tty_keys & ~K_CTRL; return 0; case KEY_CAPSLOCK: tty_capslock = !(k.down) ? tty_capslock : !tty_capslock; return 0; default: break; } if(!k.down) return 0; int16_t key; uint8_t ch; switch(tty_keys) { #define _(x, y) \ case x : { key = tty_keymap.y[k.vkey] & 0x0FFF; break; } _(0, plain); _(K_SHIFT, shift); _(K_ALTGR, altgr); _(K_SHIFT | K_ALTGR, shift_altgr); _(K_CTRL, ctrl); _(K_SHIFT | K_CTRL, shift_ctrl); _(K_ALTGR | K_CTRL, altgr_ctrl); _(K_ALTGR | K_SHIFT | K_CTRL, altgr_shift_ctrl); _(K_ALT, alt); _(K_SHIFT | K_ALT, shift_alt); _(K_ALTGR | K_ALT, altgr_alt); _(K_ALTGR | K_SHIFT | K_ALT, altgr_shift_alt); _(K_CTRL | K_ALT, ctrl_alt); _(K_SHIFT | K_CTRL | K_ALT, shift_ctrl_alt); _(K_ALTGR | K_CTRL | K_ALT, altgr_ctrl_alt); _(K_ALTGR | K_SHIFT | K_CTRL | K_ALT, altgr_shift_ctrl_alt); default: key = 0; break; #undef _ } ch = KVAL(key); switch(KTYP(key)) { case KT_LATIN: case KT_LETTER: if(tty_capslock) { if(tty_keys & K_SHIFT) ch += ch >= 'A' && ch <= 'z' ? 32 : 0; else ch -= ch >= 'a' && ch <= 'Z' ? 32 : 0; } case KT_ASCII: break; case KT_SPEC: case KT_PAD: if(!__kmap[KTYP(key)] || !__kmap[KTYP(key)][KVAL(key)]) return 0; ch = __kmap[KTYP(key)][KVAL(key)][0]; break; default: if(!__kmap[KTYP(key)] || !__kmap[KTYP(key)][KVAL(key)]) return 0; fifo_write(&tio->in, __kmap[KTYP(key)][KVAL(key)], strlen(__kmap[KTYP(key)][KVAL(key)])); *pos = *pos + strlen(__kmap[KTYP(key)][KVAL(key)]); if(tio->ios.c_lflag & ECHO) tty_output_write(inode, __kmap[KTYP(key)][KVAL(key)], 0, strlen(__kmap[KTYP(key)][KVAL(key)])); return 0; } return ch; }
static void readKernelMapping(KeySymsPtr pKeySyms, CARD8 *pModMap) { KeySym *k; int i; static unsigned char tbl[GLYPHS_PER_KEY] = { 0, /* unshifted */ 1, /* shifted */ 0, /* modeswitch unshifted */ 0 /* modeswitch shifted */ }; /* * Read the mapping from the kernel. * Since we're still using the XFree86 scancode->AT keycode mapping * routines, we need to convert the AT keycodes to Linux keycodes, * then translate the Linux keysyms into X keysyms. * * First, figure out which tables to use for the modeswitch columns * above, from the XF86Config fields. */ if (xf86Info.specialKeyMap[K_INDEX_RIGHTCTL] == KM_MODESHIFT || xf86Info.specialKeyMap[K_INDEX_RIGHTCTL] == KM_MODELOCK) tbl[2] = 4; /* control */ else if (xf86Info.specialKeyMap[K_INDEX_RIGHTALT] == KM_MODESHIFT || xf86Info.specialKeyMap[K_INDEX_RIGHTALT] == KM_MODELOCK) tbl[2] = 2; /* AltGr */ else tbl[2] = 8; /* alt */ tbl[3] = tbl[2] | 1; #ifndef ASSUME_CUSTOM_KEYCODES for (i = 0, k = map+GLYPHS_PER_KEY; i < NUM_AT2LNX; ++i) #else /* !ASSUME_CUSTOM_KEYCODES */ for (i = 0, k = map; i < NUM_AT2LNX; ++i) #endif /* !ASSUME_CUSTOM_KEYCODES */ { struct kbentry kbe; int j; #ifndef ASSUME_CUSTOM_KEYCODES kbe.kb_index = at2lnx[i]; #else /* !ASSUME_CUSTOM_KEYCODES */ kbe.kb_index = i; #endif /* !ASSUME_CUSTOM_KEYCODES */ for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { unsigned short kval; *k = NoSymbol; kbe.kb_table = tbl[j]; if ( #ifndef ASSUME_CUSTOM_KEYCODES kbe.kb_index == 0 || #endif /* !ASSUME_CUSTOM_KEYCODES */ ioctl(xf86Info.consoleFd, KDGKBENT, &kbe)) continue; kval = KVAL(kbe.kb_value); switch (KTYP(kbe.kb_value)) { case KT_LATIN: case KT_LETTER: *k = linux_to_x[kval]; break; case KT_FN: if (kval <= 19) *k = XK_F1 + kval; else switch (kbe.kb_value) { case K_FIND: *k = XK_Home; /* or XK_Find */ break; case K_INSERT: *k = XK_Insert; break; case K_REMOVE: *k = XK_Delete; break; case K_SELECT: *k = XK_End; /* or XK_Select */ break; case K_PGUP: *k = XK_Prior; break; case K_PGDN: *k = XK_Next; break; case K_HELP: *k = XK_Help; break; case K_DO: *k = XK_Execute; break; case K_PAUSE: *k = XK_Pause; break; case K_MACRO: *k = XK_Menu; break; default: break; } break; case KT_SPEC: switch (kbe.kb_value) { case K_ENTER: *k = XK_Return; break; case K_BREAK: *k = XK_Break; break; case K_CAPS: *k = XK_Caps_Lock; break; case K_NUM: *k = XK_Num_Lock; break; case K_HOLD: *k = XK_Scroll_Lock; break; case K_COMPOSE: *k = XK_Multi_key; break; default: break; } break; case KT_PAD: switch (kbe.kb_value) { case K_PPLUS: *k = XK_KP_Add; break; case K_PMINUS: *k = XK_KP_Subtract; break; case K_PSTAR: *k = XK_KP_Multiply; break; case K_PSLASH: *k = XK_KP_Divide; break; case K_PENTER: *k = XK_KP_Enter; break; case K_PCOMMA: *k = XK_KP_Separator; break; case K_PDOT: *k = XK_KP_Decimal; break; case K_PPLUSMINUS: *k = XK_KP_Subtract; break; default: if (kval <= 9) *k = XK_KP_0 + kval; break; } break; /* * KT_DEAD keys are for accelerated diacritical creation. */ case KT_DEAD: switch (kbe.kb_value) { case K_DGRAVE: *k = XK_dead_grave; break; case K_DACUTE: *k = XK_dead_acute; break; case K_DCIRCM: *k = XK_dead_circumflex; break; case K_DTILDE: *k = XK_dead_tilde; break; case K_DDIERE: *k = XK_dead_diaeresis; break; } break; case KT_CUR: switch (kbe.kb_value) { case K_DOWN: *k = XK_Down; break; case K_LEFT: *k = XK_Left; break; case K_RIGHT: *k = XK_Right; break; case K_UP: *k = XK_Up; break; } break; case KT_SHIFT: switch (kbe.kb_value) { case K_ALTGR: *k = XK_Alt_R; break; case K_ALT: *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); break; case K_CTRL: *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); break; case K_CTRLL: *k = XK_Control_L; break; case K_CTRLR: *k = XK_Control_R; break; case K_SHIFT: *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); break; case K_SHIFTL: *k = XK_Shift_L; break; case K_SHIFTR: *k = XK_Shift_R; break; default: break; } break; /* * KT_ASCII keys accumulate a 3 digit decimal number that gets * emitted when the shift state changes. We can't emulate that. */ case KT_ASCII: break; case KT_LOCK: if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock; break; default: break; } } if (k[-1] == k[-2]) k[-1] = NoSymbol; if (k[-2] == k[-3]) k[-2] = NoSymbol; if (k[-3] == k[-4]) k[-3] = NoSymbol; if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol; if (k[-1] == k[-4] && k[-2] == k[-3] && k[-2] == NoSymbol) k[-1] =NoSymbol; } #ifdef ASSUME_CUSTOM_KEYCODES /* * Find the Mapping for the special server functions */ for (i = 0; i < NR_KEYS; ++i) { struct kbentry kbe; int special = 0; kbe.kb_index = i; kbe.kb_table = 0; /* Plain map */ if (!ioctl(xf86Info.consoleFd, KDGKBENT, &kbe)) switch (kbe.kb_value) { case K(KT_LATIN,0x7f): /* This catches DEL too... But who cares? */ special = KEY_BackSpace; break; case K_PMINUS: special = KEY_KP_Minus; break; case K_PPLUS: special = KEY_KP_Plus; break; case K_F1: special = KEY_F1; break; case K_F2: special = KEY_F2; break; case K_F3: special = KEY_F3; break; case K_F4: special = KEY_F4; break; case K_F5: special = KEY_F5; break; case K_F6: special = KEY_F6; break; case K_F7: special = KEY_F7; break; case K_F8: special = KEY_F8; break; case K_F9: special = KEY_F9; break; case K_F10: special = KEY_F10; break; case K_F11: special = KEY_F11; break; case K_F12: special = KEY_F12; break; case K_ALT: special = KEY_Alt; break; case K_ALTGR: special = KEY_AltLang; break; case K_CONS: special = KEY_SysReqest; break; } SpecialServerMap[i] = special; } #endif /* ASSUME_CUSTOM_KEYCODES */ }
static inline gii_event_mask GII_keyboard_handle_data(gii_input *inp, int code) { linkbd_priv *priv = LINKBD_PRIV(inp); gii_event ev; struct kbentry entry; int symval, labelval; gii_event_mask mask; _giiEventBlank(&ev, sizeof(gii_key_event)); if (code & 0x80) { code &= 0x7f; ev.key.type = evKeyRelease; priv->keydown_buf[code] = 0; } else if (priv->keydown_buf[code] == 0) { ev.key.type = evKeyPress; priv->keydown_buf[code] = 1; } else { ev.key.type = evKeyRepeat; } ev.key.button = code; /* First update modifiers here so linkey.c can use the value */ ev.key.modifiers = priv->modifiers; if (ev.key.type == evKeyRelease && GII_KTYP(priv->keydown_sym[code]) != GII_KT_MOD && priv->keydown_sym[code] != GIIK_VOID) { /* We can use the cached values */ ev.key.sym = priv->keydown_sym[code]; ev.key.label = priv->keydown_label[code]; } else { /* Temporarily switch back to the old mode because unicodes aren't available through table lookup in MEDIUMRAW */ if (ioctl(priv->fd, KDSKBMODE, priv->old_mode) < 0) { DPRINT_MISC("Linux-kbd: ioctl(KDSKBMODE) failed.\n"); return 0; } /* Look up the keysym without modifiers, which will give us * the key label (more or less). */ entry.kb_table = 0; entry.kb_index = code; if (ioctl(priv->fd, KDGKBENT, &entry) < 0) { DPRINT_MISC("Linux-kbd: ioctl(KDGKBENT) failed.\n"); return 0; } labelval = entry.kb_value; if (priv->old_mode == K_UNICODE) labelval &= 0x0fff; /* Now look up the full keysym in the kernel's table */ /* calculate kernel-like shift value */ entry.kb_table = ((priv->modifiers & GII_MOD_SHIFT) ? (1<<KG_SHIFT) : 0) | ((priv->modifiers & GII_MOD_CTRL) ? (1<<KG_CTRL) : 0) | ((priv->modifiers & GII_MOD_ALT) ? (1<<KG_ALT) : 0) | ((priv->modifiers & GII_MOD_ALTGR) ? (1<<KG_ALTGR) : 0) | ((priv->modifiers & GII_MOD_META) ? (1<<KG_ALT) : 0) | ((priv->modifiers & GII_MOD_CAPS) ? (1<<KG_CAPSSHIFT) : 0); entry.kb_index = code; if (ioctl(priv->fd, KDGKBENT, &entry) < 0) { DPRINT_MISC("Linux-kbd: ioctl(KDGKBENT) failed.\n"); return 0; } /* Switch back to MEDIUMRAW */ if (ioctl(priv->fd, KDSKBMODE, K_MEDIUMRAW) < 0) { DPRINT_MISC("Linux-kbd: ioctl(KDSKBMODE) failed.\n"); return 0; } switch (entry.kb_value) { case K_HOLE: DPRINT_EVENTS("Linux-kbd: NOSUCHKEY\n"); break; case K_NOSUCHMAP: DPRINT_EVENTS("Linux-kbd: NOSUCHMAP\n"); entry.kb_value = K_HOLE; break; } symval = entry.kb_value; if (priv->old_mode == K_UNICODE) symval &= 0x0fff; _gii_linkey_trans(code, labelval, symval, &ev.key); if (ev.key.type == evKeyPress) { if (priv->accent) { if (GII_KTYP(ev.key.sym) != GII_KT_MOD) { handle_accent(priv, symval, &ev); } } else if (KTYP(symval) == KT_DEAD) { priv->accent = GII_KVAL(ev.key.sym); } } if (GII_KTYP(ev.key.sym) == GII_KT_DEAD) { ev.key.sym = GIIK_VOID; } } /* Keep track of modifier state */ if (GII_KTYP(ev.key.label) == GII_KT_MOD) { /* Modifers don't repeat */ if (ev.key.type == evKeyRepeat) return 0; handle_modifier(priv, &ev); } /* Now update modifiers again to get the value _after_ the current event */ ev.key.modifiers = priv->modifiers; if (ev.any.type == evKeyPress) { priv->keydown_sym[code] = ev.key.sym; priv->keydown_label[code] = ev.key.label; } DPRINT_EVENTS("KEY-%s button=0x%02x modifiers=0x%02x " "sym=0x%04x label=0x%04x\n", (ev.key.type == evKeyRelease) ? "UP" : ((ev.key.type == evKeyPress) ? "DN" : "RP"), ev.key.button, ev.key.modifiers, ev.key.sym, ev.key.label); if (priv->call_vtswitch) { if (ev.key.label == GIIK_CtrlL && priv->needctrl2switch) { if (ev.key.type == evKeyRelease) { priv->ctrlstate = 0; } else if (ev.key.type == evKeyPress) { priv->ctrlstate = 1; } } /* Check for console switch. Unfortunately, the kernel doesn't * recognize KT_CONS when the keyboard is in RAW or MEDIUMRAW * mode, so _we_ have to. Sigh. */ if ((ev.key.type == evKeyPress) && (KTYP(entry.kb_value) == KT_CONS) && priv->ctrlstate) { int rc; int new_cons = 1+KVAL(entry.kb_value); /* Clear the keydown buffer, since we'll never know what keys the user pressed (or released) while they were away. */ DPRINT_MISC("Flushing all keys.\n"); rc = GII_keyboard_flush_keys(inp); DPRINT_MISC("Switching to console %d.\n", new_cons); if (ioctl(priv->fd, VT_ACTIVATE, new_cons) < 0) { perror("ioctl(VT_ACTIVATE)"); } return rc; } } mask = (1 << ev.any.type); if (! (inp->curreventmask & mask)) return 0; /* finally queue the key event */ ev.any.size = sizeof(gii_key_event); ev.any.origin = inp->origin; _giiEvQueueAdd(inp, &ev); return (1 << ev.any.type); }
static void keyboard_interrupt(int int_pt_regs) { unsigned char scancode; static unsigned int prev_scancode = 0; /* remember E0, E1 */ char up_flag; /* 0 or 0200 */ char raw_mode; pt_regs = (struct pt_regs *) int_pt_regs; send_cmd(0xAD); /* disable keyboard */ kb_wait(); if ((inb_p(0x64) & kbd_read_mask) != 0x01) goto end_kbd_intr; scancode = inb(0x60); mark_bh(KEYBOARD_BH); if (scancode == 0xfa) { acknowledge = 1; goto end_kbd_intr; } else if (scancode == 0xfe) { resend = 1; goto end_kbd_intr; } else if (scancode == 0) { #ifdef KBD_REPORT_ERR printk("keyboard buffer overflow\n"); #endif goto end_kbd_intr; } else if (scancode == 0xff) { #ifdef KBD_REPORT_ERR printk("keyboard error\n"); #endif prev_scancode = 0; goto end_kbd_intr; } tty = ttytab[fg_console]; kbd = kbd_table + fg_console; if ((raw_mode = vc_kbd_mode(kbd,VC_RAW))) { put_queue(scancode); /* we do not return yet, because we want to maintain the key_down array, so that we have the correct values when finishing RAW mode or when changing VT's */ } if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; goto end_kbd_intr; } /* * Convert scancode to keysym, using prev_scancode. */ up_flag = (scancode & 0200); scancode &= 0x7f; if (prev_scancode) { /* * usually it will be 0xe0, but a Pause key generates * e1 1d 45 e1 9d c5 when pressed, and nothing when released */ if (prev_scancode != 0xe0) { if (prev_scancode == 0xe1 && scancode == 0x1d) { prev_scancode = 0x100; goto end_kbd_intr; } else if (prev_scancode == 0x100 && scancode == 0x45) { scancode = E1_PAUSE; prev_scancode = 0; } else { printk("keyboard: unknown e1 escape sequence\n"); prev_scancode = 0; goto end_kbd_intr; } } else { prev_scancode = 0; /* * The keyboard maintains its own internal caps lock and * num lock statuses. In caps lock mode E0 AA precedes make * code and E0 2A follows break code. In num lock mode, * E0 2A precedes make code and E0 AA follows break code. * We do our own book-keeping, so we will just ignore these. */ /* * For my keyboard there is no caps lock mode, but there are * both Shift-L and Shift-R modes. The former mode generates * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. * So, we should also ignore the latter. - [email protected] */ if (scancode == 0x2a || scancode == 0x36) goto end_kbd_intr; if (e0_keys[scancode]) scancode = e0_keys[scancode]; else if (!raw_mode) { #ifdef KBD_REPORT_UNKN printk("keyboard: unknown scancode e0 %02x\n", scancode); #endif goto end_kbd_intr; } } } else if (scancode >= E0_BASE && !raw_mode) { #ifdef KBD_REPORT_UNKN printk("keyboard: scancode (%02x) not in range 00 - %2x\n", scancode, E0_BASE - 1); #endif goto end_kbd_intr; } /* * At this point the variable `scancode' contains the keysym. * We keep track of the up/down status of the key, and * return the keysym if in MEDIUMRAW mode. * (Note: earlier kernels had a bug and did not pass the up/down * bit to applications.) */ if (up_flag) { clear_bit(scancode, key_down); rep = 0; } else rep = set_bit(scancode, key_down); if (raw_mode) goto end_kbd_intr; if (vc_kbd_mode(kbd, VC_MEDIUMRAW)) { put_queue(scancode + up_flag); goto end_kbd_intr; } /* * Small change in philosophy: earlier we defined repetition by * rep = scancode == prev_keysym; * prev_keysym = scancode; * but now by the fact that the depressed key was down already. * Does this ever make a difference? */ /* * Repeat a key only if the input buffers are empty or the * characters get echoed locally. This makes key repeat usable * with slow applications and under heavy loads. */ if (!rep || (vc_kbd_mode(kbd,VC_REPEAT) && tty && (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { u_short key_code; u_char type; /* the XOR below used to be an OR */ int shift_final = shift_state ^ kbd->lockstate; key_code = key_map[shift_final][scancode]; type = KTYP(key_code); if (type == KT_LETTER) { type = KT_LATIN; if (vc_kbd_led(kbd,VC_CAPSLOCK)) key_code = key_map[shift_final ^ (1<<KG_SHIFT)][scancode]; } (*key_handler[type])(key_code & 0xff, up_flag); } end_kbd_intr: send_cmd(0xAE); /* enable keyboard */ }
static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) { u_char acia_stat; int scancode; int break_flag; /* save frame for register dump */ kbd_pt_regs = fp; repeat: if (acia.mid_ctrl & ACIA_IRQ) if (atari_MIDI_interrupt_hook) atari_MIDI_interrupt_hook(); acia_stat = acia.key_ctrl; /* check out if the interrupt came from this ACIA */ if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ)) return; if (acia_stat & ACIA_OVRN) { /* a very fast typist or a slow system, give a warning */ /* ...happens often if interrupts were disabled for too long */ printk( KERN_DEBUG "Keyboard overrun\n" ); scancode = acia.key_data; /* Turn off autorepeating in case a break code has been lost */ del_timer( &atakeyb_rep_timer ); rep_scancode = 0; if (ikbd_self_test) /* During self test, don't do resyncing, just process the code */ goto interpret_scancode; else if (IS_SYNC_CODE(scancode)) { /* This code seem already to be the start of a new packet or a * single scancode */ kb_state.state = KEYBOARD; goto interpret_scancode; } else { /* Go to RESYNC state and skip this byte */ kb_state.state = RESYNC; kb_state.len = 1; /* skip max. 1 another byte */ goto repeat; } } if (acia_stat & ACIA_RDRF) /* received a character */ { scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ mark_bh(KEYBOARD_BH); interpret_scancode: switch (kb_state.state) { case KEYBOARD: switch (scancode) { case 0xF7: kb_state.state = AMOUSE; kb_state.len = 0; break; case 0xF8: case 0xF9: case 0xFA: case 0xFB: kb_state.state = RMOUSE; kb_state.len = 1; kb_state.buf[0] = scancode; break; case 0xFC: kb_state.state = CLOCK; kb_state.len = 0; break; case 0xFE: case 0xFF: kb_state.state = JOYSTICK; kb_state.len = 1; kb_state.buf[0] = scancode; break; case 0xF1: /* during self-test, note that 0xf1 received */ if (ikbd_self_test) { ++ikbd_self_test; self_test_last_rcv = jiffies; break; } /* FALL THROUGH */ default: break_flag = scancode & BREAK_MASK; scancode &= ~BREAK_MASK; if (ikbd_self_test) { /* Scancodes sent during the self-test stand for broken * keys (keys being down). The code *should* be a break * code, but nevertheless some AT keyboard interfaces send * make codes instead. Therefore, simply ignore * break_flag... * */ int keyval = plain_map[scancode], keytyp; set_bit( scancode, broken_keys ); self_test_last_rcv = jiffies; keyval = plain_map[scancode]; keytyp = KTYP(keyval) - 0xf0; keyval = KVAL(keyval); printk( KERN_WARNING "Key with scancode %d ", scancode ); if (keytyp == KT_LATIN || keytyp == KT_LETTER) { if (keyval < ' ') printk( "('^%c') ", keyval + '@' ); else printk( "('%c') ", keyval ); } printk( "is broken -- will be ignored.\n" ); break; } else if (test_bit( scancode, broken_keys )) break; if (break_flag) { del_timer( &atakeyb_rep_timer ); rep_scancode = 0; } else { del_timer( &atakeyb_rep_timer ); rep_scancode = scancode; atakeyb_rep_timer.expires = jiffies + key_repeat_delay; atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL; add_timer( &atakeyb_rep_timer ); } handle_scancode(break_flag | scancode); break; } break; case AMOUSE: kb_state.buf[kb_state.len++] = scancode; if (kb_state.len == 5) { kb_state.state = KEYBOARD; /* not yet used */ /* wake up someone waiting for this */ } break; case RMOUSE: kb_state.buf[kb_state.len++] = scancode; if (kb_state.len == 3) { kb_state.state = KEYBOARD; if (atari_mouse_interrupt_hook) atari_mouse_interrupt_hook(kb_state.buf); } break; case JOYSTICK: kb_state.buf[1] = scancode; kb_state.state = KEYBOARD; atari_joystick_interrupt(kb_state.buf); break; case CLOCK: kb_state.buf[kb_state.len++] = scancode; if (kb_state.len == 6) { kb_state.state = KEYBOARD; /* wake up someone waiting for this. But will this ever be used, as Linux keeps its own time. Perhaps for synchronization purposes? */ /* wake_up_interruptible(&clock_wait); */ } break; case RESYNC: if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) { kb_state.state = KEYBOARD; goto interpret_scancode; } kb_state.len--; break; } } #if 0 if (acia_stat & ACIA_CTS) /* cannot happen */; #endif if (acia_stat & (ACIA_FE | ACIA_PE)) { printk("Error in keyboard communication\n"); } /* handle_scancode() can take a lot of time, so check again if * some character arrived */ goto repeat; }
/* this logic is pulled from kbd_keycode() in drivers/tty/vt/keyboard.c in the Linux kernel source */ static void SDL_EVDEV_do_text_input(unsigned short keycode) { char shift_state; int locks_state; struct kbentry kbe; unsigned char type; char text[2] = { 0 }; if (_this->console_fd < 0) return; shift_state = TIOCL_GETSHIFTSTATE; if (ioctl(_this->console_fd, TIOCLINUX, &shift_state) < 0) { /* TODO: error */ return; } kbe.kb_table = shift_state; kbe.kb_index = keycode; if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) { /* TODO: error */ return; } type = KTYP(kbe.kb_value); if (type < 0xf0) { /* * FIXME: keysyms with a type below 0xf0 represent a unicode character * which requires special handling due to dead characters, diacritics, * etc. For perfect input a proper way to deal with such characters * should be implemented. * * For reference, the only place I was able to find out about this * special 0xf0 value was in an unused? couple of patches listed below. * * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-keyboard.diff * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-console.diff */ return; } type -= 0xf0; /* if type is KT_LETTER then it can be affected by Caps Lock */ if (type == KT_LETTER) { type = KT_LATIN; if (ioctl(_this->console_fd, KDGKBLED, &locks_state) < 0) { /* TODO: error */ return; } if (locks_state & K_CAPSLOCK) { kbe.kb_table = shift_state ^ (1 << KG_SHIFT); if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) { /* TODO: error */ return; } } } /* TODO: convert values >= 0x80 from ISO-8859-1? to UTF-8 */ if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80) return; *text = KVAL(kbe.kb_value); SDL_SendKeyboardText(text); }
/* This is our keyboard 'interrupt' routine. * Must run under sunkbd_lock. */ static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs) { unsigned char keycode; char up_flag; /* 0 or SUNKBD_UBIT */ char raw_mode; if(ch == SKBD_RESET) { kbd_reset_pending = 1; goto out; } if(ch == SKBD_LYOUT) { kbd_layout_pending = 1; goto out; } if(kbd_reset_pending) { sunkbd_type = ch; kbd_reset_pending = 0; if(ch == SUNKBD_TYPE4) send_cmd(SKBDCMD_GLAYOUT); goto out; } else if(kbd_layout_pending) { sunkbd_layout = ch; kbd_layout_pending = 0; goto out; } else if(ch == SKBD_ALLUP) { del_timer (&auto_repeat_timer); memset(key_down, 0, sizeof(key_down)); sun_compute_shiftstate(); goto out; } #ifdef SKBD_DEBUG if(ch == 0x7f) printk("KBD<ALL KEYS UP>"); else printk("KBD<%x %s>", ch, ((ch&0x80) ? "UP" : "DOWN")); #endif /* Whee, a real character. */ if(regs) { pt_regs = regs; last_keycode = keycode = ch; } else { keycode = ch; } do_poke_blanked_console = 1; tasklet_schedule(&console_tasklet); add_keyboard_randomness(keycode); tty = ttytab? ttytab[fg_console]: NULL; if (tty && (!tty->driver_data)) { /* This is to workaround ugly bug in tty_io.c, which does not do locking when it should */ tty = NULL; } kbd = kbd_table + fg_console; if((raw_mode = (kbd->kbdmode == VC_RAW))) { if (kbd_redirected == fg_console+1) push_kbd (keycode); else put_queue(keycode); /* we do not return yet, because we want to maintain * the key_down array, so that we have the correct * values when finishing RAW mode or when changing VT's. */ } up_flag = (keycode & SUNKBD_UBIT); /* The 'up' bit */ keycode &= SUNKBD_KMASK; /* all the rest */ del_timer (&auto_repeat_timer); if(up_flag) { rep = 0; clear_bit(keycode, key_down); } else { if (!norepeat_keys[keycode]) { if (kbd_rate_ticks) { auto_repeat_timer.expires = jiffies + kbd_delay_ticks; add_timer (&auto_repeat_timer); } } rep = test_and_set_bit(keycode, key_down); } #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq hack */ if (l1a_state.l1_down) { if (!up_flag) handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, kbd, tty); goto out; } #endif if(raw_mode) goto out; if(kbd->kbdmode == VC_MEDIUMRAW) { put_queue(keycode + up_flag); goto out; } /* * Small change in philosophy: earlier we defined repetition by * rep = keycode == prev_keycode; * prev_keycode = keycode; * but now by the fact that the depressed key was down already. * Does this ever make a difference? Yes. */ /* * Repeat a key only if the input buffers are empty or the * characters get echoed locally. This makes key repeat usable * with slow applications and under heavy loads. */ if (!rep || (vc_kbd_mode(kbd,VC_REPEAT) && tty && (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { u_short keysym; u_char type; /* the XOR below used to be an OR */ int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; ushort *key_map = key_maps[shift_final]; if (key_map != NULL) { keysym = key_map[keycode]; type = KTYP(keysym); if (type >= 0xf0) { type -= 0xf0; if (type == KT_LETTER) { type = KT_LATIN; if (vc_kbd_led(kbd, VC_CAPSLOCK)) { key_map = key_maps[shift_final ^ (1<<KG_SHIFT)]; if (key_map) keysym = key_map[keycode]; } } (*key_handler[type])(keysym & 0xff, up_flag); if (type != KT_SLOCK) kbd->slockstate = 0; } } else { /* maybe beep? */ /* we have at least to update shift_state */ sun_compute_shiftstate(); } } out: tasklet_schedule(&keyboard_tasklet); }
int scan_push(unsigned char scancode) { unsigned char keycode; unsigned char raw_mode = 1; int down = !(scancode & 0x80); unsigned char up_flag = down ? 0 : 0200; unsigned short keysym; u_char type; int shift_final, shift_local = 0; unsigned short *key_map; if (!first_key) { first_key = 1; if (scancode & 0x80) return 0; } #ifdef DBG0 printf("scan_push: %d\r\n", scancode); #endif /* * Convert scancode to keycode */ if (!kbd_translate(scancode, &keycode)) return 1; #ifdef DBG0 printf("translated: down=%d, keycode=%x\r\n", down, keycode); #endif /* * At this point the variable `keycode' contains the keycode. * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). * We keep track of the up/down status of the key, and * return the keycode if in MEDIUMRAW mode. */ if (up_flag) { if (!test_and_clear_bit(keycode, key_down)) { rep = 0; up_flag = kbd_unexpected_up(keycode); } } else rep = test_and_set_bit(keycode, key_down); #ifdef DBG1 printf("up_flag=%d, rep=%d, shift_state=%d\r\n", up_flag, rep, shift_state); #endif /*if (rep) return; */ /* the XOR below used to be an OR */ shift_final = shift_state ^ lockstate ^ slockstate; shift_local = (shift_final & (1 << KG_SHIFTL)) | (shift_final & (1 << KG_SHIFTR)); key_map = key_maps[shift_final]; if (shift_local == 0) shift_local = (1 << KG_SHIFT); if (key_map == NULL) { shift_final = shift_state ^ lockstate ^ slockstate; shift_final = shift_final ^ shift_local; shift_local = 0; key_map = key_maps[shift_final]; } if (key_map != NULL) { keysym = key_map[keycode]; type = KTYP(keysym); #ifdef DBG2 printf("\ntype=%x,shift_state=%d,shift_final=%d,keykode=%d,shift_local=%d\r\n", type, shift_state, shift_final, keycode, shift_local); #endif if (type >= 0xf0) { type -= 0xf0; if (type == KT_LETTER) { type = KT_LATIN; if (capslock_state) { shift_final = shift_final ^ shift_local; key_map = key_maps[shift_final]; //key_map = key_maps[shift_final ^ (1 << KG_SHIFT)]; if (key_map) keysym = key_map[keycode]; #ifdef DBG2 printf(" caps=%d,keykode=%d,keysym=%d,kg_shift=%d\r\n", shift_final, keycode, keysym, KG_SHIFT); #endif } } #ifdef DBG printf("key_handler[%d] call: %s, keysym=0x%x, up_flag=0x%x\r\n", type, key_handler_names[type], keysym & 0xff, up_flag); #endif /* printf("\nA keysym=%d,type=%d,%d",keysym,type,KT_SHIFT); */ (*key_handler[type]) (keysym & 0xff, up_flag); if (type != KT_SLOCK) slockstate = 0; } else { /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ if (!up_flag && !raw_mode) to_utf8(keysym); } } else { /* maybe beep? */ /* we have at least to update shift_state */ key_map = key_maps[0]; keysym = key_map[keycode]; type = KTYP(keysym); /* printf("\nB keysym=%d,type=%d,%d",keysym,type,KT_SHIFT); */ /*check CTRL,SHIFT,ALT keys status */ if (keysym >= 63234 && keysym <= 63237) (*key_handler[KT_SHIFT]) (keysym & 0xff, up_flag); else compute_shiftstate(); } return 1; }
/* * Check if the keyboard controller has a keypress for us. * Some parts (Enter Release, LED change) are still blocking polled here, * but hopefully they are all short. */ static int get_kbd_char(void) { int scancode, scanstatus; static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ static int shift_key; /* Shift next keypress */ static int ctrl_key; u_short keychar; extern u_short plain_map[], shift_map[], ctrl_map[]; if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) || (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) { kbd_exists = 0; return -1; } kbd_exists = 1; if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) return -1; /* * Fetch the scancode */ scancode = inb(KBD_DATA_REG); scanstatus = inb(KBD_STATUS_REG); /* * Ignore mouse events. */ if (scanstatus & KBD_STAT_MOUSE_OBF) return -1; /* * Ignore release, trigger on make * (except for shift keys, where we want to * keep the shift state so long as the key is * held down). */ if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { /* * Next key may use shift table */ if ((scancode & 0x80) == 0) { shift_key=1; } else { shift_key=0; } return -1; } if ((scancode&0x7f) == 0x1d) { /* * Left ctrl key */ if ((scancode & 0x80) == 0) { ctrl_key = 1; } else { ctrl_key = 0; } return -1; } if ((scancode & 0x80) != 0) return -1; scancode &= 0x7f; /* * Translate scancode */ if (scancode == 0x3a) { /* * Toggle caps lock */ shift_lock ^= 1; #ifdef KDB_BLINK_LED kdb_toggleled(0x4); #endif return -1; } if (scancode == 0x0e) { /* * Backspace */ return 8; } /* Special Key */ switch (scancode) { case 0xF: /* Tab */ return 9; case 0x53: /* Del */ return 4; case 0x47: /* Home */ return 1; case 0x4F: /* End */ return 5; case 0x4B: /* Left */ return 2; case 0x48: /* Up */ return 16; case 0x50: /* Down */ return 14; case 0x4D: /* Right */ return 6; } if (scancode == 0xe0) { return -1; } /* * For Japanese 86/106 keyboards * See comment in drivers/char/pc_keyb.c. * - Masahiro Adegawa */ if (scancode == 0x73) { scancode = 0x59; } else if (scancode == 0x7d) { scancode = 0x7c; } if (!shift_lock && !shift_key && !ctrl_key) { keychar = plain_map[scancode]; } else if (shift_lock || shift_key) { keychar = shift_map[scancode]; } else if (ctrl_key) { keychar = ctrl_map[scancode]; } else { keychar = 0x0020; kdb_printf("Unknown state/scancode (%d)\n", scancode); } keychar &= 0x0fff; if (keychar == '\t') keychar = ' '; switch (KTYP(keychar)) { case KT_LETTER: case KT_LATIN: if (isprint(keychar)) break; /* printable characters */ /* drop through */ case KT_SPEC: if (keychar == K_ENTER) break; /* drop through */ default: return(-1); /* ignore unprintables */ } if ((scancode & 0x7f) == 0x1c) { /* * enter key. All done. Absorb the release scancode. */ while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ; /* * Fetch the scancode */ scancode = inb(KBD_DATA_REG); scanstatus = inb(KBD_STATUS_REG); while (scanstatus & KBD_STAT_MOUSE_OBF) { scancode = inb(KBD_DATA_REG); scanstatus = inb(KBD_STATUS_REG); } if (scancode != 0x9c) { /* * Wasn't an enter-release, why not? */ kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", scancode, scanstatus); } kdb_printf("\n"); return 13; } return keychar & 0xff; }
/* keycode_to_char: [fdwatch thread] * Helper function. * KEYCODE is a Linux kernel keycode, not an Allegro keycode. * * In the process of doing the translation, we may find that the user * has pressed a key that for VT switching. In that case a negative * number is returned, the absolute value of which is the VT to * switch to. Yes, ugly. */ static int keycode_to_char(int keycode) { const unsigned int modifiers = the_keyboard.modifiers; struct kbentry kbe; int keymap; int ascii; /* build kernel keymap number */ keymap = 0; if (modifiers & ALLEGRO_KEYMOD_SHIFT) keymap |= 1; if (modifiers & ALLEGRO_KEYMOD_ALTGR) keymap |= 2; if (modifiers & ALLEGRO_KEYMOD_CTRL) keymap |= 4; if (modifiers & ALLEGRO_KEYMOD_ALT) keymap |= 8; /* map keycode to type and value */ kbe.kb_table = keymap; kbe.kb_index = keycode; ioctl(the_keyboard.fd, KDGKBENT, &kbe); if (keycode == KEY_BACKSPACE) ascii = 8; else { if (kbe.kb_value == K_NOSUCHMAP) { /* invalid keymaps */ /* FIXME: Maybe we should just redo the */ /* ioctl with keymap 0? */ ascii = 0; } else { /* most keys come here */ ascii = KVAL(kbe.kb_value); } } /* finally do some things based on key type */ switch (KTYP(kbe.kb_value)) { case KT_CONS: /* VT switch key -- return a negative number */ return -( KVAL(kbe.kb_value)+1 ); case KT_LETTER: /* apply capslock translation. */ if (modifiers & ALLEGRO_KEYMOD_CAPSLOCK) return ascii ^ 0x20; else return ascii; case KT_LATIN: case KT_ASCII: return ascii; case KT_PAD: { int val = KVAL(kbe.kb_value); if (modifiers & ALLEGRO_KEYMOD_NUMLOCK) { if ((val >= 0) && (val < NUM_PAD_KEYS)) ascii = pad_asciis[val]; } else { if ((val >= 0) && (val < NUM_PAD_KEYS)) ascii = pad_asciis_no_numlock[val]; } return ascii; } case KT_SPEC: if (keycode == KEY_ENTER) return '\r'; else return 0; default: /* dunno */ return 0; } }
static DFBInputDeviceKeySymbol keyboard_get_symbol( int code, unsigned short value, DFBInputDeviceKeymapSymbolIndex level ) { unsigned char type = KTYP(value); unsigned char index = KVAL(value); int base = (level == DIKSI_BASE); switch (type) { case KT_FN: if (index < 20) return DFB_FUNCTION_KEY( index + 1 ); break; case KT_LETTER: case KT_LATIN: switch (index) { case 0x1c: return DIKS_PRINT; case 0x7f: return DIKS_BACKSPACE; case 0xa4: return 0x20ac; /* euro currency sign */ default: return index; } break; case KT_DEAD: switch (value) { case K_DGRAVE: return DIKS_DEAD_GRAVE; case K_DACUTE: return DIKS_DEAD_ACUTE; case K_DCIRCM: return DIKS_DEAD_CIRCUMFLEX; case K_DTILDE: return DIKS_DEAD_TILDE; case K_DDIERE: return DIKS_DEAD_DIAERESIS; case K_DCEDIL: return DIKS_DEAD_CEDILLA; default: break; } break; case KT_PAD: if (index <= 9 && level != DIKSI_BASE) return DIKS_0 + index; break; case 0xe: /* special IPAQ H3600 case - AH */ switch (index) { case 0x20: return DIKS_CALENDAR; case 0x1a: return DIKS_BACK; case 0x1c: return DIKS_MEMO; case 0x21: return DIKS_POWER; } break; case 0xd: /* another special IPAQ H3600 case - AH */ switch (index) { case 0x2: return DIKS_DIRECTORY; case 0x1: return DIKS_MAIL; /* Q on older iPaqs */ } break; } switch (value) { case K_LEFT: return DIKS_CURSOR_LEFT; case K_RIGHT: return DIKS_CURSOR_RIGHT; case K_UP: return DIKS_CURSOR_UP; case K_DOWN: return DIKS_CURSOR_DOWN; case K_ENTER: return DIKS_ENTER; case K_CTRL: return DIKS_CONTROL; case K_SHIFT: return DIKS_SHIFT; case K_ALT: return DIKS_ALT; case K_ALTGR: return DIKS_ALTGR; case K_INSERT: return DIKS_INSERT; case K_REMOVE: return DIKS_DELETE; case K_FIND: return DIKS_HOME; case K_SELECT: return DIKS_END; case K_PGUP: return DIKS_PAGE_UP; case K_PGDN: return DIKS_PAGE_DOWN; case K_NUM: return DIKS_NUM_LOCK; case K_HOLD: return DIKS_SCROLL_LOCK; case K_PAUSE: return DIKS_PAUSE; case K_BREAK: return DIKS_BREAK; case K_CAPS: return DIKS_CAPS_LOCK; case K_P0: return DIKS_INSERT; case K_P1: return DIKS_END; case K_P2: return DIKS_CURSOR_DOWN; case K_P3: return DIKS_PAGE_DOWN; case K_P4: return DIKS_CURSOR_LEFT; case K_P5: return DIKS_BEGIN; case K_P6: return DIKS_CURSOR_RIGHT; case K_P7: return DIKS_HOME; case K_P8: return DIKS_CURSOR_UP; case K_P9: return DIKS_PAGE_UP; case K_PPLUS: return DIKS_PLUS_SIGN; case K_PMINUS: return DIKS_MINUS_SIGN; case K_PSTAR: return DIKS_ASTERISK; case K_PSLASH: return DIKS_SLASH; case K_PENTER: return DIKS_ENTER; case K_PCOMMA: return base ? DIKS_DELETE : DIKS_COMMA; case K_PDOT: return base ? DIKS_DELETE : DIKS_PERIOD; case K_PPARENL: return DIKS_PARENTHESIS_LEFT; case K_PPARENR: return DIKS_PARENTHESIS_RIGHT; } /* special keys not in the map, hack? */ if (code == 99) return DIKS_PRINT; if (code == 124) /* keypad equal key */ return DIKS_EQUALS_SIGN; if (code == 125) /* left windows key */ return DIKS_META; if (code == 126) /* right windows key */ return DIKS_META; if (code == 127) /* context menu key */ return DIKS_SUPER; return DIKS_NULL; }
static int keyboard_notifier_call(struct notifier_block *blk, unsigned long code, void *_param) { struct keyboard_notifier_param *param = _param; struct vc_data *vc = param->vc; int ret = NOTIFY_OK; if (!param->down) return ret; switch (code) { case KBD_KEYCODE: if (console_show) { if (param->value == BRAILLE_KEY) { console_show = 0; beep(880); vc_maybe_cursor_moved(vc); vc_refresh(vc); ret = NOTIFY_STOP; } } else { ret = NOTIFY_STOP; switch (param->value) { case KEY_INSERT: beep(440); console_show = 1; lastVC = -1; braille_write(console_buf); break; case KEY_LEFT: if (vc_x > 0) { vc_x -= WIDTH; if (vc_x < 0) vc_x = 0; } else if (vc_y >= 1) { beep(880); vc_y--; vc_x = vc->vc_cols-WIDTH; } else beep(220); break; case KEY_RIGHT: if (vc_x + WIDTH < vc->vc_cols) { vc_x += WIDTH; } else if (vc_y + 1 < vc->vc_rows) { beep(880); vc_y++; vc_x = 0; } else beep(220); break; case KEY_DOWN: if (vc_y + 1 < vc->vc_rows) vc_y++; else beep(220); break; case KEY_UP: if (vc_y >= 1) vc_y--; else beep(220); break; case KEY_HOME: vc_follow_cursor(vc); break; case KEY_PAGEUP: vc_x = 0; vc_y = 0; break; case KEY_PAGEDOWN: vc_x = 0; vc_y = vc->vc_rows-1; break; default: ret = NOTIFY_OK; break; } if (ret == NOTIFY_STOP) vc_refresh(vc); } break; case KBD_POST_KEYSYM: { unsigned char type = KTYP(param->value) - 0xf0; if (type == KT_SPEC) { unsigned char val = KVAL(param->value); int on_off = -1; switch (val) { case KVAL(K_CAPS): on_off = vc_kbd_led(kbd_table + fg_console, VC_CAPSLOCK); break; case KVAL(K_NUM): on_off = vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK); break; case KVAL(K_HOLD): on_off = vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK); break; } if (on_off == 1) beep(880); else if (on_off == 0) beep(440); } } case KBD_UNBOUND_KEYCODE: case KBD_UNICODE: case KBD_KEYSYM: /* Unused */ break; } return ret; }
/* Keyboard support */ static int kbd_getc(void) { unsigned char dt, brk, val; unsigned code; loop: while((kbd_inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ; dt = kbd_inb(KBD_DATA_REG); brk = dt & 0x80; /* brk == 1 on key release */ dt = dt & 0x7f; /* keycode */ if (console_global_data.shfts) code = shift_map[dt]; else if (console_global_data.ctls) code = ctrl_map[dt]; else code = plain_map[dt]; val = KVAL(code); switch (KTYP(code) & 0x0f) { case KT_LATIN: if (brk) break; if (console_global_data.alts) val |= 0x80; if (val == 0x7f) /* map delete to backspace */ val = '\b'; return val; case KT_LETTER: if (brk) break; if (console_global_data.caps) val -= 'a'-'A'; return val; case KT_SPEC: if (brk) break; if (val == KVAL(K_CAPS)) console_global_data.caps = !console_global_data.caps; else if (val == KVAL(K_ENTER)) { enter: /* Wait for key up */ while (1) { while((kbd_inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ; dt = kbd_inb(KBD_DATA_REG); if (dt & 0x80) /* key up */ break; } return 10; } break; case KT_PAD: if (brk) break; if (val < 10) return val; if (val == KVAL(K_PENTER)) goto enter; break; case KT_SHIFT: switch (val) { case KG_SHIFT: case KG_SHIFTL: case KG_SHIFTR: console_global_data.shfts = brk ? 0 : 1; break; case KG_ALT: case KG_ALTGR: console_global_data.alts = brk ? 0 : 1; break; case KG_CTRL: case KG_CTRLL: case KG_CTRLR: console_global_data.ctls = brk ? 0 : 1; break; } break; case KT_LOCK: switch (val) { case KG_SHIFT: case KG_SHIFTL: case KG_SHIFTR: if (brk) console_global_data.shfts = !console_global_data.shfts; break; case KG_ALT: case KG_ALTGR: if (brk) console_global_data.alts = !console_global_data.alts; break; case KG_CTRL: case KG_CTRLL: case KG_CTRLR: if (brk) console_global_data.ctls = !console_global_data.ctls; break; } break; } /* if (brk) return (0); */ /* Ignore initial 'key up' codes */ goto loop; }
static int kbd(int noblock) { unsigned char dt, brk, val; unsigned code; loop: if (noblock) { if ((inb(KBSTATP) & KBINRDY) == 0) return (-1); } else while((inb(KBSTATP) & KBINRDY) == 0) ; dt = inb(KBDATAP); brk = dt & 0x80; /* brk == 1 on key release */ dt = dt & 0x7f; /* keycode */ if (shfts) code = shift_map[dt]; else if (ctls) code = ctrl_map[dt]; else code = plain_map[dt]; val = KVAL(code); switch (KTYP(code) & 0x0f) { case KT_LATIN: if (brk) break; if (alts) val |= 0x80; if (val == 0x7f) /* map delete to backspace */ val = '\b'; return val; case KT_LETTER: if (brk) break; if (caps) val -= 'a'-'A'; return val; case KT_SPEC: if (brk) break; if (val == KVAL(K_CAPS)) caps = !caps; else if (val == KVAL(K_ENTER)) { enter: /* Wait for key up */ while (1) { while((inb(KBSTATP) & KBINRDY) == 0) ; dt = inb(KBDATAP); if (dt & 0x80) /* key up */ break; } return 10; } break; case KT_PAD: if (brk) break; if (val < 10) return val; if (val == KVAL(K_PENTER)) goto enter; break; case KT_SHIFT: switch (val) { case KG_SHIFT: case KG_SHIFTL: case KG_SHIFTR: shfts = brk ? 0 : 1; break; case KG_ALT: case KG_ALTGR: alts = brk ? 0 : 1; break; case KG_CTRL: case KG_CTRLL: case KG_CTRLR: ctls = brk ? 0 : 1; break; } break; case KT_LOCK: switch (val) { case KG_SHIFT: case KG_SHIFTL: case KG_SHIFTR: if (brk) shfts = !shfts; break; case KG_ALT: case KG_ALTGR: if (brk) alts = !alts; break; case KG_CTRL: case KG_CTRLL: case KG_CTRLR: if (brk) ctls = !ctls; break; } break; } if (brk) return (-1); /* Ignore initial 'key up' codes */ goto loop; }
int CLinuxInputDevice::KeyboardGetSymbol(unsigned short value) { unsigned char type = KTYP(value); unsigned char index = KVAL(value); switch (type) { case KT_FN: if (index < 15) return XBMCK_F1 + index; break; case KT_LETTER: case KT_LATIN: switch (index) { case 0x1c: return XBMCK_PRINT; case 0x7f: return XBMCK_BACKSPACE; case 0xa4: return XBMCK_EURO; /* euro currency sign */ default: return index; } break; /* case KT_DEAD: switch (value) { case K_DGRAVE: return DIKS_DEAD_GRAVE; case K_DACUTE: return DIKS_DEAD_ACUTE; case K_DCIRCM: return DIKS_DEAD_CIRCUMFLEX; case K_DTILDE: return DIKS_DEAD_TILDE; case K_DDIERE: return DIKS_DEAD_DIAERESIS; case K_DCEDIL: return DIKS_DEAD_CEDILLA; default: break; } break; case KT_PAD: if (index <= 9 && level != DIKSI_BASE) return (DFBInputDeviceKeySymbol) (DIKS_0 + index); break; */ } return XBMCK_UNKNOWN; }
static void kb_translate(_self, int code, int up) { static int prev= 0; unsigned short *keyMap= self->keyMaps[self->state]; int rep= (!up) && (prev == code); prev= up ? 0 : code; debugf("+++ code %d up %d prev %d rep %d map %p\n", code, up, prev, rep, keyMap); if (keyMap) { int sym= keyMap[code]; int type= KTYP(sym); debugf("+++ sym %x (%02x) type %d\n", sym, sym & 255, type); sym &= 255; if (type >= 0xf0) // shiftable type -= 0xf0; if (KT_LETTER == type) // lockable type= KT_LATIN; debugf("+++ type %d\n", type); switch (type) { case KT_LATIN: case KT_META: kb_post(self, sym, up); break; case KT_SHIFT: if (rep) break; else if (up) self->state &= ~(1 << sym); else self->state |= (1 << sym); updateModifiers(self->state); break; case KT_FN: case KT_SPEC: case KT_CUR: switch (K(type,sym)) { // FN case K_FIND: kb_post(self, 1, up); break; // home case K_INSERT: kb_post(self, 5, up); break; case K_SELECT: kb_post(self, 4, up); break; // end case K_PGUP: kb_post(self, 11, up); break; case K_PGDN: kb_post(self, 12, up); break; // SPEC case K_ENTER: kb_post(self, 13, up); break; // CUR case K_DOWN: kb_post(self, 31, up); break; case K_LEFT: kb_post(self, 28, up); break; case K_RIGHT: kb_post(self, 29, up); break; case K_UP: kb_post(self, 30, up); break; } break; case KT_CONS: if (self->vtSwitch && !self->vtLock) kb_chvt(self, sym + 1); break; default: if (type > KT_SLOCK) debugf("ignoring unknown scancode %d.%d\n", type, sym); break; } } }
void SDL_EVDEV_Poll(void) { struct input_event events[32]; int i, len; SDL_evdevlist_item *item; SDL_Scancode scan_code; int mouse_button; SDL_Mouse *mouse; #ifdef SDL_INPUT_LINUXKD Uint16 modstate; struct kbentry kbe; static char keysym[8]; char *end; Uint32 kval; #endif #if SDL_USE_LIBUDEV SDL_UDEV_Poll(); #endif mouse = SDL_GetMouse(); for (item = _this->first; item != NULL; item = item->next) { while ((len = read(item->fd, events, (sizeof events))) > 0) { len /= sizeof(events[0]); for (i = 0; i < len; ++i) { switch (events[i].type) { case EV_KEY: if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) { mouse_button = events[i].code - BTN_MOUSE; if (events[i].value == 0) { SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]); } else if (events[i].value == 1) { SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]); } break; } /* Probably keyboard */ scan_code = SDL_EVDEV_translate_keycode(events[i].code); if (scan_code != SDL_SCANCODE_UNKNOWN) { if (events[i].value == 0) { SDL_SendKeyboardKey(SDL_RELEASED, scan_code); } else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) { SDL_SendKeyboardKey(SDL_PRESSED, scan_code); #ifdef SDL_INPUT_LINUXKD if (_this->console_fd >= 0) { kbe.kb_index = events[i].code; /* Convert the key to an UTF-8 char */ /* Ref: http://www.linuxjournal.com/article/2783 */ modstate = SDL_GetModState(); kbe.kb_table = 0; /* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */ kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL); kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL); kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT); kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT); kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT); kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR); if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 && ((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER))) { kval = KVAL(kbe.kb_value); /* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it * because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale! */ if ( modstate & KMOD_CAPS && isalpha(kval) ) { if ( isupper(kval) ) { kval = tolower(kval); } else { kval = toupper(kval); } } /* Convert to UTF-8 and send */ end = SDL_UCS4ToUTF8( kval, keysym); *end = '\0'; SDL_SendKeyboardText(keysym); } } #endif /* SDL_INPUT_LINUXKD */ } } break; case EV_ABS: switch(events[i].code) { case ABS_X: SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y); break; case ABS_Y: SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value); break; default: break; } break; case EV_REL: switch(events[i].code) { case REL_X: SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0); break; case REL_Y: SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value); break; case REL_WHEEL: SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value); break; case REL_HWHEEL: SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0); break; default: break; } break; case EV_SYN: switch (events[i].code) { case SYN_DROPPED: SDL_EVDEV_sync_device(item); break; default: break; } break; } } } } }
static void keyboard_console_handler(void) { unsigned char buffer[128], scancode; int pressed, repeated, num_bytes, i, key, extended; int vt, orig_vt; struct kbentry entry; struct vt_stat vt_state; num_bytes = read(key_fd, &buffer, sizeof(buffer)); if (num_bytes > 0) { for (i = 0; i < num_bytes; i++) { scancode = kernel_to_scancode[buffer[i] & 0x7F]; pressed = (buffer[i] & 0x80) ^ 0x80; repeated = pressed && key_state[scancode]; key_state[scancode] = pressed; /* Since we took over keyboard control, we have to map our keypresses to ascii * in order to report them in our own keyboard buffer */ extended = 0; switch (scancode) { case SC_CAPSLOCK: if (pressed) key_leds ^= LED_CAP; break; case SC_NUMLOCK: if (pressed) key_leds ^= LED_NUM; break; case SC_SCROLLLOCK: if (pressed) key_leds ^= LED_SCR; break; default: extended = fb_hScancodeToExtendedKey( scancode ); break; } /* Fill in kbentry struct for KDGKBENT query */ entry.kb_table = 0; /* modifier table */ if (key_state[SC_LSHIFT] || key_state[SC_RSHIFT]) entry.kb_table |= 0x1; if (key_state[SC_ALTGR]) entry.kb_table |= 0x2; if (key_state[SC_CONTROL]) entry.kb_table |= 0x4; if (key_state[SC_ALT]) entry.kb_table |= 0x8; entry.kb_index = scancode; /* keycode */ ioctl(key_fd, KDGKBENT, &entry); if (scancode == SC_BACKSPACE) key = 8; else if (entry.kb_value == K_NOSUCHMAP) key = 0; else { key = KVAL(entry.kb_value); switch (KTYP(entry.kb_value)) { case KT_LETTER: if (key_leds & LED_CAP) key ^= 0x20; break; case KT_LATIN: case KT_ASCII: break; case KT_PAD: if (key < NUM_PAD_KEYS) { if (key_leds & LED_NUM) key = pad_numlock_ascii[key]; else key = pad_ascii[key]; } else key = 0; break; case KT_SPEC: if (scancode == SC_ENTER) key = '\r'; break; case KT_CONS: vt = key + 1; if( pressed && (ioctl(key_fd, VT_GETSTATE, &vt_state) >= 0) ) { orig_vt = vt_state.v_active; if (vt != orig_vt) { if (__fb_con.gfx_exit) { gfx_save(); ioctl(key_fd, KDSETMODE, KD_TEXT); } ioctl(key_fd, VT_ACTIVATE, vt); ioctl(key_fd, VT_WAITACTIVE, vt); while (ioctl(key_fd, VT_WAITACTIVE, orig_vt) < 0) usleep(50000); if (__fb_con.gfx_exit) { ioctl(key_fd, KDSETMODE, KD_GRAPHICS); gfx_restore(); } memset(key_state, FALSE, 128); } else { key_state[scancode] = FALSE; } extended = 0; } /* fallthrough */ default: key = 0; break; } } if( extended ) key = extended; if( pressed && key ) { key_buffer[key_tail] = key; if (((key_tail + 1) & (KEY_BUFFER_SIZE - 1)) == key_head) key_head = (key_head + 1) & (KEY_BUFFER_SIZE - 1); key_tail = (key_tail + 1) & (KEY_BUFFER_SIZE - 1); } if( gfx_key_handler ) gfx_key_handler( pressed, repeated, scancode, key ); } } /* CTRL + C */ if( key_state[SC_CONTROL] && key_state[SC_C] ) kill(main_pid, SIGINT); }