/* $Id: tty-keys.c,v 1.5 2008-06-25 07:30:08 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "tmux.h" struct { const char *name; int code; } tty_keys[] = { /* { "kb", KEYC_BACKSPACE }, */ { "kBEG", KEYC_SBEG }, { "kCAN", KEYC_SCANCEL }, { "kCMD", KEYC_SCOMMAND }, { "kCPY", KEYC_SCOPY }, { "kCRT", KEYC_SCREATE }, { "kDC", KEYC_SDC }, { "kDL", KEYC_SDL }, { "kEND", KEYC_SEND }, { "kEOL", KEYC_SEOL }, { "kEXT", KEYC_SEXIT }, { "kFND", KEYC_SFIND }, { "kHLP", KEYC_SHELP }, { "kHOM", KEYC_SHOME }, { "kIC", KEYC_SIC }, { "kLFT", KEYC_SLEFT }, { "kMOV", KEYC_SMOVE }, { "kMSG", KEYC_SMESSAGE }, { "kNXT", KEYC_SNEXT }, { "kOPT", KEYC_SOPTIONS }, { "kPRT", KEYC_SPRINT }, { "kPRV", KEYC_SPREVIOUS }, { "kRDO", KEYC_SREDO }, { "kRES", KEYC_SRSUME }, { "kRIT", KEYC_SRIGHT }, { "kRPL", KEYC_SREPLACE }, { "kSAV", KEYC_SSAVE }, { "kSPD", KEYC_SSUSPEND }, { "kUND", KEYC_SUNDO }, { "ka1", KEYC_A1 }, { "ka3", KEYC_A3 }, { "kb2", KEYC_B2 }, { "kbeg", KEYC_BEG }, { "kc1", KEYC_C1 }, { "kc3", KEYC_C3 }, { "kcan", KEYC_CANCEL }, { "kcbt", KEYC_BTAB }, { "kclo", KEYC_CLOSE }, { "kclr", KEYC_CLEAR }, { "kcmd", KEYC_COMMAND }, { "kcpy", KEYC_COPY }, { "kcrt", KEYC_CREATE }, { "kctab", KEYC_CTAB }, { "kcub1", KEYC_LEFT }, { "kcud1", KEYC_DOWN }, { "kcuf1", KEYC_RIGHT }, { "kcuu1", KEYC_UP }, { "kdch1", KEYC_DC }, { "kdl1", KEYC_DL }, { "ked", KEYC_EOS }, { "kel", KEYC_EOL }, { "kend", KEYC_END }, { "kent", KEYC_ENTER }, { "kext", KEYC_EXIT }, { "kf0", KEYC_F0 }, { "kf1", KEYC_F1 }, { "kf10", KEYC_F10 }, { "kf11", KEYC_F11 }, { "kf12", KEYC_F12 }, { "kf13", KEYC_F13 }, { "kf14", KEYC_F14 }, { "kf15", KEYC_F15 }, { "kf16", KEYC_F16 }, { "kf17", KEYC_F17 }, { "kf18", KEYC_F18 }, { "kf19", KEYC_F19 }, { "kf2", KEYC_F2 }, { "kf20", KEYC_F20 }, { "kf21", KEYC_F21 }, { "kf22", KEYC_F22 }, { "kf23", KEYC_F23 }, { "kf24", KEYC_F24 }, { "kf25", KEYC_F25 }, { "kf26", KEYC_F26 }, { "kf27", KEYC_F27 }, { "kf28", KEYC_F28 }, { "kf29", KEYC_F29 }, { "kf3", KEYC_F3 }, { "kf30", KEYC_F30 }, { "kf31", KEYC_F31 }, { "kf32", KEYC_F32 }, { "kf33", KEYC_F33 }, { "kf34", KEYC_F34 }, { "kf35", KEYC_F35 }, { "kf36", KEYC_F36 }, { "kf37", KEYC_F37 }, { "kf38", KEYC_F38 }, { "kf39", KEYC_F39 }, { "kf4", KEYC_F4 }, { "kf40", KEYC_F40 }, { "kf41", KEYC_F41 }, { "kf42", KEYC_F42 }, { "kf43", KEYC_F43 }, { "kf44", KEYC_F44 }, { "kf45", KEYC_F45 }, { "kf46", KEYC_F46 }, { "kf47", KEYC_F47 }, { "kf48", KEYC_F48 }, { "kf49", KEYC_F49 }, { "kf5", KEYC_F5 }, { "kf50", KEYC_F50 }, { "kf51", KEYC_F51 }, { "kf52", KEYC_F52 }, { "kf53", KEYC_F53 }, { "kf54", KEYC_F54 }, { "kf55", KEYC_F55 }, { "kf56", KEYC_F56 }, { "kf57", KEYC_F57 }, { "kf58", KEYC_F58 }, { "kf59", KEYC_F59 }, { "kf6", KEYC_F6 }, { "kf60", KEYC_F60 }, { "kf61", KEYC_F61 }, { "kf62", KEYC_F62 }, { "kf63", KEYC_F63 }, { "kf7", KEYC_F7 }, { "kf8", KEYC_F8 }, { "kf9", KEYC_F9 }, { "kfnd", KEYC_FIND }, { "khlp", KEYC_HELP }, { "khome", KEYC_HOME }, { "khts", KEYC_STAB }, { "kich1", KEYC_IC }, { "kil1", KEYC_IL }, { "kind", KEYC_SF }, { "kll", KEYC_LL }, { "kmov", KEYC_MOVE }, { "kmrk", KEYC_MARK }, { "kmsg", KEYC_MESSAGE }, { "knp", KEYC_NPAGE }, { "knxt", KEYC_NEXT }, { "kopn", KEYC_OPEN }, { "kopt", KEYC_OPTIONS }, { "kpp", KEYC_PPAGE }, { "kprt", KEYC_PRINT }, { "kprv", KEYC_PREVIOUS }, { "krdo", KEYC_REDO }, { "kref", KEYC_REFERENCE }, { "kres", KEYC_RESUME }, { "krfr", KEYC_REFRESH }, { "kri", KEYC_SR }, { "krmir", KEYC_EIC }, { "krpl", KEYC_REPLACE }, { "krst", KEYC_RESTART }, { "ksav", KEYC_SAVE }, { "kslt", KEYC_SELECT }, { "kspd", KEYC_SUSPEND }, { "ktbc", KEYC_CATAB }, { "kund", KEYC_UNDO }, { "pmous", KEYC_MOUSE }, }; #define NTTYKEYS (sizeof tty_keys / sizeof tty_keys[0]) RB_GENERATE(tty_keys, tty_key, entry, tty_keys_cmp); struct tty_key *tty_keys_find(struct tty *, char *, size_t, size_t *); int tty_keys_cmp(struct tty_key *k1, struct tty_key *k2) { return (strcmp(k1->string, k2->string)); } void tty_keys_init(struct tty *tty) { struct tty_key *tk; u_int i; char *s; RB_INIT(&tty->ktree); tty->ksize = 0; for (i = 0; i < NTTYKEYS; i++) { s = tigetstr(tty_keys[i].name); if (s == (char *) -1 || s == (char *) 0) continue; if (s[0] != '\033' || s[1] == '\0') continue; tk = xmalloc(sizeof *tk); tk->string = xstrdup(s + 1); tk->code = tty_keys[i].code; if (strlen(tk->string) > tty->ksize) tty->ksize = strlen(tk->string); RB_INSERT(tty_keys, &tty->ktree, tk); log_debug("found key %x: size now %zu (%s)", tk->code, tty->ksize, tk->string); } } void tty_keys_free(struct tty *tty) { struct tty_key *tk, *tl; for (tk = RB_MIN(tty_keys, &tty->ktree); tk != NULL; tk = tl) { tl = RB_NEXT(tty_keys, &tty->ktree, tk); RB_REMOVE(tty_keys, &tty->ktree, tk); xfree(tk->string); xfree(tk); } } struct tty_key * tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size) { struct tty_key *tk, tl; char *s; if (len == 0) return (NULL); s = xmalloc(tty->ksize + 1); for (*size = tty->ksize; (*size) > 0; (*size)--) { if ((*size) > len) continue; memcpy(s, buf, *size); s[*size] = '\0'; log_debug2("looking for key: %s", s); tl.string = s; tk = RB_FIND(tty_keys, &tty->ktree, &tl); if (tk != NULL) return (tk); } xfree(s); return (NULL); } int tty_keys_next(struct tty *tty, int *code) { struct tty_key *tk; size_t size; struct timespec ts; size = BUFFER_USED(tty->in); if (size == 0) return (1); log_debug("keys are %zu (%.*s)", size, (int) size, BUFFER_OUT(tty->in)); /* If a normal key, return it. */ if (*BUFFER_OUT(tty->in) != '\033') { *code = buffer_read8(tty->in); return (0); } /* Look for matching key string and return if found. */ tk = tty_keys_find(tty, BUFFER_OUT(tty->in) + 1, size - 1, &size); if (tk != NULL) { *code = tk->code; buffer_remove(tty->in, size + 1); tty->flags &= ~TTY_ESCAPE; return (0); } /* Escape but no key string. If the timer isn't started, start it. */ if (!(tty->flags & TTY_ESCAPE)) { ts.tv_sec = 0; ts.tv_nsec = 500 * 1000000L; if (clock_gettime(CLOCK_REALTIME, &tty->key_timer) != 0) fatal("clock_gettime"); timespecadd(&tty->key_timer, &ts, &tty->key_timer); tty->flags |= TTY_ESCAPE; return (1); } /* Otherwise, if the timer hasn't expired, wait. */ if (clock_gettime(CLOCK_REALTIME, &ts) != 0) fatal("clock_gettime"); if (!timespeccmp(&tty->key_timer, &ts, >)) return (1); tty->flags &= ~TTY_ESCAPE; /* Remove the leading escape. */ buffer_remove(tty->in, 1); size = BUFFER_USED(tty->in); /* If we have no following data, return escape. */ if (size == 0) { *code = '\033'; return (0); } /* If a normal key follows, return it. */ if (*BUFFER_OUT(tty->in) != '\033') { *code = KEYC_ADDESCAPE(buffer_read8(tty->in)); return (0); } /* Try to look up the key. */ tk = tty_keys_find(tty, BUFFER_OUT(tty->in) + 1, size - 1, &size); if (tk != NULL) { *code = KEYC_ADDESCAPE(tk->code); buffer_remove(tty->in, size + 1); return (0); } /* If not found, return escape-escape. */ *code = KEYC_ADDESCAPE('\033'); buffer_remove(tty->in, 1); return (0); }