libk8sterm: rewritten ESC sequences parsing (some code cleanups, on-the-fly parsing...
[k8sterm.git] / src / x11evtkbd.c
blobc2b1bc9d8e1d1132dd5724c7d668315422eebe6c
1 ////////////////////////////////////////////////////////////////////////////////
2 // keyboard mapping
3 static const char *kmap (KeySym k, uint32_t state) {
4 const char *res = NULL;
5 //
6 state &= ~Mod2Mask; // numlock
7 for (int f = 0; f < keymap_used; ++f) {
8 uint32_t mask = keymap[f].mask;
9 //
10 if (keymap[f].key == k && ((mask == XK_NO_MOD && !state) || state == mask)) {
11 //fprintf(stderr, "kp: %d\n", K8T_ISSET(curterm, term, K8T_MODE_APPKEYPAD));
12 if (!K8T_ISSET(curterm, K8T_MODE_APPKEYPAD)) {
13 if (!keymap[f].kp) {
14 //fprintf(stderr, "nokp! %d %s\n", keymap[f].kp, keymap[f].str+1);
15 return keymap[f].str; // non-keypad hit
17 continue;
19 //fprintf(stderr, "kp! %d %s\n", keymap[f].kp, keymap[f].str+1);
20 if (keymap[f].kp) return keymap[f].str; // keypad hit
21 res = keymap[f].str; // kp mode, but non-kp mapping found
24 return res;
28 static const char *kbind (KeySym k, uint32_t state) {
29 state &= ~Mod2Mask; // numlock
30 for (int f = 0; f < keybinds_used; ++f) {
31 uint32_t mask = keybinds[f].mask;
33 if (keybinds[f].key == k && ((mask == XK_NO_MOD && !state) || state == mask)) return keybinds[f].str;
35 return NULL;
39 static KeySym do_keytrans (KeySym ks) {
40 for (int f = 0; f < keytrans_used; ++f) if (keytrans[f].src == ks) return keytrans[f].dst;
41 return ks;
45 static void cmdline_closequeryexec (K8Term *term, K8TCmdLine *cmdline, int cancelled) {
46 if (!cancelled) {
47 char *rep = cmdline->cmdline+cmdline->cmdreslen;
49 trimstr(rep);
50 if (rep[0] && (tolower(rep[0]) == 'y' || tolower(rep[0]) == 't')) {
51 closeRequestComes = 2;
52 return;
55 closeRequestComes = 0;
59 static void eskdump (const char *kstr) {
60 if (kstr != NULL && kstr[0]) {
61 if (K8T_ISSET(curterm, K8T_MODE_APPKEYPAD)) fprintf(stderr, "<KP>");
62 while (*kstr) {
63 uint32_t c = (uint32_t)(*kstr++);
65 if (c != 32 && isprint(c)) fputc(c, stderr);
66 else if (c == '\n') fprintf(stderr, "(\\n)");
67 else if (c == '\r') fprintf(stderr, "(\\r)");
68 else if (c == 0x1b) fprintf(stderr, "(^[)");
69 else fprintf(stderr, "(%u)", c);
72 fputc('\n', stderr);
76 static void xevtcbkpress (XEvent *ev) {
77 XKeyEvent *e = &ev->xkey;
78 KeySym ksym = NoSymbol;
79 const char *kstr;
80 int len;
81 Status status;
82 char buf[32];
84 if (curterm == NULL) return;
86 if (!ptrBlanked && opt_ptrblank > 0) xblankPointer();
88 //if (len < 1) len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
89 if ((len = Xutf8LookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status)) > 0) buf[len] = 0;
90 // leave only known mods
91 e->state &= (Mod1Mask|Mod4Mask|ControlMask|ShiftMask);
92 //#define DUMP_KEYSYMS
93 #ifdef DUMP_KEYSYMS
95 const char *ksname = XKeysymToString(ksym);
96 fprintf(stderr, "utf(%d):[%s] (%s) 0x%08x\n", len, len>=0?buf:"<shit>", ksname, (unsigned int)e->state);
98 #endif
99 if ((kstr = kbind(ksym, e->state)) != NULL) {
100 // keybind found
101 executeCommands(kstr);
102 return;
105 if (K8T_DATA(curterm)->cmdline.cmdMode != K8T_CMDMODE_NONE) {
106 if (tcmdlProcessKeys(curterm, &K8T_DATA(curterm)->cmdline, do_keytrans(ksym), buf, len, e)) return;
109 if ((kstr = kmap(do_keytrans(ksym), e->state)) != NULL) {
112 const char *ksname = XKeysymToString(ksym);
113 fprintf(stderr, "0x%04x*0x%04x: utf(%d):[%s] (%s) 0x%08x\n", (unsigned)ksym, (unsigned)do_keytrans(ksym), len, len>=0?buf:"<shit>", ksname, (unsigned int)e->state);
114 fprintf(stderr, " slen=%u", strlen(kstr));
115 for (const char *p = kstr; *p; ++p) {
116 if (*p <= ' ' || *p == 127) fprintf(stderr, " {%u}", (unsigned)*p); else fprintf(stderr, " {%c}", (char)*p);
118 fprintf(stderr, "\n");
121 if (kstr[0]) {
122 k8t_tmUnshowHistory(curterm);
123 if (curterm->dumpeskeys) {
124 if (!isprint(kstr[0]) || kstr[1]) {
125 fprintf(stderr, "KEY: ");
126 eskdump(kstr);
129 k8t_ttyWriteStr(curterm, kstr);
131 } else {
132 int meta = (e->state&Mod1Mask);
133 int shift = (e->state&ShiftMask);
134 //int ctrl = (e->state&ControlMask);
136 if (K8T_DATA(curterm)->waitkeypress) {
137 switch (ksym) {
138 case XK_Return:
139 case XK_KP_Enter:
140 case XK_space:
141 case XK_Escape:
142 K8T_DATA(curterm)->waitkeypress = 0;
143 curterm->dead = 1;
144 if (xw.paste_term == curterm) xw.paste_term = NULL;
145 break;
147 } else {
148 switch (ksym) {
149 case XK_Return:
150 k8t_tmUnshowHistory(curterm);
151 if (meta) {
152 k8t_ttyWriteStr(curterm, "\x1b\x0a");
153 } else {
154 if (K8T_ISSET(curterm, K8T_MODE_CRLF)) k8t_ttyWriteStr(curterm, "\r\n"); else k8t_ttyWriteStr(curterm, "\r");
156 break;
157 default:
158 if (!curterm->dead && len > 0) {
159 k8t_tmUnshowHistory(curterm);
160 KeySym ksx = (meta ? XLookupKeysym(e, 0) : NoSymbol);
161 if (meta && ((ksx >= 'A' && ksx <= 'Z') || (ksx >= 'a' && ksx <= 'z'))) {
162 // alt+key: ignore current xcb language
163 // but with shift key we have to transform case
164 if (shift) {
165 if (ksx >= 'a' && ksx <= 'z') ksx -= 32; // upcase
166 } else {
167 if (ksx >= 'A' && ksx <= 'Z') ksx += 32; // locase
169 buf[0] = '\x1b';
170 buf[1] = ksx;
171 k8t_ttyWrite(curterm, buf, 2);
172 } else {
173 if (meta && len == 1) k8t_ttyWriteStr(curterm, "\x1b");
174 k8t_ttyWrite(curterm, buf, len);
177 break;