xtermcap.c revision 2eaa94a1
1/* $XTermId: xtermcap.c,v 1.14 2008/10/05 16:43:36 tom Exp $ */ 2 3/* 4 * Copyright 2007,2008 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 */ 32 33#include <xtermcap.h> 34 35#include <X11/keysym.h> 36 37#ifdef VMS 38#include <X11/keysymdef.h> 39#endif 40 41#include <xstrings.h> 42 43#ifndef HAVE_TIGETSTR 44#undef USE_TERMINFO 45#endif 46 47#ifndef USE_TERMINFO 48#define USE_TERMINFO 0 49#endif 50 51#if USE_TERMINFO && defined(NCURSES_VERSION) && defined(HAVE_USE_EXTENDED_NAMES) 52#define USE_EXTENDED_NAMES 1 53#else 54#define USE_EXTENDED_NAMES 0 55#endif 56 57#if OPT_TCAP_QUERY || OPT_TCAP_FKEYS 58 59typedef struct { 60 char *tc; 61 char *ti; 62 int code; 63 unsigned state; 64} TCAPINFO; 65/* *INDENT-OFF* */ 66#define DATA(tc,ti,x,y) { tc, ti, x, y } 67static TCAPINFO table[] = { 68 /* tcap terminfo code param */ 69 DATA( "%1", "khlp", XK_Help, 0 ), 70 DATA( "#1", "kHLP", XK_Help, 2 ), 71 DATA( "@0", "kfnd", XK_Find, 0 ), 72 DATA( "*0", "kFND", XK_Find, 2 ), 73 DATA( "*6", "kslt", XK_Select, 0 ), 74 DATA( "#6", "kSLT", XK_Select, 2 ), 75 76 DATA( "kh", "khome", XK_Home, 0 ), 77 DATA( "#2", "kHOM", XK_Home, 2 ), 78 DATA( "@7", "kend", XK_End, 0 ), 79 DATA( "*7", "kEND", XK_End, 2 ), 80 81 DATA( "kl", "kcub1", XK_Left, 0 ), 82 DATA( "kr", "kcuf1", XK_Right, 0 ), 83 DATA( "ku", "kcuu1", XK_Up, 0 ), 84 DATA( "kd", "kcud1", XK_Down, 0 ), 85 86 DATA( "#4", "kLFT", XK_Left, 2 ), 87 DATA( "%i", "kRIT", XK_Right, 2 ), 88 DATA( "%e", "kPRV", XK_Up, 2 ), 89 DATA( "%c", "kNXT", XK_Down, 2 ), 90 91 DATA( "k1", "kf1", XK_Fn(1), 0 ), 92 DATA( "k2", "kf2", XK_Fn(2), 0 ), 93 DATA( "k3", "kf3", XK_Fn(3), 0 ), 94 DATA( "k4", "kf4", XK_Fn(4), 0 ), 95 DATA( "k5", "kf5", XK_Fn(5), 0 ), 96 DATA( "k6", "kf6", XK_Fn(6), 0 ), 97 DATA( "k7", "kf7", XK_Fn(7), 0 ), 98 DATA( "k8", "kf8", XK_Fn(8), 0 ), 99 DATA( "k9", "kf9", XK_Fn(9), 0 ), 100 DATA( "k;", "kf10", XK_Fn(10), 0 ), 101 102 DATA( "F1", "kf11", XK_Fn(11), 0 ), 103 DATA( "F2", "kf12", XK_Fn(12), 0 ), 104 DATA( "F3", "kf13", XK_Fn(13), 0 ), 105 DATA( "F4", "kf14", XK_Fn(14), 0 ), 106 DATA( "F5", "kf15", XK_Fn(15), 0 ), 107 DATA( "F6", "kf16", XK_Fn(16), 0 ), 108 DATA( "F7", "kf17", XK_Fn(17), 0 ), 109 DATA( "F8", "kf18", XK_Fn(18), 0 ), 110 DATA( "F9", "kf19", XK_Fn(19), 0 ), 111 DATA( "FA", "kf20", XK_Fn(20), 0 ), 112 DATA( "FB", "kf21", XK_Fn(21), 0 ), 113 DATA( "FC", "kf22", XK_Fn(22), 0 ), 114 DATA( "FD", "kf23", XK_Fn(23), 0 ), 115 DATA( "FE", "kf24", XK_Fn(24), 0 ), 116 DATA( "FF", "kf25", XK_Fn(25), 0 ), 117 DATA( "FG", "kf26", XK_Fn(26), 0 ), 118 DATA( "FH", "kf27", XK_Fn(27), 0 ), 119 DATA( "FI", "kf28", XK_Fn(28), 0 ), 120 DATA( "FJ", "kf29", XK_Fn(29), 0 ), 121 DATA( "FK", "kf30", XK_Fn(30), 0 ), 122 DATA( "FL", "kf31", XK_Fn(31), 0 ), 123 DATA( "FM", "kf32", XK_Fn(32), 0 ), 124 DATA( "FN", "kf33", XK_Fn(33), 0 ), 125 DATA( "FO", "kf34", XK_Fn(34), 0 ), 126 DATA( "FP", "kf35", XK_Fn(35), 0 ), 127 128 DATA( "FQ", "kf36", -36, 0 ), 129 DATA( "FR", "kf37", -37, 0 ), 130 DATA( "FS", "kf38", -38, 0 ), 131 DATA( "FT", "kf39", -39, 0 ), 132 DATA( "FU", "kf40", -40, 0 ), 133 DATA( "FV", "kf41", -41, 0 ), 134 DATA( "FW", "kf42", -42, 0 ), 135 DATA( "FX", "kf43", -43, 0 ), 136 DATA( "FY", "kf44", -44, 0 ), 137 DATA( "FZ", "kf45", -45, 0 ), 138 DATA( "Fa", "kf46", -46, 0 ), 139 DATA( "Fb", "kf47", -47, 0 ), 140 DATA( "Fc", "kf48", -48, 0 ), 141 DATA( "Fd", "kf49", -49, 0 ), 142 DATA( "Fe", "kf50", -50, 0 ), 143 DATA( "Ff", "kf51", -51, 0 ), 144 DATA( "Fg", "kf52", -52, 0 ), 145 DATA( "Fh", "kf53", -53, 0 ), 146 DATA( "Fi", "kf54", -54, 0 ), 147 DATA( "Fj", "kf55", -55, 0 ), 148 DATA( "Fk", "kf56", -56, 0 ), 149 DATA( "Fl", "kf57", -57, 0 ), 150 DATA( "Fm", "kf58", -58, 0 ), 151 DATA( "Fn", "kf59", -59, 0 ), 152 DATA( "Fo", "kf60", -60, 0 ), 153 DATA( "Fp", "kf61", -61, 0 ), 154 DATA( "Fq", "kf62", -62, 0 ), 155 DATA( "Fr", "kf63", -63, 0 ), 156 157 DATA( "K1", "ka1", XK_KP_Home, 0 ), 158 DATA( "K4", "kc1", XK_KP_End, 0 ), 159 DATA( "K3", "ka3", XK_KP_Prior, 0 ), 160 DATA( "K5", "kc3", XK_KP_Next, 0 ), 161 162#ifdef XK_ISO_Left_Tab 163 DATA( "kB", "kcbt", XK_ISO_Left_Tab, 0 ), 164#endif 165 DATA( "kC", "kclr", XK_Clear, 0 ), 166 DATA( "kD", "kdch1", XK_Delete, 0 ), 167 DATA( "kI", "kich1", XK_Insert, 0 ), 168 DATA( "kN", "knp", XK_Next, 0 ), 169 DATA( "kP", "kpp", XK_Prior, 0 ), 170 DATA( "&8", "kund", XK_Undo, 0 ), 171 DATA( "kb", "kbs", XK_BackSpace, 0 ), 172# if OPT_TCAP_QUERY && OPT_ISO_COLORS 173 /* XK_COLORS is a fake code. */ 174 DATA( "Co", "colors", XK_COLORS, 0 ), 175# endif 176#if USE_EXTENDED_NAMES 177#define DEXT(name, parm, code) DATA("", name, code, parm) 178#define D1ST(name, parm, code) DEXT("k" #name, parm, code) 179#define DMOD(name, parm, code) DEXT("k" #name #parm, parm, code) 180 181#define DGRP(name, code) \ 182 D1ST(name, 2, code), \ 183 DMOD(name, 3, code), \ 184 DMOD(name, 4, code), \ 185 DMOD(name, 5, code), \ 186 DMOD(name, 6, code), \ 187 DMOD(name, 7, code), \ 188 DMOD(name, 8, code) 189 190 DGRP(DN, XK_Down), 191 DGRP(LFT, XK_Left), 192 DGRP(RIT, XK_Right), 193 DGRP(UP, XK_Up), 194 DGRP(DC, XK_Delete), 195 DGRP(END, XK_End), 196 DGRP(HOM, XK_Home), 197 DGRP(IC, XK_Insert), 198 DGRP(NXT, XK_Next), 199 DGRP(PRV, XK_Prior), 200#endif 201}; 202#undef DATA 203/* *INDENT-ON* */ 204 205#if OPT_TCAP_QUERY 206static int 207hex2int(int c) 208{ 209 if (c >= '0' && c <= '9') 210 return c - '0'; 211 if (c >= 'a' && c <= 'f') 212 return c - 'a' + 10; 213 if (c >= 'A' && c <= 'F') 214 return c - 'A' + 10; 215 return -1; 216} 217 218static TCAPINFO * 219lookupTcapByName(XtermWidget xw, const char *name) 220{ 221 TCAPINFO *result = 0; 222 Cardinal n; 223 224 if (name != 0 && *name != '\0') { 225 for (n = 0; n < XtNumber(table); n++) { 226 if (!strcmp(table[n].ti, name) || !strcmp(table[n].tc, name)) { 227 result = table + n; 228 break; 229 } 230 } 231 } 232 233 /* 234 * The vt220-keyboard will not return distinct key sequences for shifted 235 * cursor-keys. Just pretend they do not exist, since some programs may 236 * be confused if we return the same data for shifted/unshifted keys. 237 */ 238 if (xw->keyboard.type == keyboardIsVT220 239 && result != 0 240 && result->state == 2) { 241 result = 0; 242 } 243 244 if (result != 0) { 245 TRACE(("lookupTcapByName(%s) tc=%s, ti=%s code %#x, state %#x\n", 246 name, result->tc, result->ti, result->code, result->state)); 247 } else { 248 TRACE(("lookupTcapByName(%s) FAIL\n", name)); 249 } 250 return result; 251} 252 253/* 254 * Parse the termcap/terminfo name from the string, returning a positive number 255 * (the keysym) if found, otherwise -1. Update the string pointer. 256 * Returns the (shift, control) state in *state. 257 * 258 * This does not attempt to construct control/shift modifiers to construct 259 * function-key values. Instead, it sets the *fkey flag to pass to Input() 260 * and bypass the lookup of keysym altogether. 261 */ 262int 263xtermcapKeycode(XtermWidget xw, char **params, unsigned *state, Bool * fkey) 264{ 265 TCAPINFO *data; 266 unsigned len = 0; 267 int code = -1; 268#define MAX_TNAME_LEN 6 269 char name[MAX_TNAME_LEN + 1]; 270 char *p; 271 272 TRACE(("xtermcapKeycode(%s)\n", *params)); 273 274 /* Convert hex encoded name to ascii */ 275 for (p = *params; hex2int(p[0]) >= 0 && hex2int(p[1]) >= 0; p += 2) { 276 if (len >= MAX_TNAME_LEN) 277 break; 278 name[len++] = (hex2int(p[0]) << 4) + hex2int(p[1]); 279 } 280 name[len] = 0; 281 *params = p; 282 283 *state = 0; 284 *fkey = False; 285 286 if (*p == 0 || *p == ';') { 287 if ((data = lookupTcapByName(xw, name)) != 0) { 288 code = data->code; 289 *state = xtermParamToState(xw, data->state); 290 if (IsFunctionKey(code)) { 291 *fkey = True; 292 } else if (code < 0) { 293 *fkey = True; 294 code = XK_Fn((-code)); 295 } 296#if OPT_SUN_FUNC_KEYS 297 if (*fkey && xw->keyboard.type == keyboardIsSun) { 298 int num = code - XK_Fn(0); 299 300 /* match function-key case in sunfuncvalue() */ 301 if (num > 20) { 302 if (num <= 30 || num > 47) { 303 code = -1; 304 } else { 305 code -= 10; 306 switch (num) { 307 case 37: /* khome */ 308 case 39: /* kpp */ 309 case 41: /* kb2 */ 310 case 43: /* kend */ 311 case 45: /* knp */ 312 code = -1; 313 break; 314 } 315 } 316 } 317 } 318#endif 319 } 320 } 321 322 TRACE(("... xtermcapKeycode(%s, %u, %d) -> %#06x\n", 323 name, *state, *fkey, code)); 324 return code; 325} 326#endif /* OPT_TCAP_QUERY */ 327 328#if OPT_TCAP_FKEYS 329static TCAPINFO * 330lookupTcapByCode(int code, unsigned mask) 331{ 332 TCAPINFO *result = 0; 333 Cardinal n; 334 335 TRACE(("lookupTcapByCode %d:%#x\n", code, mask)); 336 for (n = 0; n < XtNumber(table); n++) { 337 if (table[n].code == code && 338 table[n].state == mask) { 339 TRACE(("lookupTcapByCode %d:%s\n", n, table[n].ti)); 340 result = table + n; 341 break; 342 } 343 } 344 return result; 345} 346 347#define NO_STRING (char *)(-1) 348 349int 350xtermcapString(XtermWidget xw, int keycode, unsigned mask) 351{ 352 int result = 0; 353 TCAPINFO *data; 354 unsigned param = xtermStateToParam(xw, mask); 355 356 if ((data = lookupTcapByCode(keycode, param)) != 0) { 357 TScreen *screen = TScreenOf(xw); 358 Cardinal which = data - table; 359 char *fkey; 360 361 if (screen->tcap_fkeys == 0) { 362 Cardinal want = XtNumber(table); 363 Cardinal have; 364#if !(USE_TERMINFO && defined(HAVE_TIGETSTR)) 365 char *area = screen->tcap_area; 366#endif 367 368 if ((screen->tcap_fkeys = TypeCallocN(char *, want)) != 0) { 369 for (have = 0; have < want; ++have) { 370#if USE_TERMINFO && defined(HAVE_TIGETSTR) 371 fkey = tigetstr(table[have].ti); 372#else 373 fkey = tgetstr(table[have].tc, &area); 374#endif 375 if (fkey != 0 && fkey != NO_STRING) { 376 screen->tcap_fkeys[have] = x_strdup(fkey); 377 } else { 378 screen->tcap_fkeys[have] = NO_STRING; 379 } 380 } 381 } 382 } 383 if (screen->tcap_fkeys != 0) { 384 if ((fkey = screen->tcap_fkeys[which]) != NO_STRING) { 385 StringInput(xw, (Char *) fkey, strlen(fkey)); 386 result = 1; 387 } 388 } 389 } 390 391 TRACE(("xtermcapString(keycode=%#x, mask=%#x) ->%d\n", 392 keycode, mask, result)); 393 394 return result; 395} 396#endif /* OPT_TCAP_FKEYS */ 397 398#endif /* OPT_TCAP_QUERY || OPT_TCAP_FKEYS */ 399/* 400 * If we're linked to terminfo, tgetent() will return an empty buffer. We 401 * cannot use that to adjust the $TERMCAP variable. 402 */ 403Bool 404get_termcap(char *name, char *buffer) 405{ 406 *buffer = 0; /* initialize, in case we're using terminfo's tgetent */ 407 408#if USE_EXTENDED_NAMES 409 use_extended_names(TRUE); 410#endif 411 if (name != 0) { 412 if (tgetent(buffer, name) == 1) { 413 TRACE(("get_termcap(%s) succeeded (%s)\n", name, 414 (*buffer 415 ? "ok:termcap, we can update $TERMCAP" 416 : "assuming this is terminfo"))); 417 return True; 418 } else { 419 *buffer = 0; /* just in case */ 420 } 421 } 422 return False; 423} 424