xtrapchar.c revision d41660be
1/* $XFree86: xc/programs/xtrap/xtrapchar.c,v 1.2 2001/11/19 15:33:41 tsi Exp $ */ 2/* 3 * @DEC_COPYRIGHT@ 4 */ 5/* 6 * HISTORY 7 * Log: xtrapchar.c,v $ 8 * Revision 1.1.2.2 1993/12/14 12:37:15 Kenneth_Miller 9 * ANSI-standardize code and turn client build on 10 * [1993/12/09 20:15:33 Kenneth_Miller] 11 * 12 * EndLog$ 13 */ 14#if !defined(lint) && 0 15static char *rcsid = "@(#)RCSfile: xtrapchar.c,v $ Revision: 1.1.2.2 $ (DEC) Date: 1993/12/14 12:37:15 $"; 16#endif 17/***************************************************************************** 18Copyright 1987, 1988, 1989, 1990, 1991, 1993 by Digital Equipment Corp., 19Maynard, MA 20 21Permission to use, copy, modify, and distribute this software and its 22documentation for any purpose and without fee is hereby granted, 23provided that the above copyright notice appear in all copies and that 24both that copyright notice and this permission notice appear in 25supporting documentation, and that the name of Digital not be 26used in advertising or publicity pertaining to distribution of the 27software without specific, written prior permission. 28 29DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 30ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 31DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 32ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 33WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 34ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 35SOFTWARE. 36 37*****************************************************************************/ 38#define ProgName "xtrapchar" 39/* 40**++ 41** FACILITY: xtrapchar - Converts ANSI character sequences to X. 42** 43** MODULE DESCRIPTION: 44** 45** Parses ANSI character sequences including application program 46** sequences to synthesize input events to X Window servers 47** using the XTrap server extension. Additionally, this main 48** module is designed to be used with the voice 49** recognition systems which will allow voice input into X Servers. 50** 51** AUTHORS: 52** 53** Kenneth B. Miller 54** 55** CREATION DATE: March 23, 1991 56** 57** DESIGN ISSUES: 58** 59** Accepts non-buffered Ascii characters as input and 60** performs a table look-up to determine what the corresponding 61** X actions are to be performed. 62** 63** Uses chparse() which was contributed to DECUS C by Roy 64** Lomicka and later revised by Martin Minow and myself. 65** Also, getopt() is used to parse the command 66** line arguments prior to calling XtAppInitialize(). 67** Currently only the -v argument is supported to indicate 68** echoing of characters received for debugging 69** purposes. 70** 71** 72** CAVEAT: 73** 74** This program has *only* been used with Digital Workstations 75** using the LK201 compatible keyboard. Though reasonable 76** effort was done to maintain portability, no claims are made 77** as to the current level of portability to non-DEC servers 78** for this program. 79**-- 80*/ 81#include <unistd.h> 82#include <stdlib.h> 83#include <ctype.h> 84#include <X11/extensions/xtraplib.h> 85#include <X11/extensions/xtraplibp.h> 86#include <X11/keysym.h> 87 88#include "chparse.h" 89 90#ifndef vaxc 91#define globalref extern 92#endif 93#ifdef Lynx 94extern char *optarg; 95extern int optind; 96extern int opterr; 97#endif 98 99 /* Special private indicators */ 100#define BPRESS '!' 101#define BRELEASE '"' 102#define BCLICK '#' 103#define APRESS '$' 104#define ARELEASE '%' 105#define CPRESS '(' 106#define CRELEASE ')' 107#define SPRESS '+' 108#define SRELEASE '-' 109#define DPRIVATE '=' 110#define MNOTIFY '>' 111#define RMNOTIFY '?' 112 113#define NPARAM 8 114#define NINTER 8 115#define NUL 0x00 116#define CAN 0x18 117#define SUB 0x1A 118#define ESC 0x1B 119#define DEL 0x7F 120#define SS3 0x8f 121#define DCS 0x90 122#define CSI 0x9B 123#define ST 0x9C 124#define OSC 0x9D 125#define PM 0x9E 126#define APC 0x9F 127 128static BOOL verbose_flag = FALSE; 129static INT16 column = 0; 130static int state = NUL; /* Parser state (n.z. if incomplete) */ 131static Window root; 132static BOOL passive_shift; /* Cap's assumed? */ 133static BOOL passive_ctrl; /* Control key assumed? */ 134static BOOL shift; /* Cap's on? */ 135static BOOL ctrl; /* Control key? */ 136static BOOL alt; /* Alt key? */ 137static KeyCode alt_code; 138static KeyCode ctrl_code; 139static KeyCode shift_code; 140 141 142 143#define _AdjustCol(length) \ 144 if ((column += length) >= 79) \ 145 { \ 146 printf("\n"); \ 147 column = length; \ 148 } 149 150static void KeyClick(XETC *tc, KeyCode keycode) 151{ 152 if (passive_ctrl && !ctrl) 153 { 154 XESimulateXEventRequest(tc, KeyPress, ctrl_code, 0, 0, 0); 155 } 156 if (passive_shift && !shift) 157 { 158 XESimulateXEventRequest(tc, KeyPress, shift_code, 0, 0, 0); 159 } 160 XESimulateXEventRequest(tc, KeyPress, keycode, 0, 0, 0); 161 XESimulateXEventRequest(tc, KeyRelease, keycode, 0, 0, 0); 162 if (passive_shift && !shift) 163 { 164 XESimulateXEventRequest(tc, KeyRelease, shift_code, 0, 0, 0); 165 } 166 if (passive_ctrl && !ctrl) 167 { 168 XESimulateXEventRequest(tc, KeyRelease, ctrl_code, 0, 0, 0); 169 } 170 passive_ctrl = passive_shift = FALSE; /* Action's been completed */ 171} 172 173 174/* 175** 176** FORWARD DECLARATIONS 177** 178*/ 179static int get_csi_key ( XETC *tc , int private , int param [], 180 int nparam , int inter [], int ninter , int final ); 181static int get_ss3_key ( XETC *tc , int private , int param [], 182 int nparam , int inter [], int ninter , int final ); 183static void send_special ( XETC *tc , int private , int param [], 184 int nparam , int inter [], int ninter , int final ); 185static KeyCode get_typical_char ( XETC *tc , CARD32 keysym); 186static KeyCode get_keycode ( XETC *tc , KeySym keysym); 187 188 189int 190main(int argc, char *argv[]) 191{ 192 Widget appW; 193 Display *dpy; 194 XETrapGetCurRep ret_cur; 195 XETC *tc; 196 XtAppContext app; 197 char *tmp = NULL; 198 INT16 ch; 199 INT16 i; 200 KeyCode keycode; 201 /* ESC & CSI Parsing variables */ 202 int max_delay = 3; 203 int rest_delay = 2; 204 int private; /* Sequence private char, 'X' if error */ 205 int param[NPARAM]; /* numeric param, starting at param[1] */ 206 int nparam; /* Number of parameters */ 207 int inter[NINTER]; /* intermediate char, starting at [1] */ 208 int ninter; /* Number of intermediates */ 209 int final; /* Sequence terminator */ 210 int *popterr; 211#ifndef vms 212 popterr = &opterr; 213#else 214 popterr = XEgetopterr(); 215#endif 216 *popterr = 0; /* don't complain about -d for display */ 217 while ((ch = getopt(argc, argv, "d:v")) != EOF) 218 { 219 switch(ch) 220 { 221 case 'v': 222 verbose_flag = TRUE; 223 break; 224 case 'd': /* -display, let's let the toolkit parse it */ 225 break; 226 default: 227 break; 228 } 229 } 230 appW = XtAppInitialize(&app,"XTrap",(XrmOptionDescList)NULL,(Cardinal)0L, 231 (int *)&argc, (String *)argv, NULL,(ArgList)&tmp, 232 (Cardinal)0); 233 234 dpy = XtDisplay(appW); 235 if (verbose_flag) 236 { 237 printf("Display: %s \n", DisplayString(dpy)); 238 } 239 if ((tc = XECreateTC(dpy,0L, NULL)) == NULL) 240 { 241 fprintf(stderr,"%s: could not initialize XTrap extension\n", ProgName); 242 exit (1L); 243 } 244 root = RootWindow(dpy,DefaultScreen(dpy)); 245 (void)XEStartTrapRequest(tc); 246 alt_code = XKeysymToKeycode(tc->dpy,XK_Alt_L); 247 ctrl_code = XKeysymToKeycode(tc->dpy,XK_Control_L); 248 shift_code = XKeysymToKeycode(tc->dpy,XK_Shift_L); 249 250 251 252 if (verbose_flag) 253 { 254 (void)XEGetCurrentRequest(tc,&ret_cur); 255 XEPrintCurrent(stderr,&ret_cur); 256 } 257 258 column = 0; /* if displaying char's, don't go beyond 80 columns */ 259 260 while ((ch = chparse(max_delay, rest_delay, &state, &private, param, 261 &nparam, inter, &ninter, &final)) != -1) 262 { 263 if (ch == -2) 264 { 265 continue; /* timeout condition */ 266 } 267 if ((!ferror(stdin)) && (!feof(stdin)) && (state == 0)) 268 { /* we got something */ 269 switch(ch) 270 { 271 case CSI: /* Control Sequence */ 272 keycode = get_csi_key(tc, private, param, nparam, inter, 273 ninter, final); 274 if (keycode) 275 KeyClick(tc, keycode); 276 break; 277 case SS3: /* Keypad stuff */ 278 keycode = get_ss3_key(tc, private, param, nparam, inter, 279 ninter, final); 280 if (keycode) 281 KeyClick(tc, keycode); 282 break; 283 case APC: /* Application Cmd (Button's, Press, Release) */ 284 send_special(tc, private, param, nparam, inter, ninter, 285 final); 286 break; 287 case ESC: /* Escape Sequence */ 288 /* send ESCAPE */ 289 if (!(keycode = XKeysymToKeycode(tc->dpy,XK_Escape))) 290 { /* must be an LK201 keyboard */ 291 BOOL orig_ctrl = ctrl; 292 /* 293 * the following is kind of strange. We need to 294 * have ctrl TRUE for get_typical_char() to 295 * report the verbose message correctly. We 296 * can't use passive_ctrl cause it resets it. 297 * Then, for KeyClick(), ctrl has to be FALSE 298 * and passive_ctrl has to be TRUE in order for 299 * us to get the desired <CTRL>[ to simulate 300 * an escape key. Once it's all done, we need 301 * to return ctrl to whatever it was and clear 302 * the passive_ctrl. 303 */ 304 ctrl = TRUE; /* for get_typical_char */ 305 keycode = get_typical_char(tc, (CARD32)'['); 306 ctrl = FALSE; /* for KeyClick */ 307 passive_ctrl = TRUE; /* for KeyClick */ 308 KeyClick(tc, keycode); 309 passive_ctrl = FALSE; /* to continue */ 310 ctrl = orig_ctrl; /* to continue */ 311 } 312 else 313 { 314 KeyClick(tc, keycode); 315 if (verbose_flag) 316 { 317 _AdjustCol(strlen("<ESC>")); 318 printf("<ESC>"); 319 } 320 } 321 /* send private (if valid) */ 322 if (private != NUL && private != 'X' && 323 (keycode = get_typical_char(tc, (CARD32)private))) 324 KeyClick(tc, keycode); 325 /* send addt'l parameters, if any */ 326 for (i = 1; i <= nparam; i++) 327 if ((keycode = get_typical_char(tc, (CARD32)param[i]))) 328 KeyClick(tc, keycode); 329 /* send intermediate's, if any */ 330 for (i = 1; i <= ninter; i++) 331 if ((keycode = get_typical_char(tc, (CARD32)inter[i]))) 332 KeyClick(tc, keycode); 333 /* send final character */ 334 if ((keycode = get_typical_char(tc, (CARD32)final))) 335 KeyClick(tc, keycode); 336 break; 337 338 case DCS: /* We don't deal with these */ 339 case OSC: 340 case PM: 341 if (verbose_flag) 342 { 343 printf("Ignoring the following: "); 344 dumpsequence(state, ch, private, param, nparam, 345 inter, ninter, final, &column); 346 } 347 break; 348 default: /* typical character */ 349 keycode = get_typical_char(tc, (CARD32)ch); 350 if (keycode) 351 KeyClick(tc, keycode); 352 break; 353 } 354 } 355 else 356 { /* error? */ 357 if (ferror(stdin) || state != 0) 358 { 359 perror("Error occurred parsing input characters!\n"); 360 } 361 break; 362 } 363 } 364 /* Clean things up */ 365 XEFreeTC(tc); 366 (void)XCloseDisplay(dpy); 367 368 exit(0L); 369} 370 371static int get_csi_key(XETC *tc, int private, 372 int param[], int nparam, 373 int inter[], int ninter, 374 int final) 375{ 376 KeySym keysym = 0; 377 switch(param[1]) 378 { 379 case 0: 380 switch ((char )final) 381 { 382 case 'A': keysym = XK_Up; break; 383 case 'B': keysym = XK_Down; break; 384 case 'C': keysym = XK_Right; break; 385 case 'D': keysym = XK_Left; break; 386 default: 387 dumpsequence(state, CSI, private, param, nparam, 388 inter, ninter, final, &column); 389 break; 390 } 391 break; 392 case 1: keysym = XK_Find; break; 393 case 2: keysym = XK_Insert; break; 394#ifdef DXK_Remove 395 case 3: keysym = DXK_Remove; break; 396#endif 397 case 4: keysym = XK_Select; break; 398 case 5: keysym = XK_Prior; break; 399 case 6: keysym = XK_Next; break; 400 case 17: keysym = XK_F6; break; 401 case 18: keysym = XK_F7; break; 402 case 19: keysym = XK_F8; break; 403 case 20: keysym = XK_F9; break; 404 case 21: keysym = XK_F10; break; 405 case 23: keysym = XK_F11; break; 406 case 24: keysym = XK_F12; break; 407 case 25: keysym = XK_F13; break; 408 case 26: keysym = XK_F14; break; 409 case 28: keysym = XK_Help; break; 410 case 29: keysym = XK_Menu; break; 411 case 31: keysym = XK_F17; break; 412 case 32: keysym = XK_F18; break; 413 case 33: keysym = XK_F19; break; 414 case 34: keysym = XK_F20; break; 415 default: 416 dumpsequence(state, CSI, private, param, nparam, 417 inter, ninter, final, &column); 418 } 419 420 return(get_keycode(tc, keysym)); 421} 422 423 /* 424 * XTrap special sequences: 425 * ButtonPress: <APC>=!X (where 'X' is 'A', 'B', or 'C' 426 * for MB1, MB2, MB3 respectively) 427 * ButtonRelease: <APC>="X (where 'X' is 'A', 'B', or 'C' 428 * for MB1, MB2, MB3 respectively) 429 * ButtonClick: <APC>=#X (where 'X' is 'A', 'B', or 'C' 430 * for MB1, MB2, MB3 respectively) 431 * AltPress: <APC>=$~ 432 * AltRelease: <APC>=%~ 433 * CtrlPress: <APC>=(~ 434 * CtrlRelease: <APC>=)~ 435 * ShiftPress: <APC>=+~ 436 * ShiftRelease: <APC>=-~ 437 * MotionNotify: <APC>>;X;Y~ (where 'X' is the X coord and 'Y' 438 * is the Y coord of the desired 439 * pointer position) 440 * Relative MotionNotify: 441 * <APC>?;X;Y~ (where 'X' is the X coord and 'Y' 442 * is the Y coord of the desired 443 * pointer position) 444 * 445 */ 446static void send_special(XETC *tc, int private, 447 int param[], int nparam, 448 int inter[], int ninter, 449 int final) 450{ 451 switch(private) 452 { 453 case DPRIVATE: /* default APC */ 454 if (ninter != 1) 455 { /* Not my sequence */ 456 dumpsequence(state, APC, private, param, nparam, 457 inter, ninter, final, &column); 458 return; 459 } 460 else 461 { 462 switch(inter[1]) 463 { 464 Window rid, wid; 465 int x, y, wx, wy; 466 unsigned int sm; 467 CARD8 detail; 468 469 case BPRESS: 470 detail = (final - 'A' + 1); 471 if ((Bool)XQueryPointer(tc->dpy,root,&rid,&wid,&x, 472 &y,&wx,&wy,&sm) == False) 473 { 474 fprintf(stderr, "\nPointer's not on screen 0!\n"); 475 } 476 else 477 { 478 XESimulateXEventRequest(tc, ButtonPress, detail, 479 x, y, 0); 480 if (verbose_flag) 481 { 482 _AdjustCol(strlen("<MB%d-Press> ")-1); 483 printf("<MB%d-Press> ", detail); 484 } 485 } 486 break; 487 case BRELEASE: 488 detail = (final - 'A' + 1); 489 if ((Bool)XQueryPointer(tc->dpy,root,&rid,&wid,&x, 490 &y,&wx,&wy,&sm) == False) 491 { 492 fprintf(stderr, "\nPointer's not on screen 0!\n"); 493 } 494 else 495 { 496 XESimulateXEventRequest(tc, ButtonRelease, detail, 497 x,y,0); 498 if (verbose_flag) 499 { 500 _AdjustCol(strlen("<MB%d-Release> ")-1); 501 printf("<MB%d-Release> ", detail); 502 } 503 } 504 break; 505 case BCLICK: 506 detail = (final - 'A' + 1); 507 if (XQueryPointer(tc->dpy,root,&rid,&wid,&x,&y, 508 &wx,&wy,&sm) 509 == False) 510 { 511 fprintf(stderr, "\nPointer's not on screen 0!\n"); 512 } 513 else 514 { 515 XESimulateXEventRequest(tc,ButtonPress, 516 detail,x,y,0); 517 XESimulateXEventRequest(tc,ButtonRelease, 518 detail,x,y,0); 519 if (verbose_flag) 520 { 521 _AdjustCol(strlen("<MB%d> ")-1); 522 printf("<MB%d> ", detail); 523 } 524 } 525 break; 526 case APRESS: 527 alt = TRUE; 528 XESimulateXEventRequest(tc,KeyPress,alt_code,0,0,0); 529 break; 530 case ARELEASE: 531 alt = FALSE; 532 XESimulateXEventRequest(tc,KeyRelease,alt_code,0,0,0); 533 break; 534 case SPRESS: 535 shift = TRUE; 536 XESimulateXEventRequest(tc,KeyPress,shift_code,0,0,0); 537 break; 538 case SRELEASE: 539 shift = FALSE; 540 XESimulateXEventRequest(tc,KeyRelease,shift_code, 541 0,0,0); 542 break; 543 case CPRESS: 544 ctrl = TRUE; 545 XESimulateXEventRequest(tc,KeyPress,ctrl_code,0,0,0); 546 break; 547 case CRELEASE: 548 ctrl = FALSE; 549 XESimulateXEventRequest(tc,KeyRelease,ctrl_code,0,0,0); 550 break; 551 default: 552 fprintf(stderr, "\nInvalid Sequence!\n"); 553 dumpsequence(state, APC, private, param, nparam, 554 inter, ninter, final, &column); 555 } 556 } 557 break; 558 case MNOTIFY: 559 if (nparam != 3) 560 { /* Not my sequence */ 561 dumpsequence(state, APC, private, param, nparam, 562 inter, ninter, final, &column); 563 return; 564 } 565 else 566 { 567 int x, y; 568 569 x = param[2]; 570 y = param[3]; 571 XESimulateXEventRequest(tc,MotionNotify,0,x,y,0); 572 if (verbose_flag) 573 { 574 _AdjustCol(strlen("<M %d,%d> ")+3); 575 printf("<M %d,%d> ",x,y); 576 } 577 } 578 break; 579 case RMNOTIFY: 580 if (nparam != 3) 581 { /* Not my sequence */ 582 dumpsequence(state, APC, private, param, nparam, 583 inter, ninter, final, &column); 584 return; 585 } 586 else 587 { 588 Window rid, wid; 589 int x, y, wx, wy; 590 unsigned int sm; 591 592 if (XQueryPointer(tc->dpy,root,&rid,&wid,&x,&y,&wx,&wy,&sm) 593 == False) 594 { 595 fprintf(stderr, "\nPointer's not on screen 0!\n"); 596 } 597 else 598 { /* We're ready to go */ 599 x += param[2]; 600 y += param[3]; 601 XESimulateXEventRequest(tc,MotionNotify,0,x,y,0); 602 if (verbose_flag) 603 { 604 _AdjustCol(strlen("<RM ddd+sddd,dddd+sdddd> ")); 605 printf("<RM %d+%d,%d+%d> ",x-param[2],param[3], 606 y-param[3],param[3]); 607 } 608 } 609 break; 610 default: 611 dumpsequence(state, APC, private, param, nparam, 612 inter, ninter, final, &column); 613 break; 614 } 615 } 616} 617 618static int get_ss3_key(XETC *tc, int private, 619 int param[], int nparam, 620 int inter[], int ninter, 621 int final) 622{ 623 KeySym keysym = 0; 624 switch(param[1]) 625 { 626 case 0: 627 switch ((char )final) 628 { 629 case 'A': keysym = XK_Up; break; 630 case 'B': keysym = XK_Down; break; 631 case 'C': keysym = XK_Right; break; 632 case 'D': keysym = XK_Left; break; 633 case 'p': keysym = XK_KP_0; break; 634 case 'q': keysym = XK_KP_1; break; 635 case 'r': keysym = XK_KP_2; break; 636 case 's': keysym = XK_KP_3; break; 637 case 't': keysym = XK_KP_4; break; 638 case 'u': keysym = XK_KP_5; break; 639 case 'v': keysym = XK_KP_6; break; 640 case 'w': keysym = XK_KP_7; break; 641 case 'x': keysym = XK_KP_8; break; 642 case 'y': keysym = XK_KP_9; break; 643 case 'm': keysym = XK_KP_Subtract; break; 644 case 'l': keysym = XK_KP_Separator; break; 645 case 'n': keysym = XK_KP_Decimal; break; 646 case 'M': keysym = XK_KP_Enter; break; 647 case 'P': keysym = XK_KP_F1; break; 648 case 'Q': keysym = XK_KP_F2; break; 649 case 'R': keysym = XK_KP_F3; break; 650 case 'S': keysym = XK_KP_F4; break; 651 default: 652 dumpsequence(state, SS3, private, param, nparam, 653 inter, ninter, final, &column); 654 break; 655 } 656 break; 657 } 658 659 return(get_keycode(tc, keysym)); 660} 661 662static KeyCode get_typical_char(XETC *tc, CARD32 keysym) 663{ 664 if (iscntrl(keysym)) 665 { 666 switch(keysym) 667 { 668 case 0x09: keysym = XK_Tab; break; 669 case 0x0d: keysym = XK_Return; break; 670 case 0x7f: keysym = XK_Delete; break; 671 case ESC: keysym = XK_Escape; break; 672 } 673 } 674 passive_shift = (keysym >= XK_A && keysym <= XK_Z) ? TRUE : FALSE; 675 switch(keysym) 676 { /* Special case shift's */ 677 case '!': case '"': case '@': case '#': case '$': 678 case '%': case '^': case '&': case '*': case '(': 679 case ')': case '_': case '+': case '{': case '}': 680 case '|': case ':': case '>': case '?': case '~': 681 passive_shift = TRUE; 682 } 683 684 if (keysym >= 1 && keysym <= 26) 685 { 686 passive_ctrl = TRUE; 687 keysym += 'a' - 1; 688 } 689 else 690 { 691 passive_ctrl = FALSE; 692 } 693 694 return(get_keycode(tc, keysym)); 695} 696 697static KeyCode get_keycode(XETC *tc, KeySym keysym) 698{ 699 char *keystr = (char *)XKeysymToString(keysym); 700 KeyCode keycode; 701 702 keystr = (keystr == NULL) ? "unknown" : keystr; 703 if (verbose_flag) 704 { 705 if (shift || passive_shift) 706 { 707 _AdjustCol(strlen("<SHIFT>")); 708 printf("<SHIFT>"); 709 } 710 if (alt) 711 { 712 _AdjustCol(strlen("<ALT>")); 713 printf("<ALT>"); 714 } 715 if (ctrl || passive_ctrl) 716 { 717 _AdjustCol(strlen("<CTRL>")); 718 printf("<CTRL>"); 719 } 720 _AdjustCol(strlen(keystr)+1); 721 printf("%s ", keystr); 722 } 723 if (!(keycode = XKeysymToKeycode(tc->dpy,keysym))) 724 { 725 fprintf(stderr,"\n[%s ('%%0x%04x') returns bad Keycode, ignored]\n", 726 keystr, (unsigned int)keysym); 727 column = 0; 728 } 729 730 return(keycode); 731} 732