I've added support for Key Position Mode, which makes it possible to effectively remap modifier and function keys on some DEC terminals.
>From ab7e813b84dcaf8d13479a662ba0014d25231143 Mon Sep 17 00:00:00 2001 From: Brian Templeton <b...@tunes.org> Date: Tue, 10 Feb 2009 01:33:58 -0500 Subject: [PATCH] Enable Key Position Mode on DEC VT420 terminals. The key mapping (defined in kpm.c) uses a modified Dvorak layout and maps the Lock key to Control. --- src/Makefile.in | 4 +- src/display.c | 34 ++++++++++ src/kpm.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/kpm.h | 4 + 4 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 src/kpm.c create mode 100644 src/kpm.h diff --git a/src/Makefile.in b/src/Makefile.in index c551067..b37c408 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -61,12 +61,12 @@ CFILES= screen.c ansi.c fileio.c mark.c misc.c resize.c socket.c \ search.c tty.c term.c window.c utmp.c loadav.c putenv.c help.c \ termcap.c input.c attacher.c pty.c process.c display.c comm.c \ kmapdef.c acls.c braille.c braille_tsi.c logfile.c layer.c \ - sched.c teln.c nethack.c encoding.c + sched.c teln.c nethack.c encoding.c kpm.c OFILES= screen.o ansi.o fileio.o mark.o misc.o resize.o socket.o \ search.o tty.o term.o window.o utmp.o loadav.o putenv.o help.o \ termcap.o input.o attacher.o pty.o process.o display.o comm.o \ kmapdef.o acls.o braille.o braille_tsi.o logfile.o layer.o \ - sched.o teln.o nethack.o encoding.o + sched.o teln.o nethack.o encoding.o kpm.o all: screen diff --git a/src/display.c b/src/display.c index ec13ec7..6489c62 100644 --- a/src/display.c +++ b/src/display.c @@ -29,6 +29,7 @@ #include <sys/types.h> #include <signal.h> #include <fcntl.h> +#include <string.h> #ifndef sun # include <sys/ioctl.h> #endif @@ -37,6 +38,9 @@ #include "screen.h" #include "extern.h" #include "braille.h" +#include "kpm.h" + +#define ENABLE_KPM_P (strncmp(D_termname, "vt420", 5) == 0) static int CountChars __P((int)); static int DoAddChar __P((int)); @@ -1153,6 +1157,8 @@ int adapt; { ASSERT(display); ASSERT(D_tcinited); + if (ENABLE_KPM_P) + kpm_on(D_userfd); D_top = D_bot = -1; AddCStr(D_TI); AddCStr(D_IS); @@ -1196,6 +1202,8 @@ FinitTerm() #ifdef BLANKER_PRG KillBlanker(); #endif + if (ENABLE_KPM_P) + kpm_off(D_userfd); if (D_tcinited) { ResizeDisplay(D_defwidth, D_defheight); @@ -4040,6 +4048,32 @@ char *data; size -= 5; } } + if (ENABLE_KPM_P) { + char kbuf[IOSIZE]; + int krc, ki, ksize = 0; + char kout[6]; + for (ki = 0; ki < size; ki++) { + krc = kpm_decode(buf[ki]); + if (krc < 0) { + Msg(0, "KPM parsing failed"); + return; + } else if (krc == 0) { + continue; + } else { + krc = kpm_map(kpm_state.pos, kpm_state.mod, kout); + if (krc >= 0) { + memcpy(kbuf+ksize, kout, krc); + ksize += krc; + } + } + } + if (ksize > 0) { + memcpy(buf, kbuf, ksize); + size = ksize; + } else { + return; + } + } #ifdef ENCODINGS if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0)) { diff --git a/src/kpm.c b/src/kpm.c new file mode 100644 index 0000000..c7e3950 --- /dev/null +++ b/src/kpm.c @@ -0,0 +1,195 @@ +#include <string.h> +#include "kpm.h" + +enum { + M_SHIFT_L = 0x01, + M_SHIFT_R = 0x02, + M_LOCK = 0x04, + M_CTRL = 0x08, + M_ALT_L = 0x10, + M_ALT_R = 0x20, + M_COMPOSE_L = 0x40, + M_COMPOSE_R = 0x80 +}; + +/* + * G99: F1 + * G00..G03: F2..F5 + * G05..G09: F6..F10 + * G11..G14: F11..F14 + * G16..G17: Help, Do + * G20..G23: F17..F20 + * E16..E18: Find, Insert Here, Remove + * D16: Select, Prev, Next + * C17: Up + * B16..B18: Left, Down, Right + * E20..E23: PF1..PF4 + * D20..D23: 7, 8, 9, minus + * C20..C23: 4, 5, 6, comma + * B20..B22: 1, 2, 3 + * A20: 0 + * A22..A23: period, Enter + */ + +char* kpm_keys['H'][100] = { + ['A'] = { 0, 0, " " }, + ['B'] = { "<>", ";:", "qQ", "jJ","kK", "xX", + "bB","mM","wW","vV","zZ" }, + ['C'] = { 0, "aA", "oO", "eE", "uU", "iI", + "dD", "hH", "tT", "nN", "sS", "-_", "\\|", "\r\r" }, + ['D'] = { "\t\t", "'\"", ",(", ".)", "pP", "yY", + "fF","gG","cC","rR", "lL", "/?", "=+" }, + ['E'] = { "`~", "1!", "2@", "3#", "4$", "5%", + "6^", "7&", "8*", "9<", "0>", "[{", "]}", "\x7F\x7F" } +}; + +#define CSI "\x1B[" +#define SS3 "\x1BO" +char* kpm_keys_x['H'][100] = { + ['A'] = { [20] = SS3 "p", SS3 "n", SS3 "M" }, + ['B'] = { [16] = SS3 "D", SS3 "B", SS3 "C", + [20] = SS3 "q", SS3 "r", SS3 "s" }, + ['C'] = { [17] = SS3 "A", + [20] = SS3 "t", SS3 "u", SS3 "v", SS3 "l" }, + ['D'] = { [16] = CSI "4~", CSI "5~", CSI "6~", + [20] = SS3 "w", SS3 "x", SS3 "y", SS3 "m" }, + ['E'] = { [16] = CSI "1~", CSI "2~", CSI "3~", + [20] = SS3 "P", SS3 "Q", SS3 "R", SS3 "S" }, + ['G'] = { CSI "12~", CSI "13~", CSI "14~", CSI "15~", 0, + CSI "17~", CSI "18~", CSI "19~", CSI "20~", CSI "21~", 0, + CSI "23~", CSI "24~", CSI "25~", CSI "26~", 0, + CSI "28~", CSI "29~", 0, 0, + CSI "31~", CSI "32~", CSI "33~", CSI "34~", + [99] = CSI "11~" } +}; + +typedef struct { + int state; + char pos[3]; + int mod; + char buf[5]; + int n; +} kpm_state_t; + +kpm_state_t kpm_state; + +int kpm_on(int fd) +{ + kpm_state.state = 0; + write(fd, "\x1B[?81h", 6); +} + +int kpm_off(int fd) +{ + write(fd, "\x1B[?81l", 6); +} + +int kpm_keys_lookup(char pos[3], char **k) +{ + char **r; + int d = 10 * ((int)pos[1] - 48) + ((int)pos[2] - 48); + r = kpm_keys[pos[0]]; + if (!r) + goto ext; + *k = r[d]; + if (!*k) + goto ext; + return 0; + + ext: + r = kpm_keys_x[pos[0]]; + if (!r) + return -1; + *k = r[d]; + if (!*k) + return -1; + return 1; +} + +#define CTRLP(m) ((m & M_CTRL) || (m & M_LOCK)) +#define SHIFTP(m) ((m & M_SHIFT_L) || (m & M_SHIFT_R)) +#define ALTP(m) ((m & M_ALT_L) || (m & M_ALT_R)) +#define UPPER_ALPHA_P(c) (('A' <= c) && (c <= 'Z')) +int kpm_map(char pos[3], int mod, char *out) +{ + char *k, c; + int l; + switch (kpm_keys_lookup(pos, &k)) { + case -1: + return -1; + case 0: + if (CTRLP(mod) && UPPER_ALPHA_P(k[1])) + c = k[1]-'@'; + else if (SHIFTP(mod)) + c = k[1]; + else + c = k[0]; + if (ALTP(mod)) + c |= 0x80; + out[0] = c; + return 1; + case 1: + l = strlen(k); + memcpy(out, k, l); + return l; + } +} + +#define KPM_END(r, next) \ + ({ kpm_state.state = next; return r; }) +#define KPM_NEED(x, next) \ + ({if (c == x) { KPM_END(0, next); } else { return -1; } }) + +int kpm_decode(char c) +{ + switch (kpm_state.state) { + case 0: + KPM_NEED('\x1B', 1); + case 1: + KPM_NEED('_', 2); + case 2: + KPM_NEED(':', 3); + case 3: + kpm_state.buf[0] = c; + kpm_state.n = 1; + KPM_END(0, 4); + case 4: + kpm_state.buf[kpm_state.n++] = c; + if (kpm_state.n == 5) { + kpm_state.pos[0] = kpm_state.buf[0]; + kpm_state.pos[1] = kpm_state.buf[1]; + kpm_state.pos[2] = kpm_state.buf[2]; + kpm_state.mod = (16 * ((int)kpm_state.buf[3] - 48) + + ((int)kpm_state.buf[4] - 48)); + KPM_END(1, 5); + } else { + KPM_END(0, 4); + } + case 5: + switch (c) { + case '\x1B': + KPM_END(0, 6); + case '.': + KPM_END(1, 5); + case '/': + kpm_state.n = 0; + KPM_END(0, 7); + default: + return -1; + } + case 6: + KPM_NEED('\\', 0); + case 7: + kpm_state.buf[kpm_state.n++] = c; + if (kpm_state.n == 3) { + kpm_state.pos[0] = kpm_state.buf[0]; + kpm_state.pos[1] = kpm_state.buf[1]; + kpm_state.pos[2] = kpm_state.buf[2]; + KPM_END(1, 5); + } else { + KPM_END(0, 7); + } + default: + return -1; + } +} diff --git a/src/kpm.h b/src/kpm.h new file mode 100644 index 0000000..61ae8ef --- /dev/null +++ b/src/kpm.h @@ -0,0 +1,4 @@ +int kpm_on(int); +int kpm_off(int); +int kpm_map(char[3], int, char *); +int kpm_decode(char); -- 1.5.6.5