aboutsummaryrefslogtreecommitdiff
path: root/sys/libterm/events.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/libterm/events.c')
-rw-r--r--sys/libterm/events.c1692
1 files changed, 0 insertions, 1692 deletions
diff --git a/sys/libterm/events.c b/sys/libterm/events.c
deleted file mode 100644
index 80bc99a..0000000
--- a/sys/libterm/events.c
+++ /dev/null
@@ -1,1692 +0,0 @@
-#include "term.h"
-
-#include <poll.h>
-
-#define bufcount(in) in->buf.c - in->buf.b
-
-enum {
- NodeKey,
- NodeArr,
-};
-
-struct Node
-{
- int type;
-};
-
-struct KeyNode
-{
- struct Node;
- struct KeyInfo key;
-};
-
-struct ArrNode
-{
- struct Node;
- uchar min, max;
- Node *arr[];
-};
-
-// -----------------------------------------------------------------------
-// loads data into trie
-
-static enum KeyEvent peekmousekey(Input *in, Key *key, ulong *nb);
-
-#define FuncNameMax 10
-static struct {
- char *name;
- int type;
- int sym;
- int mods;
-} funcs[] =
-{
- /* THIS LIST MUST REMAIN SORTED ALPHABETICALLY! */
- { "backspace", KeySym, SymBackspace, 0 },
- { "begin", KeySym, SymBegin, 0 },
- { "beg", KeySym, SymBegin, 0 },
- { "btab", KeySym, SymTab, ModShift},
- { "cancel", KeySym, SymCancel, 0 },
- { "clear", KeySym, SymClear, 0 },
- { "close", KeySym, SymClose, 0 },
- { "command", KeySym, SymCommand, 0 },
- { "copy", KeySym, SymCopy, 0 },
- { "dc", KeySym, SymDelete, 0 },
- { "down", KeySym, SymDown, 0 },
- { "end", KeySym, SymEnd, 0 },
- { "enter", KeySym, SymEnter, 0 },
- { "exit", KeySym, SymExit, 0 },
- { "find", KeySym, SymFind, 0 },
- { "help", KeySym, SymHelp, 0 },
- { "home", KeySym, SymHome, 0 },
- { "ic", KeySym, SymInsert, 0 },
- { "left", KeySym, SymLeft, 0 },
- { "mark", KeySym, SymMark, 0 },
- { "message", KeySym, SymMessage, 0 },
- { "move", KeySym, SymMove, 0 },
- { "next", KeySym, SymPagedown, 0 }, // Not quite, but it's the best we can do
- { "npage", KeySym, SymPagedown, 0 },
- { "open", KeySym, SymOpen, 0 },
- { "options", KeySym, SymOptions, 0 },
- { "ppage", KeySym, SymPageup, 0 },
- { "previous", KeySym, SymPageup, 0 }, // Not quite, but it's the best we can do
- { "print", KeySym, SymPrint, 0 },
- { "redo", KeySym, SymRedo, 0 },
- { "reference", KeySym, SymReference, 0 },
- { "refresh", KeySym, SymRefresh, 0 },
- { "replace", KeySym, SymReplace, 0 },
- { "restart", KeySym, SymRestart, 0 },
- { "resume", KeySym, SymResume, 0 },
- { "right", KeySym, SymRight, 0 },
- { "save", KeySym, SymSave, 0 },
- { "select", KeySym, SymSelect, 0 },
- { "suspend", KeySym, SymSuspend, 0 },
- { "undo", KeySym, SymUndo, 0 },
- { "up", KeySym, SymUp, 0 },
- { nil },
-};
-
-// -----------------------------------------------------------------------
-// utility functions
-
-static
-int
-stricmp(char *s, char *t)
-{
- if (s == nil)
- if (t == nil)
- return 0;
- else
- return -strlen(t);
- else
- if (t == nil)
- return +strlen(s);
-
- int d;
- for (; *s && *t; s++, t++) {
- d = tolower(*s) - tolower(*t);
- if (d < 0 || d > 0)
- return d;
- }
-
- /* XXX: not sure about passing in 0 here */
- return tolower(*s) - tolower(*t);
-}
-
-// -----------------------------------------------------------------------
-// bytes -> keysymbols
-
-static
-Node *
-keynode(int type, int sym, int mask, int set)
-{
- struct KeyNode *n;
- n = malloc(sizeof(*n));
- if (!n)
- panicf("out of memory");
-
- n->type = NodeKey;
- n->key.type = type;
- n->key.sym = sym;
- n->key.modmask = mask;
- n->key.modset = set;
-
- return (Node *)n;
-}
-
-static
-Node *
-arrnode(uchar min, uchar max)
-{
- int nb, i;
- struct ArrNode *n;
- nb = ((int)max-min+1)*sizeof(*n->arr);
- n = malloc(sizeof(*n) + nb);
- if (!n)
- panicf("out of memory");
-
- n->type = NodeArr;
- n->min = min, n->max = max;
- for (i = 0; i <= max-min; i++)
- n->arr[i] = nil;
-
- return (Node *)n;
-}
-
-
-static
-Node *
-nlookup(Node *n, uchar b)
-{
- struct ArrNode *arr;
- switch (n->type) {
- case NodeKey:
- panicf("attempting to subdivide a leaf key node");
- return nil;
- case NodeArr:
- arr = (struct ArrNode *)n;
- if (b < arr->min || b > arr->max)
- return nil;
- return arr->arr[b - arr->min];
- default:
- panicf("unrecognized key node type");
- return nil;
- }
-}
-
-static
-Node *
-compress(Node *root)
-{
- int i;
- uchar min, max;
- struct ArrNode *n, *new;
-
- if (!root)
- return root;
-
- switch (root->type) {
- case NodeKey:
- return root;
- case NodeArr:
- n = (struct ArrNode *)root;
- /* find the zeros */
- for (min = 0; !n->arr[min]; min++) {
- if (min == 255 && !n->arr[min]) {
- free(n);
- return arrnode(1, 0);
- }
- }
-
- for (max = 0xff; !n->arr[max]; max--)
- ;
-
- new = (struct ArrNode *)arrnode(min, max);
-
- for (i = min; i <= max; i++)
- new->arr[i-min] = compress(n->arr[i]);
-
- free(n);
- return (Node*)new;
- default:
- panicf("unrecognized key node type");
- return nil;
- }
-
- return root;
-}
-
-static
-void
-teardown(Node *n)
-{
- int i;
- struct ArrNode *arr;
-
- switch (n->type) {
- case NodeKey:
- break;
- case NodeArr:
- arr = (struct ArrNode *)n;
- for (i = arr->min; i <= arr->max; i++)
- if (arr->arr[i - arr->min])
- teardown(arr->arr[i - arr->min]);
- break;
- default:
- return;
- }
-
- free(n);
-}
-
-static
-int
-insert(Node *root, Node *n, char *seq)
-{
- int pos;
- uchar b;
- Node *nn;
- struct ArrNode *a;
-
- for (pos = 0; (b = seq[pos]); pos++) {
- nn = nlookup(root, b);
- if (!nn)
- break;
- root = nn;
- a = (struct ArrNode *)root;
- }
-
- for (; (b = seq[pos]); pos++) {
- nn = (seq[pos+1]) ? arrnode(0, 0xff) : n;
- if (!nn)
- return 0;
-
- if (root->type != NodeArr)
- panicf("inserted child node onto leaf 'key' node");
-
- a = (struct ArrNode*)root;
- if (b < a->min || b > a->max)
- panicf("out of bound trie insertion");
-
- a->arr[b-a->min] = root = nn;
- }
-
- return 1;
-}
-
-/* unibilium helpers */
-static
-enum unibi_string
-nametostr(char *name)
-{
- enum unibi_string ret;
- for (ret = unibi_string_begin_+1; ret < unibi_string_end_; ret++)
- if (!strcmp(unibi_name_str(ret), name))
- return ret;
-
- return -1;
-}
-
-static
-char *
-unibi_lookup(unibi_term *info, char *name)
-{
- enum unibi_string idx;
- if ((idx = nametostr(name)) == -1)
- return nil;
-
- return (char*)unibi_get_str(info, idx);
-}
-
-static
-Node *
-tryloadkey(unibi_term *info, char *name, char **val, struct KeyInfo *key)
-{
- char *v;
-
- v = unibi_lookup(info, name);
- if (!v || v[0] == 0)
- return nil;
-
- *val = v;
- return keynode(key->type, key->sym, key->modmask, key->modset);
-}
-
-static
-Node *
-loadtermkeys(unibi_term *info)
-{
- int i;
- struct Node *root, *n;
- char *val, name[5 + FuncNameMax + 1];
-
- root = arrnode(0, 0xff);
- if (!root)
- panicf("out of memory");
-
- /* load key syms */
- for (i = 0; funcs[i].name; i++) {
- sprintf(name, "key_%s", funcs[i].name);
- n = tryloadkey(info, name, &val, &(struct KeyInfo){
- .type = funcs[i].type,
- .sym = funcs[i].sym,
- .modmask = funcs[i].mods,
- .modset = funcs[i].mods,
- });
-
- /* try shift modified */
- if (!n)
- n = tryloadkey(info, name, &val, &(struct KeyInfo){
- .type = funcs[i].type,
- .sym = funcs[i].sym,
- .modmask = funcs[i].mods | ModShift,
- .modset = funcs[i].mods | ModShift,
- });
-
- /* give up */
- if (n)
- insert(root, n, val);
- }
-
- /* load function keys */
- for (i = 1; i < 0xff; i++) {
- sprintf(name, "key_f%d", i);
- n = tryloadkey(info, name, &val, &(struct KeyInfo){
- .type = KeyFunc,
- .sym = i,
- .modmask = 0,
- .modset = 0,
- });
- if (!n)
- break;
-
- insert(root, n, val);
- }
-
- /* load mouse keys */
- val = unibi_lookup(info, "key_mouse");
- if (val && !strcmp(val, "\x1b[M")) {
- n = keynode(KeyMouse, 0, 0, 0);
- insert(root, n, val);
- }
-
- return compress(root);
-}
-
-static
-enum KeyEvent
-peeksym(Input *in, Key *key, int force, ulong *nb)
-{
- int res;
- uchar *b, *o;
- Node *root;
- struct KeyNode *kn;
-
- root = in->keys;
- b = in->buf.b;
- while (b <= in->buf.c) {
- printf("checking '%s'\n", b);
- root = nlookup(root, *b);
- if (!root)
- break;
- b++;
-
- if (root->type != NodeKey)
- continue;
-
- kn = (struct KeyNode*)root;
- if (kn->key.type == KeyMouse) {
- o = in->buf.b, in->buf.b = b;
- res = peekmousekey(in, key, nb);
- in->buf.b = o;
-
- if (res == EvKey)
- *nb += b - in->buf.b;
-
- return res;
- }
- key->type = kn->key.type;
- key->mods = kn->key.modset;
- key->code.sym = kn->key.type;
- *nb = b - in->buf.b;
-
- return EvKey;
- }
-
- if (root && !force)
- return EvAgain;
-
- return EvNil;
-}
-
-// -----------------------------------------------------------------------
-// misc commands
-
-static
-inline
-void
-setpos(Key *key, int row, int col)
-{
- row = MIN(row, 0xfff);
- col = MIN(col, 0xfff);
-
- key->code.mouse[1] = (row & 0x0ff);
- key->code.mouse[2] = (col & 0x0ff);
- key->code.mouse[3] = (row & 0xf00) >> 8 | (col & 0x300) >> 4;
-}
-
-static
-inline
-void
-getpos(Key *key, int *row, int *col)
-{
- if (col)
- *col = ((uchar)key->code.mouse[1] | ((uchar)key->code.mouse[3] & 0x0f) << 8) - 1;
-
- if (row)
- *row = ((uchar)key->code.mouse[2] | ((uchar)key->code.mouse[3] & 0x70) << 4) - 1;
-}
-
-// -----------------------------------------------------------------------
-// csi/ss3 commands
-
-static int csiinit;
-
-static struct KeyInfo ss3[64];
-static char ss3kpalts[64];
-
-static struct KeyInfo csiss3[64];
-static enum KeyEvent (*do_csi[64])(Input *in, Key *key, int cmd, int narg, long *arg);
-
-static struct KeyInfo csifuncs[35];
-
-/* csi/ss3 cmd keys */
-static
-enum KeyEvent
-do_csi_full(Input *in, Key *key, int cmd, int narg, long *arg)
-{
- if(narg > 1 && arg[1] != -1)
- key->mods = arg[1] - 1;
- else
- key->mods = 0;
-
- key->type = csiss3[cmd - 0x40].type;
- key->code.sym = csiss3[cmd - 0x40].sym;
- key->mods &= ~(csiss3[cmd - 0x40].modmask);
- key->mods |= csiss3[cmd - 0x40].modset;
-
- if(key->code.sym == SymUnknown)
- return EvNil;
-
- return EvKey;
-}
-
-static
-void
-put_csi_full(int type, int sym, int modset, int modmask, uchar cmd)
-{
- if(cmd < 0x40 || cmd >= 0x80)
- return;
-
- csiss3[cmd - 0x40].type = type;
- csiss3[cmd - 0x40].sym = sym;
- csiss3[cmd - 0x40].modset = modset;
- csiss3[cmd - 0x40].modmask = modmask;
-
- do_csi[cmd - 0x40] = &do_csi_full;
-}
-
-/* ss3 kpad keys */
-static
-void
-put_ss3_kpalt(int type, int sym, uchar cmd, char kpalt)
-{
- if(cmd < 0x40 || cmd >= 0x80)
- return;
-
- ss3[cmd - 0x40].type = type;
- ss3[cmd - 0x40].sym = sym;
- ss3[cmd - 0x40].modset = 0;
- ss3[cmd - 0x40].modmask= 0;
- ss3kpalts[cmd - 0x40] = kpalt;
-}
-
-/* csi number ~func keys */
-static void emitcodepoint(Input *in, rune r, Key *key);
-
-static
-enum KeyEvent
-do_csi_func(Input *in, Key *key, int cmd, int narg, long *arg)
-{
- if (narg > 1 && arg[1] != -1)
- key->mods = arg[1] - 1;
- else
- key->mods = 0;
-
- key->type = KeySym;
-
- if (arg[0] == 27) {
- int mod = key->mods;
- emitcodepoint(in, (rune)arg[2], key);
- key->mods |= mod;
- } else if (arg[0] >= 0 && arg[0] < arrlen(csifuncs)) {
- key->type = csifuncs[arg[0]].type;
- key->code.sym = csifuncs[arg[0]].sym;
- key->mods &= ~(csifuncs[arg[0]].modmask);
- key->mods |= csifuncs[arg[0]].modset;
- } else
- key->code.sym = SymUnknown;
-
- if (key->code.sym == SymUnknown)
- return EvNil;
-
- return EvKey;
-}
-
-static
-void
-put_csi_func(int type, int sym, int num)
-{
- if(num >= arrlen(csifuncs))
- return;
-
- csifuncs[num].type = type;
- csifuncs[num].sym = sym;
- csifuncs[num].modset = 0;
- csifuncs[num].modmask = 0;
-
- do_csi['~' - 0x40] = &do_csi_func;
-}
-
-/* CSI u extended unicode keys */
-static
-enum KeyEvent
-do_csi_u(Input *in, Key *key, int cmd, int narg, long *arg)
-{
- switch(cmd) {
- case 'u': {
- if(narg > 1 && arg[1] != -1)
- key->mods = arg[1] - 1;
- else
- key->mods = 0;
-
- int mod = key->mods;
- key->type = KeySym;
- emitcodepoint(in, arg[0], key);
- key->mods |= mod;
-
- return EvKey;
- }
- default:
- return EvNil;
- }
-}
-
-/* csi m/M mouse events */
-
-static
-enum KeyEvent
-do_csi_m(Input *in, Key *key, int cmd, int narg, long *arg)
-{
- int initial = cmd >> 8;
- cmd &= 0xff;
-
- switch(cmd) {
- case 'M':
- case 'm':
- break;
- default:
- return EvNil;
- }
-
- // rxvt protocol
- if(!initial && narg >= 3) {
- key->type = KeyMouse;
- key->code.mouse[0] = arg[0];
-
- key->mods = (key->code.mouse[0] & 0x1c) >> 2;
- key->code.mouse[0] &= ~0x1c;
-
- setpos(key, arg[1], arg[2]);
-
- return EvKey;
- }
-
- // SGR protocol
- if(initial == '<' && narg >= 3) {
- key->type = KeyMouse;
- key->code.mouse[0] = arg[0];
-
- key->mods = (key->code.mouse[0] & 0x1c) >> 2;
- key->code.mouse[0] &= ~0x1c;
-
- setpos(key, arg[1], arg[2]);
-
- if(cmd == 'm') // release
- key->code.mouse[3] |= 0x80;
-
- return EvKey;
- }
-
- return EvNil;
-}
-
-/* csi ? R position events */
-
-static
-enum KeyEvent
-do_csi_R(Input *in, Key *key, int cmd, int narg, long *arg)
-{
- switch(cmd) {
- case 'R'|'?'<<8:
- if(narg < 2)
- return EvNil;
- key->type = KeyPosition;
- setpos(key, arg[1], arg[0]);
- return EvKey;
- default:
- return do_csi_full(in, key, cmd, narg, arg);
- }
-}
-
-/* csi $y mode status events */
-
-static
-enum KeyEvent
-do_csi_y(Input *in, Key *key, int cmd, int narg, long *arg)
-{
- switch (cmd) {
- case 'y'|'$'<<16:
- case 'y'|'$'<<16 | '?'<<8:
- if (narg < 2)
- return EvNil;
-
- key->type = KeyModeReport;
- key->code.mouse[0] = (cmd >> 8);
- key->code.mouse[1] = arg[0] >> 8;
- key->code.mouse[2] = arg[0] & 0xff;
- key->code.mouse[3] = arg[1];
- return EvKey;
-
- default:
- return EvNil;
- }
-}
-
-/* parse csi events */
-static
-enum KeyEvent
-parse_csi(Input *in, ulong introlen, ulong *csi_len, ulong *nargs, long args[], unsigned long *commandp)
-{
- ulong csi_end = introlen;
-
- while (csi_end < bufcount(in)) {
- if (in->buf.b[csi_end] >= 0x40 && in->buf.b[csi_end] < 0x80)
- break;
- csi_end++;
- }
-
- if(csi_end >= bufcount(in))
- return EvAgain;
-
- uchar cmd = in->buf.b[csi_end];
- *commandp = cmd;
-
- char present = 0;
- int argi = 0;
-
- ulong p = introlen;
-
- // See if there is an initial byte
- if (in->buf.b[p] >= '<' && in->buf.b[p] <= '?') {
- *commandp |= (in->buf.b[p] << 8);
- p++;
- }
-
- // Now attempt to parse out up number;number;... separated values
- while (p < csi_end) {
- uchar c = in->buf.b[p];
-
- if (c >= '0' && c <= '9') {
- if (!present) {
- args[argi] = c - '0';
- present = 1;
- } else {
- args[argi] = (args[argi] * 10) + c - '0';
- }
- } else if(c == ';') {
- if (!present)
- args[argi] = -1;
- present = 0;
- argi++;
-
- if(argi > 16)
- break;
- } else if (c >= 0x20 && c <= 0x2f) {
- *commandp |= c << 16;
- break;
- }
- p++;
- }
-
- if(present)
- argi++;
-
- *nargs = argi;
- *csi_len = csi_end + 1;
-
- return EvKey;
-}
-
-static
-void
-loadctrlkeys(void)
-{
- int i;
- for(i = 0; i < 64; i++) {
- csiss3[i].sym = SymUnknown;
- ss3[i].sym = SymUnknown;
- ss3kpalts[i] = 0;
- }
-
- for(i = 0; i < arrlen(csifuncs); i++)
- csifuncs[i].sym = SymUnknown;
-
- put_csi_full(KeySym, SymUp, 0, 0, 'A');
- put_csi_full(KeySym, SymDown, 0, 0, 'B');
- put_csi_full(KeySym, SymRight,0, 0, 'C');
- put_csi_full(KeySym, SymLeft, 0, 0, 'D');
- put_csi_full(KeySym, SymBegin,0, 0, 'E');
- put_csi_full(KeySym, SymEnd, 0, 0, 'F');
- put_csi_full(KeySym, SymHome, 0, 0, 'H');
- put_csi_full(KeySym, 1, 0, 0, 'P');
- put_csi_full(KeySym, 2, 0, 0, 'Q');
- put_csi_full(KeySym, 3, 0, 0, 'R');
- put_csi_full(KeySym, 4, 0, 0, 'S');
-
- put_csi_full(KeySym, SymTab, ModShift, ModShift, 'Z');
-
- put_ss3_kpalt(KeySym, SymKpenter, 'M', 0);
- put_ss3_kpalt(KeySym, SymKpequals, 'X', '=');
- put_ss3_kpalt(KeySym, SymKpmult, 'j', '*');
- put_ss3_kpalt(KeySym, SymKpplus, 'k', '+');
- put_ss3_kpalt(KeySym, SymKpcomma, 'l', ',');
- put_ss3_kpalt(KeySym, SymKpminus, 'm', '-');
- put_ss3_kpalt(KeySym, SymKpperiod, 'n', '.');
- put_ss3_kpalt(KeySym, SymKpdiv, 'o', '/');
- put_ss3_kpalt(KeySym, SymKp0, 'p', '0');
- put_ss3_kpalt(KeySym, SymKp1, 'q', '1');
- put_ss3_kpalt(KeySym, SymKp2, 'r', '2');
- put_ss3_kpalt(KeySym, SymKp3, 's', '3');
- put_ss3_kpalt(KeySym, SymKp4, 't', '4');
- put_ss3_kpalt(KeySym, SymKp5, 'u', '5');
- put_ss3_kpalt(KeySym, SymKp6, 'v', '6');
- put_ss3_kpalt(KeySym, SymKp7, 'w', '7');
- put_ss3_kpalt(KeySym, SymKp8, 'x', '8');
- put_ss3_kpalt(KeySym, SymKp9, 'y', '9');
-
- put_csi_func(KeySym, SymFind, 1);
- put_csi_func(KeySym, SymInsert, 2);
- put_csi_func(KeySym, SymDelete, 3);
- put_csi_func(KeySym, SymSelect, 4);
- put_csi_func(KeySym, SymPageup, 5);
- put_csi_func(KeySym, SymPagedown, 6);
- put_csi_func(KeySym, SymHome, 7);
- put_csi_func(KeySym, SymEnd, 8);
-
- put_csi_func(KeyFunc, 1, 11);
- put_csi_func(KeyFunc, 2, 12);
- put_csi_func(KeyFunc, 3, 13);
- put_csi_func(KeyFunc, 4, 14);
- put_csi_func(KeyFunc, 5, 15);
- put_csi_func(KeyFunc, 6, 17);
- put_csi_func(KeyFunc, 7, 18);
- put_csi_func(KeyFunc, 8, 19);
- put_csi_func(KeyFunc, 9, 20);
- put_csi_func(KeyFunc, 10, 21);
- put_csi_func(KeyFunc, 11, 23);
- put_csi_func(KeyFunc, 12, 24);
- put_csi_func(KeyFunc, 13, 25);
- put_csi_func(KeyFunc, 14, 26);
- put_csi_func(KeyFunc, 15, 28);
- put_csi_func(KeyFunc, 16, 29);
- put_csi_func(KeyFunc, 17, 31);
- put_csi_func(KeyFunc, 18, 32);
- put_csi_func(KeyFunc, 19, 33);
- put_csi_func(KeyFunc, 20, 34);
-
- do_csi['u' - 0x40] = &do_csi_u;
- do_csi['M' - 0x40] = &do_csi_m;
- do_csi['m' - 0x40] = &do_csi_m;
- do_csi['R' - 0x40] = &do_csi_R;
-
- do_csi['y' - 0x40] = &do_csi_y;
-
- csiinit = 1;
-}
-
-static
-enum KeyEvent
-peekcsi(Input *in, ulong introlen, Key *key, int force, ulong *nb)
-{
- ulong csi_len;
- long arg[16];
- ulong nargs = arrlen(arg);
- ulong cmd;
-
- enum KeyEvent ev = parse_csi(in, introlen, &csi_len, &nargs, arg, &cmd);
-
- if (ev== EvAgain) {
- if(!force)
- return ev;
-
- emitcodepoint(in, '[', key);
- key->mods |= ModAlt;
- *nb = introlen;
- return EvKey;
- }
- // Mouse in X10 encoding consumes the next 3 bytes also
- if (cmd == 'M' && nargs < 3) {
- in->buf.b += csi_len;
- ev = peekmousekey(in, key, nb);
- in->buf.b -= csi_len;
-
- if (ev == EvKey)
- *nb += csi_len;
-
- return ev;
- }
-
- ev = EvNil;
-
- // We know from the logic above that cmd must be >= 0x40 and < 0x80
- if (do_csi[(cmd & 0xff) - 0x40])
- ev = (*do_csi[(cmd & 0xff) - 0x40])(in, key, cmd, nargs, arg);
-
- if (ev == EvNil) {
- key->type = KeyUnknownCSI;
- key->code.num = cmd;
- key->mods = 0;
-
- in->buf.off = csi_len - introlen;
- *nb = introlen; /* dont advance yet */
- return EvKey;
- }
-
- *nb = csi_len;
- return ev;
-}
-
-static
-enum KeyEvent
-peekss3(Input *in, ulong introlen, Key *key, int force, ulong *nb)
-{
- if(bufcount(in) < introlen + 1) {
- if(!force)
- return EvAgain;
-
- emitcodepoint(in, 'O', key);
- key->mods |= ModAlt;
- *nb= bufcount(in);
- return EvKey;
- }
- uchar cmd = in->buf.b[introlen];
-
- if(cmd < 0x40 || cmd >= 0x80)
- return EvNil;
-
- key->type = csiss3[cmd - 0x40].type;
- key->code.sym = csiss3[cmd - 0x40].sym;
- key->mods = csiss3[cmd - 0x40].modset;
-
- if (key->code.sym == SymUnknown) {
- if (in->flags & FlagConvertKP && ss3kpalts[cmd - 0x40]) {
- key->type = KeyUnicode;
- key->code.pt = ss3kpalts[cmd - 0x40];
- key->mods = 0;
-
- key->utf8[0] = key->code.pt;
- key->utf8[1] = 0;
- } else {
- key->type = ss3[cmd - 0x40].type;
- key->code.sym = ss3[cmd - 0x40].sym;
- key->mods = ss3[cmd - 0x40].modset;
- }
- }
-
- if(key->code.sym == SymUnknown)
- return EvNil;
-
- *nb = introlen + 1;
-
- return EvKey;
-}
-
-static
-enum KeyEvent
-peekctrl(Input *in, ulong introlen, Key *key, int force, ulong *nb)
-{
- ulong str_end = introlen;
-
- while(str_end < bufcount(in)) {
- if (in->buf.b[str_end] == 0x9c) // ST
- break;
- if (in->buf.b[str_end] == 0x1b &&
- (str_end + 1) < bufcount(in) &&
- in->buf.b[str_end+1] == 0x5c) // ESC-prefixed ST
- break;
-
- str_end++;
- }
-
- if (str_end >= bufcount(in))
- return EvAgain;
-
- *nb = str_end + 1;
- if(in->buf.b[str_end] == 0x1b)
- (*nb)++;
-
- // XXX: read carefully
- if(in->savedcsi)
- free(in->savedcsi);
-
- ulong len = str_end - introlen;
-
- in->nsavedcsi++;
- in->savedcsi = malloc(len + 1);
-
- strncpy(in->savedcsi, (char *)in->buf.b + introlen, len);
- in->savedcsi[len] = 0;
-
- key->type = (in->buf.b[introlen-1] & 0x1f) == 0x10 ? KeyDCS : KeyOSC;
- key->code.num = in->nsavedcsi;
- key->mods = 0;
-
- return EvKey;
-}
-
-static
-enum KeyEvent
-peekesc(Input *in, Key *key, int force, ulong *nb)
-{
- if (bufcount(in) == 0)
- return in->closed ? EvEOF : EvNil;
-
- switch (*in->buf.b) {
- case 0x1b:
- if(bufcount(in) < 2)
- return EvNil;
-
- switch(in->buf.b[1]) {
- case 0x4f: // ESC-prefixed SS3
- return peekss3(in, 2, key, force, nb);
-
- case 0x50: // ESC-prefixed DCS
- case 0x5d: // ESC-prefixed OSC
- return peekctrl(in, 2, key, force, nb);
-
- case 0x5b: // ESC-prefixed CSI
- return peekcsi(in, 2, key, force, nb);
- }
-
- return EvNil;
-
- case 0x8f: // SS3
- return peekss3(in, 1, key, force, nb);
-
- case 0x90: // DCS
- case 0x9d: // OSC
- return peekctrl(in, 1, key, force, nb);
-
- case 0x9b: // CSI
- return peekcsi(in, 1, key, force, nb);
- }
-
- return EvNil;
-}
-
-
-// -----------------------------------------------------------------------
-// internal functions
-
-static
-int
-registername(Input *in, int sym, char *name)
-{
- if (!sym)
- sym = in->nkeynm;
-
- if(sym >= in->nkeynm) {
- char **tmp = realloc(in->keynm, sizeof(*tmp) * (sym + 1));
- if(!tmp)
- return -1;
-
- in->keynm = tmp;
-
- // Fill in the hole
- for(int i = in->nkeynm; i < sym; i++)
- in->keynm[i] = nil;
-
- in->nkeynm = sym + 1;
- }
-
- in->keynm[sym] = name;
-
- return sym;
-}
-
-static
-int
-registerc0(Input *in, int sym, int modset, int modmask, uchar ctrl, char *name)
-{
- if(ctrl >= 0x20) {
- errno = EINVAL;
- return -1;
- }
-
- if (name)
- sym = registername(in, sym, name);
-
- in->c0[ctrl].sym = sym;
- in->c0[ctrl].modset = modset;
- in->c0[ctrl].modmask = modmask;
-
- return sym;
-}
-
-static
-void
-advance(Input *in, ulong nb)
-{
- if (in->buf.c < in->buf.b + nb) {
- in->buf.b = in->buf.c;
- return;
- }
-
- in->buf.b += nb;
-}
-
-static
-void
-slidebuffer(Input *in)
-{
- static const ulong halfway = arrlen(in->buf.bytes) / 2;
- if (in->buf.b - in->buf.bytes > halfway) {
- memmove(in->buf.bytes, in->buf.bytes + halfway, halfway);
- in->buf.b -= halfway;
- in->buf.c -= halfway;
- }
-}
-
-static
-void
-harmonize(Input *in, Key *key)
-{
- int flags = in->hflag;
-
- if (flags & HarmonizeSpace) {
- if (key->type == KeyUnicode && key->code.pt == 0x20) {
- key->type = KeySym;
- key->code.sym = SymSpace;
- }
- } else {
- if (key->type == KeySym && key->code.sym == SymSpace) {
- key->type = KeyUnicode;
- key->code.pt = 0x20;
- utf8·runetobyte((char*)key->utf8, &key->code.pt);
- }
- }
-
- if (flags & HarmonizeDelBS) {
- if (key->type == KeySym && key->code.sym == SymDel) {
- key->code.sym = SymBackspace;
- }
- }
-}
-
-static
-void
-emitcodepoint(Input *in, rune r, Key *key)
-{
- if (r == 0) {
- key->type = KeySym;
- key->code.sym = SymSpace;
- key->mods = ModCtrl;
- goto harmonize;
- }
- if (r < 0x20) {
- key->code.pt = 0;
- key->mods = 0;
- if (!(in->flags & FlagNoInterpret) && in->c0[r].sym != SymUnknown) {
- key->code.sym = in->c0[r].sym;
- key->mods |= in->c0[r].modset;
- }
- if (!key->code.sym) {
- key->type = KeyUnicode;
- if (r+0x40 >= 'A' && r+0x40 <= 'Z')
- // it's a letter - use lowercase instead
- key->code.pt = r + 0x60;
- else
- key->code.pt = r + 0x40;
- key->mods = ModCtrl;
- } else
- key->type = KeySym;
- goto harmonize;
- }
- if (r == 0x7f && !(in->flags & FlagNoInterpret)) {
- // ascii del
- key->type = KeySym;
- key->code.sym = SymDel;
- key->mods = 0;
- goto harmonize;
- }
- if (r >= 0x20 && r < 0x80) {
- // ascii lowbyte range
- key->type = KeyUnicode;
- key->code.pt = r;
- key->mods = 0;
- goto harmonize;
- }
- if (r >= 0x80 && r < 0xa0) {
- // UTF-8 never starts with a C1 byte. So we can be sure of these
- key->type = KeyUnicode;
- key->code.pt = r - 0x40;
- key->mods = ModCtrl|ModAlt;
- goto harmonize;
- }
- key->type = KeyUnicode;
- key->code.pt = r;
- key->mods = 0;
-
-harmonize:
- harmonize(in, key);
- utf8·runetobyte((char*)key->utf8, &key->code.pt);
-}
-
-static
-enum KeyEvent
-peekmousekey(Input *in, Key *key, ulong *nb)
-{
- if (in->buf.c - in->buf.b < 3)
- return EvAgain;
-
- key->type = KeyMouse;
- key->code.mouse[0] = in->buf.c[0] - 0x20;
- key->code.mouse[1] = in->buf.c[1] - 0x20;
- key->code.mouse[2] = in->buf.c[2] - 0x20;
- key->code.mouse[3] = 0;
-
- key->mods = (key->code.mouse[0] & 0x1c) >> 2;
- key->code.mouse[0] &= ~0x1c;
-
- *nb = 3;
- return EvKey;
-}
-
-enum KeyEvent peekkey(Input *in, Key *key, int force, ulong *nb);
-
-static
-enum KeyEvent
-peeksimplekey(Input *in, Key *key, int force, ulong *nb)
-{
- uchar c, *b;
- int n;
- rune r;
- enum KeyEvent ev;
-
- b = in->buf.b;
- c = *b;
-
- if (c == 0x1b) {
- if (bufcount(in) == 1) {
- if (!force)
- return EvAgain;
- goto ascii;
- }
- in->buf.b++;
- ev = peekkey(in, key, force, nb);
- in->buf.b--;
-
- switch (ev) {
- case EvKey:
- key->mods |= ModAlt;
- (*nb)++;
- /* fallthrough */
- case EvNil: case EvEOF:
- case EvAgain: case EvErr:
- return ev;
- }
- }
- if (c == 0xa0)
- goto ascii;
- if (in->flags & FlagUTF8) {
- n = utf8·bytetorune(&r, (char*)in->buf.b);
- *nb = n; /* store the number of bytes */
- if (n > bufcount(in)) {
- if (!force)
- return EvAgain;
- r = RuneErr;
- *nb = bufcount(in);
- }
- key->type = KeyUnicode;
- key->mods = 0;
- goto utf8;
- }
- /* if we are here just emit raw byte */
- key->type = KeyUnicode;
- key->code.pt = c;
- key->mods = 0;
- key->utf8[0] = c;
- key->utf8[1] = 0;
- *nb = 1;
- return EvKey;
-
-ascii:
- *nb = 1;
- r = c;
-utf8:
- emitcodepoint(in, r, key);
- return EvKey;
-}
-
-// -----------------------------------------------------------------------
-// exported functions
-
-Input *
-makeinput(int fd, int flags, unibi_term *info)
-{
- int i;
- Input *in;
- char *e;
-
- if (!(in = malloc(sizeof(in))))
- panicf("out of memory");
-
- in->fd = fd;
- if (!(flags & (FlagRaw|FlagUTF8))) {
- if (((e = getenv("LANG")) || (e = getenv("LC_MESSAGES")) || (e = getenv("LC_ALL"))) &&
- (e = strchr(e, '.')) && e++ && (!stricmp(e, "UTF-8") || !stricmp(e, "UTF8")))
- flags |= FlagUTF8;
- else
- flags |= FlagRaw;
- }
- in->flags = flags;
- in->wait = 50; /* in msec */
- in->closed = 0;
- in->started = 0;
- in->hasold = 0;
- in->keys = loadtermkeys(info);
-
- /* initialize buffer */
- in->buf.c = in->buf.b = in->buf.bytes;
- in->buf.e = arrend(in->buf.bytes);
- in->buf.off = 0;
- memset(in->buf.bytes, 0, arrlen(in->buf.bytes));
-
- /* initialize names */
- for (i = 0; i < 32; i++)
- in->c0[i].sym = SymNone;
-
- registerc0(in, SymTab, 0x09, 0, 0, nil);
- registerc0(in, SymEnter, 0x0d, 0, 0, nil);
- registerc0(in, SymEscape, 0x1b, 0, 0, nil);
-
- /* load in csi */
- in->nsavedcsi = 0;
- in->savedcsi = nil;
- loadctrlkeys();
-
- return in;
-}
-
-void
-freeinput(Input *in)
-{
- // free(in);
-}
-
-int
-startrecord(Input *in)
-{
- struct termios new;
- if (in->started)
- return 1;
-
- if (in->fd != -1 && !(in->flags & FlagNoTermIOS)) {
- if (tcgetattr(in->fd, &new) == 0) {
- in->oldterm = new;
- in->hasold = 1;
-
- new.c_iflag &= ~(IXON|INLCR|ICRNL);
- new.c_lflag &= ~(ICANON|ECHO|IEXTEN);
-
- new.c_cc[VMIN] = 1;
- new.c_cc[VTIME] = 0;
-
- if (in->flags & FlagCtrlC)
- new.c_lflag &= ~ISIG;
- else {
- /* Disable Ctrl-\==VQUIT and Ctrl-D==VSUSP but leave Ctrl-C as SIGINT */
- new.c_cc[VQUIT] = _POSIX_VDISABLE;
- new.c_cc[VSUSP] = _POSIX_VDISABLE;
- /* Some OSes have Ctrl-Y==VDSUSP */
-# ifdef VDSUSP
- new.c_cc[VDSUSP] = _POSIX_VDISABLE;
-# endif
- }
- tcsetattr(in->fd, TCSANOW, &new);
- }
- }
-
- in->started = 1;
- return 1;
-}
-
-int
-stoprecord(Input *in)
-{
- if (!in->started)
- return 1;
-
- if (in->hasold)
- tcsetattr(in->fd, TCSANOW, &in->oldterm);
-
- in->started = 0;
- return 1;
-}
-
-enum KeyEvent
-peekkey(Input *in, Key *key, int force, ulong *nb)
-{
- int i, again = 0;
- enum KeyEvent ev;
- static enum KeyEvent (*peek[2])(Input *, Key *, int, ulong *) = { peeksym, peekesc };
-
- if (!in->started) {
- errno = EINVAL;
- return EvErr;
- }
-
- if (in->buf.off) {
- in->buf.b += in->buf.off;
- in->buf.off = 0;
- }
-
- for (i = 0; i < arrlen(peek); i++) {
- ev = peek[i](in, key, force, nb);
- switch (ev) {
- case EvKey:
- slidebuffer(in);
- /* fallthrough */
- case EvEOF:
- case EvErr:
- return ev;
- case EvAgain:
- if (!force)
- again = 1;
- /* fallthrough */
- case EvNil:
- continue;
- }
- }
- if (again)
- return EvAgain;
-
- return peeksimplekey(in, key, force, nb);
-}
-
-enum KeyEvent
-getkey(Input *in, Key *key)
-{
- ulong nb;
- enum KeyEvent ev;
-
- ev = peekkey(in, key, 0, &nb);
- switch (ev) {
- case EvKey:
- advance(in, nb);
- break;
- case EvAgain:
- peekkey(in, key, 1, &nb);
- /* get nb but don't advance */
- break;
- default:
- ;
- }
- return ev;
-}
-
-enum KeyEvent
-demandkey(Input *in, Key *key)
-{
- ulong nb;
- enum KeyEvent ev;
-
- ev = peekkey(in, key, 1, &nb);
- if (ev == EvKey)
- advance(in, nb);
-
- return ev;
-}
-
-enum KeyEvent
-isreadablekey(Input *in)
-{
- int n;
- if (in->fd == -1) {
- errno = EBADF;
- return EvErr;
- }
-
- /* reset to beginning of buffer */
- if (in->buf.b > in->buf.bytes) {
- n = in->buf.b - in->buf.bytes;
- memmove(in->buf.bytes, in->buf.b, n);
- in->buf.b = in->buf.bytes;
- in->buf.c = in->buf.b + n;
- }
-
-read:
- n = read(in->fd, in->buf.c, in->buf.e-in->buf.c);
- if (n == -1) {
- if (errno == EAGAIN)
- return EvNil;
- if (errno == EINTR && !(in->flags & FlagEintr))
- goto read;
- else
- return EvErr;
- }
- if (n < 1) {
- in->closed = 1;
- return EvNil;
- }
- in->buf.c += n;
- return EvAgain;
-}
-
-enum KeyEvent
-waitkey(Input *in, Key *key)
-{
- enum KeyEvent ev;
- struct pollfd p;
-
- if (in->fd == -1) {
- errno = EBADF;
- return EvErr;
- }
-
- for (;;) {
- ev = getkey(in, key);
- switch (ev) {
- case EvKey: case EvEOF: case EvErr:
- return ev;
- case EvNil:
- ev = isreadablekey(in);
- if (ev == EvErr)
- return ev;
- break;
-
- case EvAgain:
- /* can't wait any longer */
- if (in->closed)
- return demandkey(in, key);
- poll:
- p.fd = in->fd;
- p.events = POLLIN;
-
- if (poll(&p, 1, in->wait) == -1) {
- if (errno == EINTR && !(in->flags & FlagEintr))
- goto poll;
- return EvErr;
- }
-
- if (p.revents & (POLLIN|POLLHUP|POLLERR))
- ev = isreadablekey(in);
- else
- ev = EvNil;
-
- if (ev == EvErr)
- return ev;
- if (ev == EvNil)
- return demandkey(in, key);
- break;
- }
- }
- /* unreachable */
-}
-
-enum KeyEvent
-decodemouse(Input *in, Key *key, enum MouseEvent *ev, int *button, int *row, int *col)
-{
- if(key->type != KeyMouse)
- return EvNil;
-
- if(button)
- *button = 0;
-
- getpos(key, row, col);
-
- if(!ev)
- return EvKey;
-
- int btn = 0;
- int code = key->code.mouse[0];
- int drag = code & 0x20;
- code &= ~0x3c;
-
- switch(code) {
- case 0:
- case 1:
- case 2:
- *ev = drag ? MouseDrag : MousePress;
- btn = code + 1;
- break;
-
- case 3:
- *ev = MouseRelease;
- // no button hint
- break;
-
- case 64:
- case 65:
- *ev = drag ? MouseDrag : MousePress;
- btn = code + 4 - 64;
- break;
-
- default:
- *ev = MouseNil;
- }
-
- if (button)
- *button = btn;
-
- if (key->code.mouse[3] & 0x80)
- *ev = MouseRelease;
-
- return EvKey;
-}
-
-enum KeyEvent
-decodepos(Input *in, Key *key, int *row, int *col)
-{
- if (key->type != KeyPosition)
- return EvNil;
-
- getpos(key, row, col);
-
- return EvKey;
-}
-
-enum KeyEvent
-decodemode(Input *in, Key *key, int *init, int *mode, int *val)
-{
- if (key->type != KeyModeReport)
- return EvNil;
-
- if (init)
- *init = key->code.mouse[0];
-
- if (mode)
- *mode = (key->code.mouse[1] << 8) | key->code.mouse[2];
-
- if (val)
- *val = key->code.mouse[3];
-
- return EvKey;
-}
-
-char *
-keyname(Input *in, int sym)
-{
- if (sym == SymUnknown || sym >= in->nkeynm)
- return "<unknown>";
-
- return in->keynm[sym];
-}
-
-// -----------------------------------------------------------------------
-// main point of entry
-
-static
-void
-printkey(Input *in, Key *key)
-{
- enum MouseEvent ev;
- int button, line, col;
- int init, mode, val;
-
- switch(key->type) {
- case KeyUnicode:
- fprintf(stderr, "Unicode codepoint=U+%04dx utf8='%s'", key->code.pt, key->utf8);
- break;
- case KeyFunc:
- fprintf(stderr, "Function F%d", key->code.num);
- break;
- case KeySym:
- fprintf(stderr, "Keysym sym=%d(%s)", key->code.sym, keyname(in, key->code.sym));
- break;
- case KeyMouse:
- decodemouse(in, key, &ev, &button, &line, &col);
- fprintf(stderr, "Mouse ev=%d button=%d pos=(%d,%d)\n", ev, button, line, col);
- break;
- case KeyPosition:
- decodepos(in, key, &line, &col);
- fprintf(stderr, "Position report pos=(%d,%d)\n", line, col);
- break;
- case KeyModeReport:
- decodemode(in, key, &init, &mode, &val);
- fprintf(stderr, "Mode report mode=%s %d val=%d\n", init == '?' ? "DEC" : "ANSI", mode, val);
- break;
- case KeyDCS:
- fprintf(stderr, "Device Control String");
- break;
- case KeyOSC:
- fprintf(stderr, "Operating System Control");
- break;
- case KeyUnknownCSI:
- fprintf(stderr, "unknown CSI\n");
- break;
- }
-
- mode = key->mods;
- fprintf(stderr, " mod=%s%s%s+%02x",
- (mode & ModCtrl ? "<C>" : ""),
- (mode & ModAlt ? "<A>" : ""),
- (mode & ModShift? "<S>" : ""),
- mode & ~(ModCtrl|ModAlt|ModShift));
-}
-
-int
-main()
-{
- char *name;
- Input *in;
- unibi_term *info;
- Key key;
- enum KeyEvent ev;
-
- name = getenv("TERM");
- info = unibi_from_term(name);
- in = makeinput(0, FlagSpaceSymbol, info);
-
- int n = 0; /* for debugging purposes only */
- startrecord(in);
- while ((ev = waitkey(in, &key)) != EvEOF) {
- switch (ev) {
- case EvKey:
- printkey(in, &key);
- printf("\n");
- break;
- case EvNil:
- printf("<nil>\n");
- case EvAgain:
- printf("<again>\n");
- default:
- ;
- }
- n++;
- if (n > 200)
- break;
- }
- stoprecord(in);
- freeinput(in);
-}