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