/* * KEYBOARD.C * * (C)Copyright 1987 by Matthew Dillon * * Handle keyboard related stuff such as keyboard mappings. Every time * a key is pressed, KEYCTL() is called with the code. KEYCTL() remembers * which qualifier keys are currently held down, and when a non-qualifier * key is pressed finds the hash entry for the key. If no hash entry * exists (e.g. you type a normal 'a') the default keymap is used. */ #include "defs.h" typedef struct IOStdReq CIO; #define QUAL_SHIFT 0x01 #define QUAL_CTRL 0x02 #define QUAL_AMIGA 0x04 #define QUAL_ALT 0x08 #define QUAL_LMB 0x10 #define QUAL_MMB 0x20 #define QUAL_RMB 0x40 #define XBITSET(array,bit) (array[(bit)>>3] |= 1<<((bit)&7)) #define XBITTEST(array,bit) (array[(bit)>>3] & 1<<((bit)&7)) #define HASHSIZE 64 typedef struct _HASH { struct _HASH *next; /* next hash */ u_char code; /* keycode */ u_char mask; /* qual. mask */ u_char qual; /* qual. comp */ u_char stat; /* string static? */ char *str; /* command string */ } HASH; HASH *Hash[HASHSIZE]; static u_char isascii[0x80/8]; /* is printable ascii */ static u_char isalpha[0x80/8]; /* is alpha a-z/A-Z */ static u_char ctoa[0x80]; /* cvt to character */ static u_char cstoa[0x80]; /* cvt to shifted chacter */ dealloc_hash() { register HASH *hash, *hnext = NULL; register short i; for (i = 0; i < HASHSIZE; ++i) { for (hash = Hash[i]; hash; hash = hnext) { hnext = hash->next; if (!hash->stat) FreeMem(hash->str, strlen(hash->str)+1); FreeMem(hash, sizeof(HASH)); } Hash[i] = NULL; } } resethash() { register short i; static struct { char *from, *to; } defmap[] = { "esc", "esc", "return", "return insline up firstnb down", "enter", "return", "up", "up", "down", "down", "right", "right", "left", "left", "bs", "bs", "del", "del", "help", "newwindow newfile s:DME.DOC escimm `find '", "tab", "tab", "s-up", "top", "s-down", "bottom", "s-right", "last", "s-left", "first", "s-tab", "backtab", "s-del", "deline", "s- ", "` '", /* shift space to space */ "c-l", "wleft", "c-r", "wright", "c-i", "insertmode on", "c-o", "insertmode off", "c-j", "join", "c-s", "split first down", "c-del", "remeol", "c-n", "next", "c-p", "prev", "c-/", "escimm `find '", "c-g", "escimm `goto '", "c-up", "pageup", "c-down", "pagedown", "c-q", "quit", "c-f", "reformat", "c-w", "wordwrap toggle", "f1", "escimm `insfile '", "f2", "escimm `newfile '", "f3", "escimm `newwindow newfile '", "f7", "escimm `bsave '", "f8", "saveold escimm `newfile '", "f9", "saveold", "f10", "saveold quit", "c-b", "block", "c-u", "unblock", "a-d", "bdelete", "a-c", "bcopy", "a-m", "bmove", "a-s", "bsource", "a-S", "unblock block block bsource", "L-lmb", "tomouse", /* left button */ "L-mmo", "tomouse", /* mouse move w/left held down */ "R-rmb", "iconify", /* right button */ NULL, NULL }; dealloc_hash(); loaddefaultkeymap(); for (i = 0; defmap[i].from; ++i) { u_char code, qual; if (get_codequal(defmap[i].from, &code, &qual)) addhash(code, 1, 0xFF, qual, defmap[i].to); } } /* * Go through keycodes $00 to $4F and load the ctoa[], cstoa[], and * isalpha[] char tables from the default console keymap. */ loaddefaultkeymap() { CIO cio; struct KeyMap km; /* * Note: -1 specification for unit # means that we are not openning * a real console. We can only execute a CD_ASKDEFAULTKEYMAP through * it. */ if (!OpenDevice("console.device", -1, &cio, 0)) { cio.io_Command = CD_ASKDEFAULTKEYMAP; cio.io_Data = (APTR)&km; cio.io_Length = sizeof(km); DoIO(&cio); loadhilo(km.km_LoKeyMapTypes, km.km_LoKeyMap, km.km_LoCapsable, 0, 0x40, 0x00); loadhilo(km.km_HiKeyMapTypes, km.km_HiKeyMap, km.km_HiCapsable, 0, 0x10, 0x40); CloseDevice(&cio); } else { if (Output()) puts ("Unable to get console keymap"); } } /* * Decode plain and shifted keys only. Ignore strings larger than * a single character (thus things like the cursor keys do not get * mapped) */ loadhilo(types, map, caps, is, ie, ia) u_char *types; u_char *caps; long *map; { register long n; register int idx; register u_char *ptr; u_char c; for (; is < ie; ++is) { n = map[is]; if (n && (types[is] & 0x60)) { /* STRING 0x40 or BUG 0x20 */ ptr = (u_char *)n; n = 0; if (ptr[0] == 0) n = ptr[1]; if (ptr[0] == 1) n = ptr[ptr[1]]; if (types[is] & KCF_SHIFT) { if (ptr[2] == 0) n |= ptr[3] << 8; if (ptr[2] == 1) n |= ptr[ptr[3]] << 8; } } idx = is + ia; c = n; ctoa[idx] = c; cstoa[idx] = (n>>8) & 0xFF; if (caps[is>>3] & (1 << (is&7))) XBITSET(isalpha,idx); if (c >= 32 && c != 0x7F && ctoa[idx]) XBITSET(isascii,idx); } } returnoveride(n) { HASH *hash; static u_char *str; static int stat; for (hash = Hash[0x44 % HASHSIZE]; hash; hash = hash->next) { if (hash->code == 0x44 && hash->qual == 0) { if (n) { str = (u_char *)hash->str; stat= hash->stat; hash->str = "return"; hash->stat = 1; } else { if (str == NULL) { remhash(0x44, -1, 0); } else { hash->str = (char *)str; hash->stat= stat; } } return(0); } } if (n) { addhash(0x44, 1, 0xFF, 0, "return"); str = NULL; } } addhash(code, stat, mask, qual, str) u_char code, stat, mask, qual; u_char *str; { register HASH **p, *hash; hash = *(p = &Hash[code % HASHSIZE]); while (hash) { if (hash->code == code && hash->qual == qual && hash->mask == mask) { if (!hash->stat) FreeMem(hash->str, strlen(hash->str)+1); goto newstr; } hash = *(p = &hash->next); } *p = hash = (HASH *)AllocMem(sizeof(HASH), 0); hash->next = NULL; newstr: hash->code = code; hash->stat = stat; hash->mask = mask; hash->qual = qual; hash->str = (char *)str; if (!stat) /* if not static */ hash->str = (char *)strcpy(AllocMem(strlen(str)+1, 0), str); } remhash(code, mask, qual) u_char code, mask, qual; { register HASH *hash, **p; hash = *(p = &Hash[code % HASHSIZE]); while (hash) { if (hash->code == code && hash->qual == qual && hash->mask == mask) { if (!hash->stat) FreeMem(hash->str, strlen(hash->str)+1); *p = hash->next; FreeMem(hash, sizeof(HASH)); return(1); } hash = *(p = &hash->next); } return(0); } keyctl(code, qual) register USHORT qual; { register u_char c, c2; register HASH *hash; code &= 0xFF; if ((code & 0x78) == 0x60) /* forget qualifier keys */ return(0); if (code & 0x80) /* forget upstrokes */ return(0); c2 = 0; if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) c2 |= QUAL_SHIFT; if (qual & (IEQUALIFIER_CONTROL)) c2 |= QUAL_CTRL; if (qual & (IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND)) c2 |= QUAL_AMIGA; if (qual & (IEQUALIFIER_LALT|IEQUALIFIER_RALT)) c2 |= QUAL_ALT; if ((qual & IEQUALIFIER_CAPSLOCK) && (code <= 0x37) && XBITTEST(isalpha,code)) c2 |= QUAL_SHIFT; if (qual & IEQUALIFIER_LEFTBUTTON) c2 |= QUAL_LMB; if (qual & IEQUALIFIER_MIDBUTTON) c2 |= QUAL_MMB; if (qual & (IEQUALIFIER_RBUTTON)) c2 |= QUAL_RMB; for (hash = Hash[code % HASHSIZE]; hash; hash = hash->next) { if (hash->code == code) { if ((c2 & hash->mask) == hash->qual) break; } } /* * Use hash entry only if not in command line mode, or if the * entry does not correspond to an alpha key. */ if (hash) { char buf[256]; /*printf ("c2 %lx BIT: %lx\n", c2, XBITTEST(isascii,code));*/ if (c2 || !ComLineMode || !XBITTEST(isascii,code)) { strcpy(buf, hash->str); do_command(buf); return(0); } } if (code < 0x50) { c = (c2 & QUAL_SHIFT) ? cstoa[code] : ctoa[code]; if (c2 & QUAL_CTRL) c &= 0x1F; if (c && (c2 & QUAL_ALT)) c |= 0x80; if (c && (c2 & QUAL_AMIGA)) c |= 0xC0; if (c) { u_char buf[3]; buf[0] = '\''; buf[1] = c; buf[2] = 0; do_command(buf); } } } #define LN(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|d) long lname[] = { LN('e','s','c',0x45), LN('f','1', 0 ,0x50), LN('f','2', 0 ,0x51), LN('f','3', 0 ,0x52), LN('f','4', 0 ,0x53), LN('f','5', 0 ,0x54), LN('f','6', 0 ,0x55), LN('f','7', 0 ,0x56), LN('f','8', 0 ,0x57), LN('f','9', 0 ,0x58), LN('f','1','0',0x59), LN('d','e','l',0x46), LN('b','a','c',0x41), LN('b','s', 0 ,0x41), LN('t','a','b',0x42), LN('h','e','l',0x5F), LN('r','e','t',0x44), LN('u','p', 0 ,0x4C), LN('d','o','w',0x4D), LN('r','i','g',0x4E), LN('l','e','f',0x4F), LN('e','n','t',0x43), LN('n','k','-',0x4A), LN('n','k','.',0x3C), LN('n','k','0',0x0F), LN('n','k','1',0x1D), LN('n','k','2',0x1E), LN('n','k','3',0x1F), LN('n','k','4',0x2D), LN('n','k','5',0x2E), LN('n','k','6',0x2F), LN('n','k','7',0x3D), LN('n','k','8',0x3E), LN('n','k','9',0x3F), LN('l','m','b',0x68), LN('m','m','b',0x6A), LN('r','m','b',0x69), LN('m','m','o',QMOVE), 0 }; char * keyspectomacro(str) char *str; { HASH *hash; u_char code, qual; if (get_codequal(str, &code, &qual)) { for (hash = Hash[code % HASHSIZE]; hash; hash = hash->next) { if (hash->code == code) { if (hash->qual == (qual & hash->mask)) return(hash->str); } } } title ("Bad command or unmapped key"); return(NULL); } get_codequal(str, pcode, pqual) u_char *pcode, *pqual; u_char *str; { u_char qual; register short i; qual = 0; if (strlen(str) > 1) { for (; *str && *str != '-'; ++str) { if (*str == 's') qual |= QUAL_SHIFT; if (*str == 'c') qual |= QUAL_CTRL; if (*str == 'a') qual |= QUAL_ALT; if (*str == 'A') qual |= QUAL_AMIGA; if (*str == 'L') qual |= QUAL_LMB; if (*str == 'M') qual |= QUAL_MMB; if (*str == 'R') qual |= QUAL_RMB; if (!qual) goto notqual; } if (*str) ++str; } notqual: *pqual = qual; if (strlen(str) != 1) { /* long name */ register short shift = 24; register long mult = 0; while (*str && shift >= 8) { if (*str >= 'A' && *str <= 'Z') *str = *str - 'A' + 'a'; mult |= *str << shift; shift -= 8; ++str; } for (i = 0; lname[i]; ++i) { if (mult == (lname[i] & 0xFFFFFF00)) { *pcode = lname[i] & 0x7F; return(1); } } } else { /* short name */ for (i = 0; i < sizeof(ctoa); ++i) { if (*str == ctoa[i]) { *pcode = i; return(1); } } for (i = 0; i < sizeof(cstoa); ++i) { if (*str == cstoa[i]) { *pcode = i; *pqual |= QUAL_SHIFT; return(1); } } } return(0); } u_char * cqtoa(code, qual) { static u_char buf[32]; register u_char *ptr = buf; register int i; if (qual & QUAL_SHIFT) *ptr++ = 's'; if (qual & QUAL_CTRL) *ptr++ = 'c'; if (qual & QUAL_ALT) *ptr++ = 'a'; if (qual & QUAL_AMIGA) *ptr++ = 'A'; if (qual & QUAL_LMB) *ptr++ = 'L'; if (qual & QUAL_MMB) *ptr++ = 'M'; if (qual & QUAL_RMB) *ptr++ = 'R'; if (qual) *ptr++ = '-'; for (i = 0; i < sizeof(lname)/sizeof(lname[0]); ++i) { if ((lname[i]&0xFF) == code) { *ptr++ = (lname[i]>>24); *ptr++ = (lname[i]>>16); *ptr++ = (lname[i]>>8); break; } } if (i == sizeof(lname)/sizeof(lname[0])) *ptr++ = ctoa[code]; *ptr++ = 0; return(buf); } do_map() { u_char code, qual; if (get_codequal(av[1], &code, &qual)) { addhash(code, 0, 0xFF, qual, av[2]); } else { title("Unknown Key"); } } do_unmap() /* key */ { u_char code, qual; if (get_codequal(av[1], &code, &qual)) { remhash(code, -1, qual); } else { title("Unknown Command"); } } do_clearmap() { resethash(); } /* * SAVEMAP file * SAVESMAP file */ do_savemap() { char sysalso; char err = 0; u_char buf[256]; long fi; register int i; register HASH *hash; fi = xopen(av[1], "w", 512); if (fi) { sysalso = av[0][4] == 's'; for (i = 0; i < HASHSIZE; ++i) { for (hash = Hash[i]; hash; hash = hash->next) { if (hash->stat == 0 || sysalso) { sprintf(buf, "map `%s' `%s'", cqtoa(hash->code, hash->qual), hash->str); xputs(fi, buf); } } } xclose(fi); if (err) title ("Unable to Write"); else title ("OK"); } else { title("Unable to open file"); } }