1a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
2a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat   Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat   All rights reserved.
4a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
5a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatThis file is part of x11vnc.
6a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
7a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatx11vnc is free software; you can redistribute it and/or modify
8a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatit under the terms of the GNU General Public License as published by
9a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatthe Free Software Foundation; either version 2 of the License, or (at
10a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatyour option) any later version.
11a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
12a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatx11vnc is distributed in the hope that it will be useful,
13a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatbut WITHOUT ANY WARRANTY; without even the implied warranty of
14a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatGNU General Public License for more details.
16a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
17a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatYou should have received a copy of the GNU General Public License
18a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatalong with x11vnc; if not, write to the Free Software
19a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehator see <http://www.gnu.org/licenses/>.
21a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
22a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatIn addition, as a special exception, Karl J. Runge
23a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatgives permission to link the code of its release of x11vnc with the
24a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatOpenSSL project's "OpenSSL" library (or with modified versions of it
25a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatthat use the same license as the "OpenSSL" library), and distribute
26a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatthe linked executables.  You must obey the GNU General Public License
27a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatin all respects for all of the code used other than "OpenSSL".  If you
28a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatmodify this file, you may extend this exception to your version of the
29a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatfile, but you are not obligated to do so.  If you do not wish to do
30a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatso, delete this exception statement from your version.
31a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat*/
32a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
33a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* -- keyboard.c -- */
34a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
35a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "x11vnc.h"
36a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "xwrappers.h"
37a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "xrecord.h"
38a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "xinerama.h"
39a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "pointer.h"
40a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "userinput.h"
41a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "win_utils.h"
42a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "rates.h"
43a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "cleanup.h"
44a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "allowed_input_t.h"
45a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "unixpw.h"
46a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "v4l.h"
47a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "linuxfb.h"
48a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "uinput.h"
49a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "macosx.h"
50a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#include "screen.h"
51a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
52a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid get_keystate(int *keystate);
53a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid clear_modifiers(int init);
54a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint track_mod_state(rfbKeySym keysym, rfbBool down, rfbBool set);
55a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid clear_keys(void);
56a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid clear_locks(void);
57a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint get_autorepeat_state(void);
58a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint get_initial_autorepeat_state(void);
59a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid autorepeat(int restore, int bequiet);
60a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid check_add_keysyms(void);
61a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint add_keysym(KeySym keysym);
62a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid delete_added_keycodes(int bequiet);
63a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_remap(char *infile);
64a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint sloppy_key_check(int key, rfbBool down, rfbKeySym keysym, int *new_kc);
65a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid switch_to_xkb_if_better(void);
66a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatchar *short_kmbcf(char *str);
67a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_allowed_input(void);
68a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_modtweak(void);
69a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_keyboard_and_pointer(void);
70a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid get_allowed_input(rfbClientPtr client, allowed_input_t *input);
71a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatdouble typing_rate(double time_window, int *repeating);
72a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint skip_cr_when_scaling(char *mode);
73a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
74a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
75a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
76a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void delete_keycode(KeyCode kc, int bequiet);
77a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int count_added_keycodes(void);
78a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void add_remap(char *line);
79a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void add_dead_keysyms(char *str);
80a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void initialize_xkb_modtweak(void);
81a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
82a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    rfbClientPtr client);
83a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void tweak_mod(signed char mod, rfbBool down);
84a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
85a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    rfbClientPtr client);
86a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
87a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
88a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
89a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
90a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Routine to retreive current state keyboard.  1 means down, 0 up.
91a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
92a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid get_keystate(int *keystate) {
93a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
94a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
95a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!keystate) {}
96a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return;
97a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
98a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, k;
99a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char keys[32];
100a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
101a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
102a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
103a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* n.b. caller decides to X_LOCK or not. */
104a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XQueryKeymap(dpy, keys);
105a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i=0; i<32; i++) {
106a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char c = keys[i];
107a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
108a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (k=0; k < 8; k++) {
109a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (c & 0x1) {
110a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				keystate[8*i + k] = 1;
111a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else {
112a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				keystate[8*i + k] = 0;
113a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
114a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			c = c >> 1;
115a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
116a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
117a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
118a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
119a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
120a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
121a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Try to KeyRelease any non-Lock modifiers that are down.
122a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
123a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid clear_modifiers(int init) {
124a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
125a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
126a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!init) {}
127a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return;
128a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
129a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static KeyCode keycodes[256];
130a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static KeySym  keysyms[256];
131a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static char *keystrs[256];
132a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static int kcount = 0, first = 1;
133a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int keystate[256];
134a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, j, minkey, maxkey, syms_per_keycode;
135a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym *keymap;
136a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym keysym;
137a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeyCode keycode;
138a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
139a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
140a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
141a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* n.b. caller decides to X_LOCK or not. */
142a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (first) {
143a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
144a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * we store results in static arrays, to aid interrupted
145a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * case, but modifiers could have changed during session...
146a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
147a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XDisplayKeycodes(dpy, &minkey, &maxkey);
148a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
149a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
150a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    &syms_per_keycode);
151a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
152a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i = minkey; i <= maxkey; i++) {
153a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    for (j = 0; j < syms_per_keycode; j++) {
154a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			char *str;
155a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keysym = keymap[ (i - minkey) * syms_per_keycode + j ];
156a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (keysym == NoSymbol || ! ismodkey(keysym)) {
157a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
158a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
159a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keycode = XKeysymToKeycode(dpy, keysym);
160a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (keycode == NoSymbol) {
161a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
162a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
163a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keycodes[kcount] = keycode;
164a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keysyms[kcount]  = keysym;
165a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			str = XKeysymToString(keysym);
166a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! str) str = "null";
167a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keystrs[kcount]  = strdup(str);
168a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			kcount++;
169a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    }
170a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
171a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XFree_wr((void *) keymap);
172a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		first = 0;
173a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
174a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (init) {
175a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
176a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
177a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
178a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	get_keystate(keystate);
179a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i=0; i < kcount; i++) {
180a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keysym  = keysyms[i];
181a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keycode = keycodes[i];
182a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
183a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! keystate[(int) keycode]) {
184a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
185a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
186a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
187a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (clear_mods) {
188a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("clear_modifiers: up: %-10s (0x%x) "
189a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    "keycode=0x%x\n", keystrs[i], keysym, keycode);
190a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
191a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime);
192a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
193a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFlush_wr(dpy);
194a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
195a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
196a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
197a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic KeySym simple_mods[] = {
198a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XK_Shift_L, XK_Shift_R,
199a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XK_Control_L, XK_Control_R,
200a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XK_Meta_L, XK_Meta_R,
201a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XK_Alt_L, XK_Alt_R,
202a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XK_Super_L, XK_Super_R,
203a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XK_Hyper_L, XK_Hyper_R,
204a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XK_Mode_switch,
205a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	NoSymbol
206a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat};
207a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define NSIMPLE_MODS 13
208a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
209a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint track_mod_state(rfbKeySym keysym, rfbBool down, rfbBool set) {
210a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym sym = (KeySym) keysym;
211a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static rfbBool isdown[NSIMPLE_MODS];
212a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static int first = 1;
213a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, cnt = 0;
214a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
215a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
216a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * simple tracking method for the modifier state without
217a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * contacting the Xserver.  Ignores, of course what keys are
218a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * pressed on the physical display.
219a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 *
220a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * This is unrelated to our mod_tweak and xkb stuff.
221a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * Just a simple thing for wireframe/scroll heuristics,
222a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * sloppy keys etc.
223a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
224a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
225a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (first) {
226a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<NSIMPLE_MODS; i++) {
227a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			isdown[i] = FALSE;
228a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
229a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		first = 0;
230a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
231a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
232a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (sym != NoSymbol) {
233a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<NSIMPLE_MODS; i++) {
234a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sym == simple_mods[i]) {
235a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (set) {
236a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					isdown[i] = down;
237a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					return 1;
238a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				} else {
239a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (isdown[i]) {
240a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						return 1;
241a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					} else {
242a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						return 0;
243a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
244a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
245a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				break;
246a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
247a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
248a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* not a modifier */
249a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (set) {
250a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return 0;
251a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
252a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return -1;
253a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
254a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
255a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
256a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* called with NoSymbol: return number currently pressed: */
257a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i=0; i<NSIMPLE_MODS; i++) {
258a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (isdown[i]) {
259a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			cnt++;
260a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
261a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
262a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return cnt;
263a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
264a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
265a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
266a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Attempt to set all keys to Up position.  Can mess up typing at the
267a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * physical keyboard so use with caution.
268a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
269a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid clear_keys(void) {
270a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int k, keystate[256];
271a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
272a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
273a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
274a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* n.b. caller decides to X_LOCK or not. */
275a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	get_keystate(keystate);
276a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (k=0; k<256; k++) {
277a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keystate[k]) {
278a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			KeyCode keycode = (KeyCode) k;
279a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("clear_keys: keycode=%d\n", keycode);
280a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime);
281a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
282a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
283a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFlush_wr(dpy);
284a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
285a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
286a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
287a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid clear_locks(void) {
288a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
289a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
290a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return;
291a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
292a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XModifierKeymap *map;
293a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, j, k = 0;
294a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	unsigned int state = 0;
295a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
296a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
297a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
298a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* n.b. caller decides to X_LOCK or not. */
299a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if LIBVNCSERVER_HAVE_XKEYBOARD
300a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (xkb_present) {
301a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XkbStateRec kbstate;
302a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
303a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("locked:  0x%x\n", kbstate.locked_mods);
304a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("latched: 0x%x\n", kbstate.latched_mods);
305a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("compat:  0x%x\n", kbstate.compat_state);
306a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		state = kbstate.locked_mods;
307a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! state) {
308a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			state = kbstate.compat_state;
309a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
310a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else
311a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
312a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	{
313a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		state = mask_state();
314a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* this may contain non-locks too... */
315a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("state:   0x%x\n", state);
316a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
317a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! state) {
318a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
319a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
320a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	map = XGetModifierMapping(dpy);
321a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! map) {
322a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
323a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
324a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i = 0; i < 8; i++) {
325a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int did = 0;
326a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (j = 0; j < map->max_keypermod; j++) {
327a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! did && state & (0x1 << i)) {
328a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (map->modifiermap[k]) {
329a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					KeyCode key = map->modifiermap[k];
330a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					KeySym ks = XKeycodeToKeysym(dpy, key, 0);
331a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					char *nm = XKeysymToString(ks);
332a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					rfbLog("toggling: %03d / %03d -- %s\n", key, ks, nm ? nm : "BadKey");
333a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					did = 1;
334a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					XTestFakeKeyEvent_wr(dpy, key, True, CurrentTime);
335a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					usleep(10*1000);
336a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					XTestFakeKeyEvent_wr(dpy, key, False, CurrentTime);
337a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					XFlush_wr(dpy);
338a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
339a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
340a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k++;
341a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
342a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
343a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFreeModifiermap(map);
344a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFlush_wr(dpy);
345a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbLog("state:   0x%x\n", mask_state());
346a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
347a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
348a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
349a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
350a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Kludge for -norepeat option: we turn off keystroke autorepeat in
351a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * the X server when clients are connected.  This may annoy people at
352a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * the physical display.  We do this because 'key down' and 'key up'
353a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * user input events may be separated by 100s of ms due to screen fb
354a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * processing or link latency, thereby inducing the X server to apply
355a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * autorepeat when it should not.  Since the *client* is likely doing
356a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * keystroke autorepeating as well, it kind of makes sense to shut it
357a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * off if no one is at the physical display...
358a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
359a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int save_auto_repeat = -1;
360a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
361a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint get_autorepeat_state(void) {
362a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
363a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET(0)
364a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return 0;
365a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
366a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XKeyboardState kstate;
367a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
368a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET(0)
369a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
370a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_LOCK;
371a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XGetKeyboardControl(dpy, &kstate);
372a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_UNLOCK;
373a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return kstate.global_auto_repeat;
374a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
375a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
376a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
377a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint get_initial_autorepeat_state(void) {
378a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (save_auto_repeat < 0) {
379a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		save_auto_repeat = get_autorepeat_state();
380a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
381a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return save_auto_repeat;
382a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
383a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
384a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid autorepeat(int restore, int bequiet) {
385a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
386a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
387a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!restore || !bequiet) {}
388a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return;
389a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
390a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int global_auto_repeat;
391a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XKeyboardControl kctrl;
392a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
393a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
394a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
395a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (restore) {
396a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (save_auto_repeat < 0) {
397a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;		/* nothing to restore */
398a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
399a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		global_auto_repeat = get_autorepeat_state();
400a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* read state and skip restore if equal (e.g. no clients) */
401a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (global_auto_repeat == save_auto_repeat) {
402a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
403a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
404a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
405a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_LOCK;
406a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		kctrl.auto_repeat_mode = save_auto_repeat;
407a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
408a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XFlush_wr(dpy);
409a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
410a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
411a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! bequiet && ! quiet) {
412a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("Restored X server key autorepeat to: %d\n",
413a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    save_auto_repeat);
414a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
415a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
416a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		global_auto_repeat = get_autorepeat_state();
417a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (save_auto_repeat < 0) {
418a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
419a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * we only remember the state at startup
420a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * to avoid confusing ourselves later on.
421a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
422a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			save_auto_repeat = global_auto_repeat;
423a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
424a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
425a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_LOCK;
426a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		kctrl.auto_repeat_mode = AutoRepeatModeOff;
427a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
428a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XFlush_wr(dpy);
429a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
430a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
431a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! bequiet && ! quiet) {
432a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("Disabled X server key autorepeat.\n");
433a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (no_repeat_countdown >= 0) {
434a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("  to force back on run: 'xset r on' (%d "
435a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "times)\n", no_repeat_countdown+1);
436a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
437a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
438a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
439a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
440a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
441a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
442a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
443a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * We periodically delete any keysyms we have added, this is to
444a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * lessen our effect on the X server state if we are terminated abruptly
445a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * and cannot clear them and also to clear out any strange little used
446a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * ones that would just fill up the keymapping.
447a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
448a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid check_add_keysyms(void) {
449a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static time_t last_check = 0;
450a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int clear_freq = 300, quiet = 1, count;
451a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	time_t now = time(NULL);
452a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
453a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (unixpw_in_progress) return;
454a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
455a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (now > last_check + clear_freq) {
456a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		count = count_added_keycodes();
457a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
458a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * only really delete if they have not typed recently
459a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * and we have added 8 or more.
460a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
461a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (now > last_keyboard_input + 5 && count >= 8) {
462a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			X_LOCK;
463a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			delete_added_keycodes(quiet);
464a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			X_UNLOCK;
465a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
466a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		last_check = now;
467a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
468a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
469a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
470a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic KeySym added_keysyms[0x100];
471a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
472a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* these are just for rfbLog messages: */
473a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic KeySym alltime_added_keysyms[1024];
474a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int alltime_len = 1024;
475a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int alltime_num = 0;
476a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
477a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint add_keysym(KeySym keysym) {
478a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static int first = 1;
479a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int n;
480a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
481a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (first) {
482a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (n=0; n < 0x100; n++) {
483a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			added_keysyms[n] = NoSymbol;
484a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
485a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		first = 0;
486a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
487a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET(0)
488a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!keysym) {}
489a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return 0;
490a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
491a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int minkey, maxkey, syms_per_keycode;
492a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int kc, ret = 0;
493a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym *keymap;
494a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
495a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (first) {
496a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (n=0; n < 0x100; n++) {
497a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			added_keysyms[n] = NoSymbol;
498a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
499a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		first = 0;
500a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
501a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
502a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET(0)
503a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
504a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (keysym == NoSymbol) {
505a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return 0;
506a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
507a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* there can be a race before MappingNotify */
508a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (n=0; n < 0x100; n++) {
509a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (added_keysyms[n] == keysym) {
510a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return n;
511a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
512a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
513a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
514a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XDisplayKeycodes(dpy, &minkey, &maxkey);
515a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
516a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    &syms_per_keycode);
517a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
518a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = minkey+1; kc <= maxkey; kc++) {
519a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int i, j, didmsg = 0, is_empty = 1;
520a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *str;
521a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		KeySym newks[8];
522a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
523a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (n=0; n < syms_per_keycode; n++) {
524a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (keymap[ (kc-minkey) * syms_per_keycode + n]
525a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    != NoSymbol) {
526a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				is_empty = 0;
527a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				break;
528a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
529a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
530a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! is_empty) {
531a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
532a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
533a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
534a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<8; i++) {
535a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			newks[i] = NoSymbol;
536a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
537a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (add_keysyms == 2) {
538a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			newks[0] = keysym;	/* XXX remove me */
539a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
540a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for(i=0; i < syms_per_keycode; i++) {
541a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				newks[i] = keysym;
542a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (i >= 7) break;
543a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
544a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
545a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
546a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XChangeKeyboardMapping(dpy, kc, syms_per_keycode,
547a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    newks, 1);
548a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
549a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (alltime_num >= alltime_len) {
550a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			didmsg = 1;	/* something weird */
551a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
552a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (j=0; j<alltime_num; j++) {
553a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (alltime_added_keysyms[j] == keysym) {
554a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					didmsg = 1;
555a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					break;
556a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
557a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
558a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
559a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! didmsg) {
560a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			str = XKeysymToString(keysym);
561a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("added missing keysym to X display: %03d "
562a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    "0x%x \"%s\"\n", kc, keysym, str ? str : "null");
563a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
564a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (alltime_num < alltime_len) {
565a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				alltime_added_keysyms[alltime_num++] = keysym;
566a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
567a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
568a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
569a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XFlush_wr(dpy);
570a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		added_keysyms[kc] = keysym;
571a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		ret = kc;
572a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		break;
573a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
574a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFree_wr(keymap);
575a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return ret;
576a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
577a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
578a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
579a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void delete_keycode(KeyCode kc, int bequiet) {
580a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
581a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
582a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!kc || !bequiet) {}
583a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return;
584a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
585a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int minkey, maxkey, syms_per_keycode, i;
586a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym *keymap;
587a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym ksym, newks[8];
588a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *str;
589a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
590a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
591a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
592a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XDisplayKeycodes(dpy, &minkey, &maxkey);
593a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
594a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    &syms_per_keycode);
595a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
596a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i=0; i<8; i++) {
597a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		newks[i] = NoSymbol;
598a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
599a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
600a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XChangeKeyboardMapping(dpy, kc, syms_per_keycode, newks, 1);
601a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
602a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! bequiet && ! quiet) {
603a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		ksym = XKeycodeToKeysym(dpy, kc, 0);
604a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		str = XKeysymToString(ksym);
605a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("deleted keycode from X display: %03d 0x%x \"%s\"\n",
606a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    kc, ksym, str ? str : "null");
607a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
608a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
609a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFree_wr(keymap);
610a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFlush_wr(dpy);
611a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
612a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
613a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
614a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int count_added_keycodes(void) {
615a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int kc, count = 0;
616a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = 0; kc < 0x100; kc++) {
617a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (added_keysyms[kc] != NoSymbol) {
618a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			count++;
619a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
620a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
621a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return count;
622a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
623a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
624a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid delete_added_keycodes(int bequiet) {
625a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int kc;
626a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = 0; kc < 0x100; kc++) {
627a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (added_keysyms[kc] != NoSymbol) {
628a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			delete_keycode(kc, bequiet);
629a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			added_keysyms[kc] = NoSymbol;
630a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
631a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
632a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
633a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
634a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
635a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * The following is for an experimental -remap option to allow the user
636a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * to remap keystrokes.  It is currently confusing wrt modifiers...
637a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
638a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehattypedef struct keyremap {
639a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym before;
640a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym after;
641a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int isbutton;
642a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	struct keyremap *next;
643a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} keyremap_t;
644a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
645a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic keyremap_t *keyremaps = NULL;
646a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
647a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void add_remap(char *line) {
648a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char str1[256], str2[256];
649a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym ksym1, ksym2;
650a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int isbtn = 0;
651a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	unsigned int i;
652a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static keyremap_t *current = NULL;
653a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	keyremap_t *remap;
654a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
655a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (sscanf(line, "%s %s", str1, str2) != 2) {
656a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLogEnable(1);
657a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("remap: invalid line: %s\n", line);
658a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		clean_up_exit(1);
659a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
660a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (sscanf(str1, "0x%x", &i) == 1) {
661a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		ksym1 = (KeySym) i;
662a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
663a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		ksym1 = XStringToKeysym(str1);
664a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
665a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (sscanf(str2, "0x%x", &i) == 1) {
666a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		ksym2 = (KeySym) i;
667a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
668a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		ksym2 = XStringToKeysym(str2);
669a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
670a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (ksym2 == NoSymbol) {
671a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (sscanf(str2, "Button%u", &i) == 1) {
672a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			ksym2 = (KeySym) i;
673a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			isbtn = 1;
674a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
675a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
676a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (ksym1 == NoSymbol || ksym2 == NoSymbol) {
677a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (strcasecmp(str2, "NoSymbol") && strcasecmp(str2, "None")) {
678a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("warning: skipping invalid remap line: %s", line);
679a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
680a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
681a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
682a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	remap = (keyremap_t *) malloc((size_t) sizeof(keyremap_t));
683a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	remap->before = ksym1;
684a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	remap->after  = ksym2;
685a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	remap->isbutton = isbtn;
686a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	remap->next   = NULL;
687a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
688a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbLog("remapping: (%s, 0x%x) -> (%s, 0x%x) isbtn=%d\n", str1,
689a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    ksym1, str2, ksym2, isbtn);
690a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
691a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (keyremaps == NULL) {
692a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keyremaps = remap;
693a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
694a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		current->next = remap;
695a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
696a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	current = remap;
697a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
698a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
699a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void add_dead_keysyms(char *str) {
700a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *p, *q;
701a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i;
702a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *list[] = {
703a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"g grave dead_grave",
704a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"a acute dead_acute",
705a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"c asciicircum dead_circumflex",
706a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"t asciitilde dead_tilde",
707a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"m macron dead_macron",
708a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"b breve dead_breve",
709a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"D abovedot dead_abovedot",
710a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"d diaeresis dead_diaeresis",
711a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"o degree dead_abovering",
712a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"A doubleacute dead_doubleacute",
713a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"r caron dead_caron",
714a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		"e cedilla dead_cedilla",
715a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		"x XXX-ogonek dead_ogonek", */
716a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		"x XXX-belowdot dead_belowdot", */
717a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		"x XXX-hook dead_hook", */
718a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		"x XXX-horn dead_horn", */
719a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		NULL
720a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	};
721a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
722a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	p = str;
723a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
724a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	while (*p != '\0') {
725a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (isspace((unsigned char) (*p))) {
726a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*p = '\0';
727a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
728a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		p++;
729a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
730a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
731a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!strcmp(str, "DEAD")) {
732a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i = 0; list[i] != NULL; i++) {
733a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			p = list[i] + 2;
734a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			add_remap(p);
735a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
736a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (!strcmp(str, "DEAD=missing")) {
737a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i = 0; list[i] != NULL; i++) {
738a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			KeySym ksym, ksym2;
739a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int inmap = 0;
740a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
741a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			p = strdup(list[i] + 2);
742a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			q = strchr(p, ' ');
743a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (q == NULL) {
744a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				free(p);
745a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
746a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
747a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*q = '\0';
748a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			ksym = XStringToKeysym(p);
749a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*q = ' ';
750a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ksym == NoSymbol) {
751a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				free(p);
752a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
753a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
754a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (XKeysymToKeycode(dpy, ksym)) {
755a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				inmap = 1;
756a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
757a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if LIBVNCSERVER_HAVE_XKEYBOARD
758a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! inmap && xkb_present && dpy) {
759a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int kc, grp, lvl;
760a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (kc = 0; kc < 0x100; kc++) {
761a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    for (grp = 0; grp < 4; grp++) {
762a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					for (lvl = 0; lvl < 8; lvl++) {
763a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						ksym2 = XkbKeycodeToKeysym(dpy,
764a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						    kc, grp, lvl);
765a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (ksym2 == NoSymbol) {
766a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							continue;
767a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
768a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (ksym2 == ksym) {
769a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							inmap = 1;
770a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							break;
771a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
772a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
773a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    }
774a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
775a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
776a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
777a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if ((ksym2 = 0)) {}
778a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
779a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! inmap) {
780a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				add_remap(p);
781a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
782a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			free(p);
783a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
784a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if ((p = strchr(str, '=')) != NULL) {
785a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while (*p != '\0') {
786a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (i = 0; list[i] != NULL; i++) {
787a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				q = list[i];
788a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (*p == *q) {
789a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					q += 2;
790a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					add_remap(q);
791a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					break;
792a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
793a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
794a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			p++;
795a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
796a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
797a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
798a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
799a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
800a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * process the -remap string (file or mapping string)
801a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
802a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_remap(char *infile) {
803a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	FILE *in;
804a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *p, *q, line[256];
805a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
806a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (keyremaps != NULL) {
807a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* free last remapping */
808a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keyremap_t *next_remap, *curr_remap = keyremaps;
809a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while (curr_remap != NULL) {
810a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			next_remap = curr_remap->next;
811a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			free(curr_remap);
812a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			curr_remap = next_remap;
813a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
814a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keyremaps = NULL;
815a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
816a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (infile == NULL || *infile == '\0') {
817a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* just unset remapping */
818a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
819a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
820a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
821a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	in = fopen(infile, "r");
822a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (in == NULL) {
823a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* assume cmd line key1-key2,key3-key4 */
824a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (strstr(infile, "DEAD") == infile) {
825a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			;
826a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (!strchr(infile, '-')) {
827a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLogEnable(1);
828a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("remap: cannot open: %s\n", infile);
829a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLogPerror("fopen");
830a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			clean_up_exit(1);
831a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
832a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if ((in = tmpfile()) == NULL) {
833a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLogEnable(1);
834a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("remap: cannot open tmpfile for %s\n", infile);
835a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLogPerror("tmpfile");
836a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			clean_up_exit(1);
837a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
838a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
839a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* copy in the string to file format */
840a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		p = infile;
841a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while (*p) {
842a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (*p == '-') {
843a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(in, " ");
844a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else if (*p == ',' || *p == ' ' ||  *p == '\t') {
845a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(in, "\n");
846a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else {
847a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(in, "%c", *p);
848a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
849a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			p++;
850a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
851a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		fprintf(in, "\n");
852a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		fflush(in);
853a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rewind(in);
854a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
855a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
856a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	while (fgets(line, 256, in) != NULL) {
857a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		p = lblanks(line);
858a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (*p == '\0') {
859a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
860a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
861a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (strchr(line, '#')) {
862a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
863a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
864a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
865a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (strstr(p, "DEAD") == p)  {
866a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			add_dead_keysyms(p);
867a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
868a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
869a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if ((q = strchr(line, '-')) != NULL) {
870a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* allow Keysym1-Keysym2 notation */
871a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*q = ' ';
872a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
873a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		add_remap(p);
874a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
875a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fclose(in);
876a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
877a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
878a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
879a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * preliminary support for using the Xkb (XKEYBOARD) extension for handling
880a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * user input.  inelegant, slow, and incomplete currently... but initial
881a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * tests show it is useful for some setups.
882a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
883a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehattypedef struct keychar {
884a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeyCode code;
885a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int group;
886a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int level;
887a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} keychar_t;
888a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
889a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* max number of key groups and shift levels we consider */
890a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define GRP 4
891a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define LVL 8
892a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int lvl_max, grp_max, kc_min, kc_max;
893a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic KeySym xkbkeysyms[0x100][GRP][LVL];
894a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic unsigned int xkbstate[0x100][GRP][LVL];
895a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic unsigned int xkbignore[0x100][GRP][LVL];
896a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic unsigned int xkbmodifiers[0x100][GRP][LVL];
897a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int multi_key[0x100], mode_switch[0x100], skipkeycode[0x100];
898a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int shift_keys[0x100];
899a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
900a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
901a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * for trying to order the keycodes to avoid problems, note the
902a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * *first* keycode bound to it.  kc_vec will be a permutation
903a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * of 1...256 to get them in the preferred order.
904a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
905a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int kc_vec[0x100];
906a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int kc1_shift, kc1_control, kc1_caplock, kc1_alt;
907a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int kc1_meta, kc1_numlock, kc1_super, kc1_hyper;
908a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int kc1_mode_switch, kc1_iso_level3_shift, kc1_multi_key;
909a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
910a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint sloppy_key_check(int key, rfbBool down, rfbKeySym keysym, int *new_kc) {
911a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!sloppy_keys) {
912a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return 0;
913a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
914a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
915a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET(0)
916a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
917a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!key || !down || !keysym || !new_kc) {}
918a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return 0;
919a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
920a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
921a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!down && !keycode_state[key] && !IsModifierKey(keysym)) {
922a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int i, cnt = 0, downkey = -1;
923a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int nmods_down = track_mod_state(NoSymbol, FALSE, FALSE);
924a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int mods_down[256];
925a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
926a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (nmods_down) {
927a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* tracking to skip down modifier keycodes. */
928a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for(i=0; i<256; i++) {
929a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				mods_down[i] = 0;
930a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
931a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			i = 0;
932a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			while (simple_mods[i] != NoSymbol) {
933a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				KeySym ksym = simple_mods[i];
934a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				KeyCode k = XKeysymToKeycode(dpy, ksym);
935a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (k != NoSymbol && keycode_state[(int) k]) {
936a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					mods_down[(int) k] = 1;
937a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
938a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
939a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				i++;
940a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
941a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
942a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
943a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * the keycode is already up... look for a single one
944a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * (non modifier) that is down
945a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
946a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<256; i++) {
947a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (keycode_state[i]) {
948a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (nmods_down && mods_down[i]) {
949a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					continue;
950a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
951a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				cnt++;
952a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				downkey = i;
953a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
954a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
955a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (cnt == 1) {
956a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
957a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    sloppy_keys: %d/0x%x "
958a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "-> %d/0x%x  (nmods: %d)\n", (int) key,
959a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    (int) key, downkey, downkey, nmods_down);
960a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
961a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*new_kc = downkey;
962a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return 1;
963a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
964a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
965a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return 0;
966a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
967a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
968a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
969a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if !LIBVNCSERVER_HAVE_XKEYBOARD || SKIP_XKB
970a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
971a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* empty functions for no xkb */
972a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void initialize_xkb_modtweak(void) {}
973a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
974a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    rfbClientPtr client) {
975a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!client || !down || !keysym) {} /* unused vars warning: */
976a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
977a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid switch_to_xkb_if_better(void) {}
978a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
979a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
980a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
981a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid switch_to_xkb_if_better(void) {
982a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym keysym, *keymap;
983a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int miss_noxkb[256], miss_xkb[256], missing_noxkb = 0, missing_xkb = 0;
984a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, j, k, n, minkey, maxkey, syms_per_keycode;
985a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int syms_gt_4 = 0;
986a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int kc, grp, lvl;
987a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
988a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* non-alphanumeric on us keyboard */
989a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym must_have[] = {
990a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_exclam,
991a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_at,
992a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_numbersign,
993a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_dollar,
994a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_percent,
995a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		XK_asciicircum, */
996a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_ampersand,
997a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_asterisk,
998a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_parenleft,
999a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_parenright,
1000a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_underscore,
1001a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_plus,
1002a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_minus,
1003a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_equal,
1004a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_bracketleft,
1005a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_bracketright,
1006a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_braceleft,
1007a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_braceright,
1008a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_bar,
1009a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_backslash,
1010a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_semicolon,
1011a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		XK_apostrophe, */
1012a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_colon,
1013a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_quotedbl,
1014a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_comma,
1015a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_period,
1016a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_less,
1017a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_greater,
1018a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_slash,
1019a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XK_question,
1020a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		XK_asciitilde, */
1021a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*		XK_grave, */
1022a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		NoSymbol
1023a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	};
1024a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1025a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! use_modifier_tweak || got_noxkb) {
1026a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
1027a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1028a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (use_xkb_modtweak) {
1029a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* already using it */
1030a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
1031a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1032a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
1033a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1034a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XDisplayKeycodes(dpy, &minkey, &maxkey);
1035a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1036a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
1037a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    &syms_per_keycode);
1038a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1039a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* handle alphabetic char with only one keysym (no upper + lower) */
1040a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i = minkey; i <= maxkey; i++) {
1041a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		KeySym lower, upper;
1042a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* 2nd one */
1043a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keysym = keymap[(i - minkey) * syms_per_keycode + 1];
1044a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym != NoSymbol) {
1045a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
1046a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1047a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* 1st one */
1048a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keysym = keymap[(i - minkey) * syms_per_keycode + 0];
1049a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym == NoSymbol) {
1050a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
1051a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1052a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XConvertCase(keysym, &lower, &upper);
1053a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (lower != upper) {
1054a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keymap[(i - minkey) * syms_per_keycode + 0] = lower;
1055a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keymap[(i - minkey) * syms_per_keycode + 1] = upper;
1056a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1057a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1058a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1059a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	k = 0;
1060a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	while (must_have[k] != NoSymbol) {
1061a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int gotit = 0;
1062a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		KeySym must = must_have[k];
1063a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i = minkey; i <= maxkey; i++) {
1064a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    for (j = 0; j < syms_per_keycode; j++) {
1065a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keysym = keymap[(i-minkey) * syms_per_keycode + j];
1066a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (j >= 4) {
1067a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    if (k == 0 && keysym != NoSymbol) {
1068a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* for k=0 count the high keysyms */
1069a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				syms_gt_4++;
1070a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard > 1) {
1071a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					char *str = XKeysymToString(keysym);
1072a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "- high keysym mapping"
1073a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    ": at %3d j=%d "
1074a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "'%s'\n", i, j, str ? str : "null");
1075a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1076a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    }
1077a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    continue;
1078a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1079a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (keysym == must) {
1080a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard > 1) {
1081a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					char *str = XKeysymToString(must);
1082a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "- at %3d j=%d found "
1083a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "'%s'\n", i, j, str ? str : "null");
1084a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1085a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* n.b. do not break, see syms_gt_4 above. */
1086a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				gotit = 1;
1087a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1088a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    }
1089a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1090a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! gotit) {
1091a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard > 1) {
1092a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				char *str = XKeysymToString(must);
1093a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				KeyCode kc = XKeysymToKeycode(dpy, must);
1094a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "- did not find 0x%lx '%s'\t"
1095a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "Ks2Kc: %d\n", must, str ? str:"null", kc);
1096a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc != None) {
1097a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					int j2;
1098a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					for(j2=0; j2<syms_per_keycode; j2++) {
1099a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						keysym = keymap[(kc-minkey) *
1100a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						    syms_per_keycode + j2];
1101a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						fprintf(stderr, "  %d=0x%lx",
1102a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						    j2, keysym);
1103a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1104a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "\n");
1105a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1106a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1107a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			missing_noxkb++;
1108a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			miss_noxkb[k] = 1;
1109a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
1110a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			miss_noxkb[k] = 0;
1111a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1112a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		k++;
1113a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1114a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	n = k;
1115a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1116a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFree_wr(keymap);
1117a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (missing_noxkb == 0 && syms_per_keycode > 4 && syms_gt_4 >= 0) {
1118a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* we used to have syms_gt_4 >= 8, now always on. */
1119a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! raw_fb_str) {
1120a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("\n");
1121a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("XKEYBOARD: number of keysyms per keycode %d is greater\n", syms_per_keycode);
1122a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  than 4 and %d keysyms are mapped above 4.\n", syms_gt_4);
1123a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  Automatically switching to -xkb mode.\n");
1124a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  If this makes the key mapping worse you can\n");
1125a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  disable it with the \"-noxkb\" option.\n");
1126a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  Also, remember \"-remap DEAD\" for accenting characters.\n");
1127a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("\n");
1128a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1129a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1130a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		use_xkb_modtweak = 1;
1131a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
1132a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1133a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (missing_noxkb == 0) {
1134a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! raw_fb_str) {
1135a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("\n");
1136a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("XKEYBOARD: all %d \"must have\" keysyms accounted for.\n", n);
1137a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  Not automatically switching to -xkb mode.\n");
1138a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  If some keys still cannot be typed, try using -xkb.\n");
1139a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("  Also, remember \"-remap DEAD\" for accenting characters.\n");
1140a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("\n");
1141a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1142a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
1143a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1144a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1145a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (k=0; k<n; k++) {
1146a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		miss_xkb[k] = 1;
1147a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1148a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1149a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = 0; kc < 0x100; kc++) {
1150a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    for (grp = 0; grp < GRP; grp++) {
1151a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (lvl = 0; lvl < LVL; lvl++) {
1152a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* look up the Keysym, if any */
1153a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keysym = XkbKeycodeToKeysym(dpy, kc, grp, lvl);
1154a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (keysym == NoSymbol) {
1155a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
1156a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1157a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (k=0; k<n; k++) {
1158a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (keysym == must_have[k]) {
1159a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					miss_xkb[k] = 0;
1160a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1161a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1162a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1163a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    }
1164a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1165a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1166a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (k=0; k<n; k++) {
1167a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (miss_xkb[k]) {
1168a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			missing_xkb++;
1169a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1170a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1171a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1172a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbLog("\n");
1173a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (missing_xkb < missing_noxkb) {
1174a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("XKEYBOARD:\n");
1175a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("Switching to -xkb mode to recover these keysyms:\n");
1176a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
1177a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("XKEYBOARD: \"must have\" keysyms better accounted"
1178a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    " for\n");
1179a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("under -noxkb mode: not switching to -xkb mode:\n");
1180a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1181a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1182a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbLog("   xkb  noxkb   Keysym  (\"X\" means present)\n");
1183a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbLog("   ---  -----   -----------------------------\n");
1184a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (k=0; k<n; k++) {
1185a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *xx, *xn, *name;
1186a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1187a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keysym = must_have[k];
1188a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym == NoSymbol) {
1189a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
1190a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1191a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (!miss_xkb[k] && !miss_noxkb[k]) {
1192a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
1193a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1194a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (miss_xkb[k]) {
1195a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xx = "   ";
1196a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
1197a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xx = " X ";
1198a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1199a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (miss_noxkb[k]) {
1200a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xn = "   ";
1201a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
1202a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xn = " X ";
1203a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1204a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		name = XKeysymToString(keysym);
1205a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("   %s  %s     0x%lx  %s\n", xx, xn, keysym,
1206a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    name ? name : "null");
1207a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1208a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbLog("\n");
1209a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1210a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (missing_xkb < missing_noxkb) {
1211a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("  If this makes the key mapping worse you can\n");
1212a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("  disable it with the \"-noxkb\" option.\n");
1213a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("\n");
1214a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1215a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		use_xkb_modtweak = 1;
1216a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1217a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
1218a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("  If some keys still cannot be typed, try using"
1219a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    " -xkb.\n");
1220a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("  Also, remember \"-remap DEAD\" for accenting"
1221a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    " characters.\n");
1222a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1223a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbLog("\n");
1224a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
1225a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1226a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* sets up all the keymapping info via Xkb API */
1227a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1228a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void initialize_xkb_modtweak(void) {
1229a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym ks;
1230a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int kc, grp, lvl, k;
1231a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	unsigned int state;
1232a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1233a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
1234a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Here is a guide:
1235a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1236a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatWorkarounds arrays:
1237a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1238a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatmulti_key[]     indicates which keycodes have Multi_key (Compose)
1239a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                bound to them.
1240a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatmode_switch[]   indicates which keycodes have Mode_switch (AltGr)
1241a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                bound to them.
1242a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatshift_keys[]    indicates which keycodes have Shift bound to them.
1243a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatskipkeycode[]   indicates which keycodes are to be skipped
1244a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                for any lookups from -skip_keycodes option.
1245a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1246a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatGroups and Levels, here is an example:
1247a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1248a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat      ^          --------
1249a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat      |      L2 | A   AE |
1250a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    shift       |        |
1251a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    level    L1 | a   ae |
1252a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                 --------
1253a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                  G1  G2
1254a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1255a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                  group ->
1256a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1257a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatTraditionally this it all a key could do.  L1 vs. L2 selected via Shift
1258a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatand G1 vs. G2 selected via Mode_switch.  Up to 4 Keysyms could be bound
1259a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatto a key.  See initialize_modtweak() for an example of using that type
1260a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatof keymap from XGetKeyboardMapping().
1261a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1262a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatXkb gives us up to 4 groups and 63 shift levels per key, with the
1263a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatsituation being potentially different for each key.  This is complicated,
1264a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatand I don't claim to understand it all, but in the following we just think
1265a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatof ranging over the group and level indices as covering all of the cases.
1266a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatThis gives us an accurate view of the keymap.  The main tricky part
1267a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatis mapping between group+level and modifier state.
1268a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1269a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatOn current linux/XFree86 setups (Xkb is enabled by default) the
1270a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatinformation from XGetKeyboardMapping() (evidently the compat map)
1271a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatis incomplete and inaccurate, so we are really forced to use the
1272a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatXkb API.
1273a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1274a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatxkbkeysyms[]      For a (keycode,group,level) holds the KeySym (0 for none)
1275a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatxkbstate[]        For a (keycode,group,level) holds the corresponding
1276a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                  modifier state needed to get that KeySym
1277a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatxkbignore[]       For a (keycode,group,level) which modifiers can be
1278a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                  ignored (the 0 bits can be ignored).
1279a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatxkbmodifiers[]    For the KeySym bound to this (keycode,group,level) store
1280a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat                  the modifier mask.
1281a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat *
1282a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
1283a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1284a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
1285a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1286a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* initialize all the arrays: */
1287a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = 0; kc < 0x100; kc++) {
1288a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		multi_key[kc] = 0;
1289a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		mode_switch[kc] = 0;
1290a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		skipkeycode[kc] = 0;
1291a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		shift_keys[kc] = 0;
1292a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1293a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (grp = 0; grp < GRP; grp++) {
1294a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (lvl = 0; lvl < LVL; lvl++) {
1295a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				xkbkeysyms[kc][grp][lvl] = NoSymbol;
1296a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				xkbmodifiers[kc][grp][lvl] = -1;
1297a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				xkbstate[kc][grp][lvl] = -1;
1298a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1299a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1300a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1301a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1302a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1303a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * the array is 256*LVL*GRP, but we can make the searched region
1304a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * smaller by computing the actual ranges.
1305a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1306a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	lvl_max = 0;
1307a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	grp_max = 0;
1308a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc_max = 0;
1309a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc_min = 0x100;
1310a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1311a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* first keycode for a modifier type (multi_key too) */
1312a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_shift = -1;
1313a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_control = -1;
1314a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_caplock = -1;
1315a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_alt = -1;
1316a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_meta = -1;
1317a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_numlock = -1;
1318a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_super = -1;
1319a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_hyper = -1;
1320a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_mode_switch = -1;
1321a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_iso_level3_shift = -1;
1322a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	kc1_multi_key = -1;
1323a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1324a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1325a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * loop over all possible (keycode, group, level) triples
1326a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * and record what we find for it:
1327a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1328a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
1329a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("initialize_xkb_modtweak: XKB keycode -> keysyms "
1330a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    "mapping info:\n");
1331a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1332a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = 0; kc < 0x100; kc++) {
1333a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    for (grp = 0; grp < GRP; grp++) {
1334a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (lvl = 0; lvl < LVL; lvl++) {
1335a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			unsigned int ms, mods;
1336a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int state_save = -1, mods_save = -1;
1337a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			KeySym ks2;
1338a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1339a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* look up the Keysym, if any */
1340a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			ks = XkbKeycodeToKeysym(dpy, kc, grp, lvl);
1341a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xkbkeysyms[kc][grp][lvl] = ks;
1342a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1343a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* if no Keysym, on to next */
1344a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == NoSymbol) {
1345a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
1346a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1347a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
1348a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * for various workarounds, note where these special
1349a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * keys are bound to.
1350a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
1351a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Multi_key) {
1352a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				multi_key[kc] = lvl+1;
1353a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1354a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Mode_switch) {
1355a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				mode_switch[kc] = lvl+1;
1356a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1357a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Shift_L || ks == XK_Shift_R) {
1358a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				shift_keys[kc] = lvl+1;
1359a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1360a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1361a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Shift_L || ks == XK_Shift_R) {
1362a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_shift == -1) {
1363a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_shift = kc;
1364a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1365a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1366a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Control_L || ks == XK_Control_R) {
1367a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_control == -1) {
1368a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_control = kc;
1369a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1370a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1371a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Caps_Lock || ks == XK_Caps_Lock) {
1372a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_caplock == -1) {
1373a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_caplock = kc;
1374a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1375a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1376a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Alt_L || ks == XK_Alt_R) {
1377a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_alt == -1) {
1378a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_alt = kc;
1379a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1380a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1381a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Meta_L || ks == XK_Meta_R) {
1382a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_meta == -1) {
1383a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_meta = kc;
1384a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1385a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1386a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Num_Lock) {
1387a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_numlock == -1) {
1388a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_numlock = kc;
1389a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1390a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1391a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Super_L || ks == XK_Super_R) {
1392a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_super == -1) {
1393a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_super = kc;
1394a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1395a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1396a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Hyper_L || ks == XK_Hyper_R) {
1397a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_hyper == -1) {
1398a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_hyper = kc;
1399a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1400a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1401a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Mode_switch) {
1402a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_mode_switch == -1) {
1403a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_mode_switch = kc;
1404a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1405a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1406a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_ISO_Level3_Shift) {
1407a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_iso_level3_shift == -1) {
1408a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_iso_level3_shift = kc;
1409a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1410a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1411a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (ks == XK_Multi_key) {	/* not a modifier.. */
1412a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (kc1_multi_key == -1) {
1413a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					kc1_multi_key = kc;
1414a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1415a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1416a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1417a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
1418a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * record maximum extent for group/level indices
1419a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * and keycode range:
1420a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
1421a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (grp > grp_max) {
1422a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				grp_max = grp;
1423a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1424a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (lvl > lvl_max) {
1425a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				lvl_max = lvl;
1426a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1427a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (kc > kc_max) {
1428a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				kc_max = kc;
1429a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1430a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (kc < kc_min) {
1431a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				kc_min = kc;
1432a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1433a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1434a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
1435a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * lookup on *keysym* (i.e. not kc, grp, lvl)
1436a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * and get the modifier mask.  this is 0 for
1437a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * most keysyms, only non zero for modifiers.
1438a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
1439a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			ms = XkbKeysymToModifiers(dpy, ks);
1440a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xkbmodifiers[kc][grp][lvl] = ms;
1441a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1442a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
1443a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Amusing heuristic (may have bugs).  There are
1444a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * 8 modifier bits, so 256 possible modifier
1445a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * states.  We loop over all of them for this
1446a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * keycode (simulating Key "events") and ask
1447a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * XkbLookupKeySym to tell us the Keysym.  Once it
1448a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * matches the Keysym we have for this (keycode,
1449a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * group, level), gotten via XkbKeycodeToKeysym()
1450a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * above, we then (hopefully...) know that state
1451a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * of modifiers needed to generate this keysym.
1452a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 *
1453a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Yes... keep your fingers crossed.
1454a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 *
1455a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Note that many of the 256 states give the
1456a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Keysym, we just need one, and we take the
1457a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * first one found.
1458a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
1459a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			state = 0;
1460a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			while(state < 256) {
1461a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (XkbLookupKeySym(dpy, kc, state, &mods,
1462a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    &ks2)) {
1463a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1464a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					/* save these for workaround below */
1465a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (state_save == -1) {
1466a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						state_save = state;
1467a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						mods_save = mods;
1468a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1469a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (ks2 == ks) {
1470a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						/*
1471a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						 * zero the irrelevant bits
1472a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						 * by anding with mods.
1473a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						 */
1474a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						xkbstate[kc][grp][lvl]
1475a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						    = state & mods;
1476a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						/*
1477a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						 * also remember the irrelevant
1478a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						 * bits since it is handy.
1479a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						 */
1480a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						xkbignore[kc][grp][lvl] = mods;
1481a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1482a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						break;
1483a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1484a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1485a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				state++;
1486a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1487a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (xkbstate[kc][grp][lvl] == (unsigned int) -1
1488a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    && grp == 1) {
1489a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/*
1490a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Hack on Solaris 9 for Mode_switch
1491a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * for Group2 characters.  We force the
1492a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Mode_switch modifier bit on.
1493a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * XXX Need to figure out better what is
1494a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * happening here.  Is compat on somehow??
1495a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 */
1496a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				unsigned int ms2;
1497a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				ms2 = XkbKeysymToModifiers(dpy, XK_Mode_switch);
1498a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1499a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				xkbstate[kc][grp][lvl]
1500a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    = (state_save & mods_save) | ms2;
1501a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1502a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				xkbignore[kc][grp][lvl] = mods_save | ms2;
1503a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1504a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1505a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
1506a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				char *str;
1507a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "  %03d  G%d L%d  mod=%s ",
1508a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    kc, grp+1, lvl+1, bitprint(ms, 8));
1509a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "state=%s ",
1510a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    bitprint(xkbstate[kc][grp][lvl], 8));
1511a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "ignore=%s ",
1512a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    bitprint(xkbignore[kc][grp][lvl], 8));
1513a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				str = XKeysymToString(ks);
1514a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, " ks=0x%08lx \"%s\"\n",
1515a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    ks, str ? str : "null");
1516a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1517a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1518a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    }
1519a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1520a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1521a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1522a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * kc_vec will be used in some places to find modifiers, etc
1523a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * we apply some permutations to it as workarounds.
1524a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1525a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = 0; kc < 0x100; kc++) {
1526a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		kc_vec[kc] = kc;
1527a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1528a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1529a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (kc1_mode_switch != -1 && kc1_iso_level3_shift != -1) {
1530a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (kc1_mode_switch < kc1_iso_level3_shift) {
1531a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* we prefer XK_ISO_Level3_Shift: */
1532a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			kc_vec[kc1_mode_switch] = kc1_iso_level3_shift;
1533a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			kc_vec[kc1_iso_level3_shift] = kc1_mode_switch;
1534a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1535a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1536a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* any more? need to watch for undoing the above. */
1537a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1538a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1539a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * process the user supplied -skip_keycodes string.
1540a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * This is presumably a list if "ghost" keycodes, the X server
1541a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * thinks they exist, but they do not.  ghosts can lead to
1542a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * ambiguities in the reverse map: Keysym -> KeyCode + Modstate,
1543a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * so if we can ignore them so much the better.  Presumably the
1544a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * user can never generate them from the physical keyboard.
1545a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * There may be other reasons to deaden some keys.
1546a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1547a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (skip_keycodes != NULL) {
1548a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *p, *str = strdup(skip_keycodes);
1549a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		p = strtok(str, ", \t\n\r");
1550a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while (p) {
1551a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k = 1;
1552a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sscanf(p, "%d", &k) != 1 || k < 0 || k >= 0x100) {
1553a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLogEnable(1);
1554a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("invalid skip_keycodes: %s %s\n",
1555a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    skip_keycodes, p);
1556a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				clean_up_exit(1);
1557a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1558a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			skipkeycode[k] = 1;
1559a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			p = strtok(NULL, ", \t\n\r");
1560a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1561a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		free(str);
1562a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1563a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
1564a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		fprintf(stderr, "grp_max=%d lvl_max=%d\n", grp_max, lvl_max);
1565a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1566a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
1567a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1568a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic short **score_hint = NULL;
1569a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
1570a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Called on user keyboard input.  Try to solve the reverse mapping
1571a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * problem: KeySym (from VNC client) => KeyCode(s) to press to generate
1572a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * it.  The one-to-many KeySym => KeyCode mapping makes it difficult, as
1573a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * does working out what changes to the modifier keypresses are needed.
1574a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
1575a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
1576a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    rfbClientPtr client) {
1577a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1578a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int kc, grp, lvl, i, kci;
1579a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int kc_f[0x100], grp_f[0x100], lvl_f[0x100], state_f[0x100], found;
1580a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int ignore_f[0x100];
1581a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	unsigned int state = 0;
1582a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1583a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1584a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* these are used for finding modifiers, etc */
1585a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XkbStateRec kbstate;
1586a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int got_kbstate = 0;
1587a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int Kc_f, Grp_f = 0, Lvl_f = 0;
1588a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#	define KLAST 10
1589a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static int Kc_last_down[KLAST];
1590a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static KeySym Ks_last_down[KLAST];
1591a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static int klast = 0, khints = 1, anydown = 1;
1592a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static int cnt = 0;
1593a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1594a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!client || !down || !keysym) {} /* unused vars warning: */
1595a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1596a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
1597a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1598a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_LOCK;
1599a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1600a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (klast == 0) {
1601a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int i, j;
1602a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<KLAST; i++) {
1603a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Kc_last_down[i] = -1;
1604a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Ks_last_down[i] = NoSymbol;
1605a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1606a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (getenv("NOKEYHINTS")) {
1607a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			khints = 0;
1608a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1609a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (getenv("NOANYDOWN")) {
1610a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			anydown = 0;
1611a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1612a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (getenv("KEYSDOWN")) {
1613a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			klast = atoi(getenv("KEYSDOWN"));
1614a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (klast < 1) klast = 1;
1615a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (klast > KLAST) klast = KLAST;
1616a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
1617a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			klast = 3;
1618a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1619a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (khints && score_hint == NULL) {
1620a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			score_hint = (short **) malloc(0x100 * sizeof(short *));
1621a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (i=0; i<0x100; i++) {
1622a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				score_hint[i] = (short *) malloc(0x100 * sizeof(short));
1623a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1624a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1625a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (i=0; i<0x100; i++) {
1626a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (j=0; j<0x100; j++) {
1627a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					score_hint[i][j] = -1;
1628a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1629a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1630a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1631a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1632a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	cnt++;
1633a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (cnt % 100 && khints && score_hint != NULL) {
1634a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int i, j;
1635a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<0x100; i++) {
1636a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (j=0; j<0x100; j++) {
1637a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				score_hint[i][j] = -1;
1638a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1639a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1640a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1641a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1642a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
1643a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *str = XKeysymToString(keysym);
1644a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1645a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (debug_keyboard > 1) {
1646a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("----------start-xkb_tweak_keyboard (%s) "
1647a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    "--------\n", down ? "DOWN" : "UP");
1648a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1649a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1650a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("xkb_tweak_keyboard: %s keysym=0x%x \"%s\"\n",
1651a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    down ? "down" : "up", (int) keysym, str ? str : "null");
1652a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1653a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1654a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1655a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * set everything to not-yet-found.
1656a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * these "found" arrays (*_f) let us dynamically consider the
1657a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * one-to-many Keysym -> Keycode issue.  we set the size at 256,
1658a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * but of course only very few will be found.
1659a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1660a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i = 0; i < 0x100; i++) {
1661a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		kc_f[i]    = -1;
1662a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		grp_f[i]   = -1;
1663a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		lvl_f[i]   = -1;
1664a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		state_f[i] = -1;
1665a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		ignore_f[i] = -1;
1666a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1667a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	found = 0;
1668a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1669a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1670a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * loop over all (keycode, group, level) triples looking for
1671a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * matching keysyms.  Amazingly this isn't slow (but maybe if
1672a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * you type really fast...).  Hash lookup into a linked list of
1673a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * (keycode,grp,lvl) triples would be the way to improve this
1674a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * in the future if needed.
1675a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1676a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (kc = kc_min; kc <= kc_max; kc++) {
1677a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    for (grp = 0; grp < grp_max+1; grp++) {
1678a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (lvl = 0; lvl < lvl_max+1; lvl++) {
1679a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (keysym != xkbkeysyms[kc][grp][lvl]) {
1680a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
1681a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1682a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* got a keysym match */
1683a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			state = xkbstate[kc][grp][lvl];
1684a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1685a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard > 1) {
1686a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				char *s1, *s2;
1687a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				s1 = XKeysymToString(XKeycodeToKeysym(dpy,
1688a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    kc, 0));
1689a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (! s1) s1 = "null";
1690a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				s2 = XKeysymToString(keysym);
1691a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (! s2) s2 = "null";
1692a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "  got match kc=%03d=0x%02x G%d"
1693a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    " L%d  ks=0x%x \"%s\"  (basesym: \"%s\")\n",
1694a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    kc, kc, grp+1, lvl+1, keysym, s2, s1);
1695a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    need state: %s\n",
1696a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    bitprint(state, 8));
1697a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    ignorable : %s\n",
1698a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    bitprint(xkbignore[kc][grp][lvl], 8));
1699a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1700a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1701a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* save it if state is OK and not told to skip */
1702a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (state == (unsigned int) -1) {
1703a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
1704a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1705a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (skipkeycode[kc] && debug_keyboard) {
1706a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    xxx skipping keycode: %d "
1707a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				   "G%d/L%d\n", kc, grp+1, lvl+1);
1708a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1709a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (skipkeycode[kc]) {
1710a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
1711a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1712a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (found > 0 && kc == kc_f[found-1]) {
1713a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* ignore repeats for same keycode */
1714a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
1715a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1716a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			kc_f[found] = kc;
1717a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			grp_f[found] = grp;
1718a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			lvl_f[found] = lvl;
1719a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			state_f[found] = state;
1720a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			ignore_f[found] = xkbignore[kc][grp][lvl];
1721a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			found++;
1722a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1723a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    }
1724a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1725a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1726a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define PKBSTATE  \
1727a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fprintf(stderr, "    --- current mod state:\n"); \
1728a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fprintf(stderr, "    mods      : %s\n", bitprint(kbstate.mods, 8)); \
1729a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fprintf(stderr, "    base_mods : %s\n", bitprint(kbstate.base_mods, 8)); \
1730a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fprintf(stderr, "    latch_mods: %s\n", bitprint(kbstate.latched_mods, 8)); \
1731a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fprintf(stderr, "    lock_mods : %s\n", bitprint(kbstate.locked_mods, 8)); \
1732a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fprintf(stderr, "    compat    : %s\n", bitprint(kbstate.compat_state, 8));
1733a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1734a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1735a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * Now get the current state of the keyboard from the X server.
1736a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * This seems to be the safest way to go as opposed to our
1737a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * keeping track of the modifier state on our own.  Again,
1738a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * this is fortunately not too slow.
1739a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1740a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1741a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard > 1) {
1742a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* get state early for debug output */
1743a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
1744a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		got_kbstate = 1;
1745a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		PKBSTATE
1746a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1747a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1748a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!found && add_keysyms && keysym && ! IsModifierKey(keysym)) {
1749a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int new_kc = add_keysym(keysym);
1750a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (new_kc != 0) {
1751a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			found = 1;
1752a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			kc_f[0] = new_kc;
1753a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			grp_f[0] = 0;
1754a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			lvl_f[0] = 0;
1755a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			state_f[0] = 0;
1756a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1757a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1758a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1759a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!found && debug_keyboard) {
1760a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *str = XKeysymToString(keysym);
1761a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		fprintf(stderr, "    *** NO key found for: 0x%x %s  "
1762a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    "*keystroke ignored*\n", keysym, str ? str : "null");
1763a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1764a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!found) {
1765a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
1766a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
1767a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1768a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1769a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
1770a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * we try to optimize here if found > 1
1771a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * e.g. minimize lvl or grp, or other things to give
1772a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * "safest" scenario to simulate the keystrokes.
1773a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
1774a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1775a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (found > 1) {
1776a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (down) {
1777a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int l, score[0x100];
1778a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int best = 0, best_score = -1;
1779a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* need to break the tie... */
1780a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! got_kbstate) {
1781a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
1782a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				got_kbstate = 1;
1783a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1784a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (khints && keysym < 0x100) {
1785a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int ks = (int) keysym, j;
1786a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (j=0; j< 0x100; j++) {
1787a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					score_hint[ks][j] = -1;
1788a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1789a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1790a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (l=0; l < found; l++) {
1791a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int myscore = 0, b = 0x1, i;
1792a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int curr, curr_state = kbstate.mods;
1793a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int need, need_state = state_f[l];
1794a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int ignore_state = ignore_f[l];
1795a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1796a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* see how many modifiers need to be changed */
1797a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (i=0; i<8; i++) {
1798a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					curr = b & curr_state;
1799a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					need = b & need_state;
1800a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (! (b & ignore_state)) {
1801a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						;
1802a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					} else if (curr == need) {
1803a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						;
1804a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					} else {
1805a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						myscore++;
1806a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1807a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					b = b << 1;
1808a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1809a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				myscore *= 100;
1810a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1811a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* throw in some minimization of lvl too: */
1812a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				myscore += 2*lvl_f[l] + grp_f[l];
1813a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1814a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/*
1815a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * XXX since we now internally track
1816a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * keycode_state[], we could throw that into
1817a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * the score as well.  I.e. if it is already
1818a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * down, it is pointless to think we can
1819a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * press it down further!  E.g.
1820a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 *   myscore += 1000 * keycode_state[kc_f[l]];
1821a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Also could watch multiple modifier
1822a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * problem, e.g. Shift+key -> Alt
1823a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * keycode = 125 on my keyboard.
1824a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 */
1825a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1826a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				score[l] = myscore;
1827a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard > 1) {
1828a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    *** score for "
1829a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "keycode %03d: %4d\n",
1830a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    kc_f[l], myscore);
1831a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1832a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (khints && keysym < 0x100 && kc_f[l] < 0x100) {
1833a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					score_hint[(int) keysym][kc_f[l]] = (short) score[l];
1834a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1835a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1836a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (l=0; l < found; l++) {
1837a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int myscore = score[l];
1838a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (best_score == -1 || myscore < best_score) {
1839a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					best = l;
1840a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					best_score = myscore;
1841a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1842a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1843a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Kc_f = kc_f[best];
1844a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Grp_f = grp_f[best];
1845a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Lvl_f = lvl_f[best];
1846a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			state = state_f[best];
1847a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1848a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
1849a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* up */
1850a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int i, Kc_loc = -1;
1851a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Kc_f = -1;
1852a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1853a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* first try the scores we remembered when the key went down: */
1854a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (khints && keysym < 0x100) {
1855a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* low keysyms, ascii, only */
1856a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int ks = (int) keysym;
1857a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int ok = 1, lbest = 0, l;
1858a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				short sbest = -1;
1859a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (l=0; l < found; l++) {
1860a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (kc_f[l] < 0x100) {
1861a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						int key = (int) kc_f[l];
1862a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (! keycode_state[key]) {
1863a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							continue;
1864a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
1865a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (score_hint[ks][key] < 0) {
1866a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							ok = 0;
1867a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							break;
1868a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
1869a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (sbest < 0 || score_hint[ks][key] < sbest) {
1870a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							sbest = score_hint[ks][key];
1871a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							lbest = l;
1872a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
1873a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					} else {
1874a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						ok = 0;
1875a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						break;
1876a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1877a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1878a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (ok && sbest != -1) {
1879a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					Kc_f = kc_f[lbest];
1880a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1881a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard && Kc_f != -1) {
1882a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    UP: found via score_hint, s/l=%d/%d\n",
1883a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    sbest, lbest);
1884a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1885a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1886a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1887a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* next look at our list of recently pressed down keys */
1888a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (Kc_f == -1) {
1889a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (i=klast-1; i>=0; i--) {
1890a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					/*
1891a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					 * some people type really fast and leave
1892a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					 * lots of keys down before releasing
1893a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					 * them.  this gives problem on weird
1894a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					 * qwerty+dvorak keymappings where each
1895a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					 * alpha character is on TWO keys.
1896a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					 */
1897a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (keysym == Ks_last_down[i]) {
1898a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						int l;
1899a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						for (l=0; l < found; l++) {
1900a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							if (Kc_last_down[i] == kc_f[l]) {
1901a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat								int key = (int) kc_f[l];
1902a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat								if (keycode_state[key]) {
1903a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat									Kc_f = Kc_last_down[i];
1904a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat									Kc_loc = i;
1905a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat									break;
1906a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat								}
1907a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							}
1908a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
1909a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1910a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (Kc_f != -1) {
1911a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						break;
1912a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1913a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1914a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard && Kc_f != -1) {
1915a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    UP: found via klast, i=%d\n", Kc_loc);
1916a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1917a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1918a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1919a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* next just check for "best" one that is down */
1920a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (Kc_f == -1 && anydown) {
1921a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int l;
1922a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int best = -1, lbest = 0;
1923a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/*
1924a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * If it is already down, that is
1925a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * a great hint.  Use it.
1926a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 *
1927a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * note: keycode_state is internal and
1928a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * ignores someone pressing keys on the
1929a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * physical display (but is updated
1930a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * periodically to clean out stale info).
1931a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 */
1932a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (l=0; l < found; l++) {
1933a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					int key = (int) kc_f[l];
1934a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					int j, jmatch = -1;
1935a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1936a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (! keycode_state[key]) {
1937a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						continue;
1938a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1939a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					/* break ties based on lowest XKeycodeToKeysym index */
1940a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					for (j=0; j<8; j++) {
1941a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						KeySym ks = XKeycodeToKeysym(dpy, kc_f[l], j);
1942a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (ks != NoSymbol && ks == keysym) {
1943a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							jmatch = j;
1944a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							break;
1945a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
1946a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1947a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (jmatch == -1) {
1948a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						continue;
1949a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1950a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (best == -1 || jmatch < best) {
1951a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						best = jmatch;
1952a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						lbest = l;
1953a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1954a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1955a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (best != -1) {
1956a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					Kc_f = kc_f[lbest];
1957a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1958a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard && Kc_f != -1) {
1959a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    UP: found via downlist, l=%d\n", lbest);
1960a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1961a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1962a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1963a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* next, use the first one found that is down */
1964a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (Kc_f == -1) {
1965a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int l;
1966a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				for (l=0; l < found; l++) {
1967a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					int key = (int) kc_f[l];
1968a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (keycode_state[key]) {
1969a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						Kc_f = kc_f[l];
1970a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						break;
1971a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
1972a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1973a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard && Kc_f != -1) {
1974a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    UP: set to first one down, kc_f[%d]!!\n", l);
1975a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1976a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1977a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1978a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* last, use the first one found */
1979a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (Kc_f == -1) {
1980a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* hope for the best... XXX check mods */
1981a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				Kc_f = kc_f[0];
1982a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard && Kc_f != -1) {
1983a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    UP: set to first one at all, kc_f[0]!!\n");
1984a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
1985a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
1986a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
1987a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
1988a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		Kc_f = kc_f[0];
1989a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		Grp_f = grp_f[0];
1990a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		Lvl_f = lvl_f[0];
1991a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		state = state_f[0];
1992a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
1993a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
1994a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard && found > 1) {
1995a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int l;
1996a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *str;
1997a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		fprintf(stderr, "    *** found more than one keycode: ");
1998a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (l = 0; l < found; l++) {
1999a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			fprintf(stderr, "%03d ", kc_f[l]);
2000a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2001a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (l = 0; l < found; l++) {
2002a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			str = XKeysymToString(XKeycodeToKeysym(dpy,kc_f[l],0));
2003a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			fprintf(stderr, " \"%s\"", str ? str : "null");
2004a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2005a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		fprintf(stderr, ", picked this one: %03d  (last down: %03d)\n",
2006a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    Kc_f, Kc_last_down[0]);
2007a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2008a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2009a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (sloppy_keys) {
2010a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int new_kc;
2011a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (sloppy_key_check(Kc_f, down, keysym, &new_kc)) {
2012a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Kc_f = new_kc;
2013a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2014a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2015a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2016a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (down) {
2017a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2018a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * need to set up the mods for tweaking and other workarounds
2019a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2020a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int needmods[8], sentmods[8], Ilist[8], keystate[256];
2021a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int involves_multi_key, shift_is_down;
2022a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int i, j, b, curr, need;
2023a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		unsigned int ms;
2024a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		KeySym ks;
2025a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		Bool dn;
2026a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2027a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* remember these to aid the subsequent up case: */
2028a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=KLAST-1; i >= 1; i--) {
2029a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Ks_last_down[i] = Ks_last_down[i-1];
2030a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			Kc_last_down[i] = Kc_last_down[i-1];
2031a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2032a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		Ks_last_down[0] = keysym;
2033a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		Kc_last_down[0] = Kc_f;
2034a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2035a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! got_kbstate) {
2036a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* get the current modifier state if we haven't yet */
2037a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
2038a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			got_kbstate = 1;
2039a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2040a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2041a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2042a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * needmods[] whether or not that modifier bit needs
2043a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *            something done to it.
2044a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *            < 0 means no,
2045a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *            0   means needs to go up.
2046a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *            1   means needs to go down.
2047a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *
2048a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * -1, -2, -3 are used for debugging info to indicate
2049a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * why nothing needs to be done with the modifier, see below.
2050a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *
2051a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * sentmods[] is the corresponding keycode to use
2052a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * to achieve the needmods[] requirement for the bit.
2053a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2054a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2055a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<8; i++) {
2056a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			needmods[i] = -1;
2057a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			sentmods[i] = 0;
2058a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2059a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2060a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2061a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * Loop over the 8 modifier bits and check if the current
2062a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * setting is what we need it to be or whether it should
2063a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * be changed (by us sending some keycode event)
2064a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *
2065a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * If nothing needs to be done to it record why:
2066a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *   -1  the modifier bit is ignored.
2067a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *   -2  the modifier bit is ignored, but is correct anyway.
2068a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 *   -3  the modifier bit is correct.
2069a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2070a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2071a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		b = 0x1;
2072a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<8; i++) {
2073a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			curr = b & kbstate.mods;
2074a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			need = b & state;
2075a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2076a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! (b & xkbignore[Kc_f][Grp_f][Lvl_f])) {
2077a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* irrelevant modifier bit */
2078a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				needmods[i] = -1;
2079a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (curr == need) needmods[i] = -2;
2080a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else if (curr == need) {
2081a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* already correct */
2082a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				needmods[i] = -3;
2083a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else if (! curr && need) {
2084a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* need it down */
2085a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				needmods[i] = 1;
2086a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else if (curr && ! need) {
2087a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/* need it up */
2088a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				needmods[i] = 0;
2089a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2090a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2091a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			b = b << 1;
2092a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2093a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2094a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2095a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * Again we dynamically probe the X server for information,
2096a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * this time for the state of all the keycodes.  Useful
2097a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * info, and evidently is not too slow...
2098a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2099a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		get_keystate(keystate);
2100a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2101a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2102a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * We try to determine if Shift is down (since that can
2103a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * screw up ISO_Level3_Shift manipulations).
2104a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2105a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		shift_is_down = 0;
2106a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2107a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (kc = kc_min; kc <= kc_max; kc++) {
2108a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (skipkeycode[kc] && debug_keyboard) {
2109a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    xxx skipping keycode: "
2110a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "%d\n", kc);
2111a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2112a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (skipkeycode[kc]) {
2113a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
2114a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2115a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (shift_keys[kc] && keystate[kc]) {
2116a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				shift_is_down = kc;
2117a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				break;
2118a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2119a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2120a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2121a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2122a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * Now loop over the modifier bits and try to deduce the
2123a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * keycode presses/release require to match the desired
2124a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * state.
2125a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2126a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<8; i++) {
2127a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (needmods[i] < 0 && debug_keyboard > 1) {
2128a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int k = -needmods[i] - 1;
2129a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				char *words[] = {"ignorable",
2130a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "bitset+ignorable", "bitset"};
2131a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    +++ needmods: mod=%d is "
2132a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "OK  (%s)\n", i, words[k]);
2133a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2134a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (needmods[i] < 0) {
2135a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
2136a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2137a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2138a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			b = 1 << i;
2139a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2140a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard > 1) {
2141a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    +++ needmods: mod=%d %s "
2142a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "need it to be: %d %s\n", i, bitprint(b, 8),
2143a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    needmods[i], needmods[i] ? "down" : "up");
2144a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2145a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2146a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
2147a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Again, an inefficient loop, this time just
2148a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * looking for modifiers...
2149a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 *
2150a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * note the use of kc_vec to prefer XK_ISO_Level3_Shift
2151a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * over XK_Mode_switch.
2152a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
2153a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			for (kci = kc_min; kci <= kc_max; kci++) {
2154a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			  for (grp = 0; grp < grp_max+1; grp++) {
2155a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    for (lvl = 0; lvl < lvl_max+1; lvl++) {
2156a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				int skip = 1, dbmsg = 0;
2157a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2158a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				kc = kc_vec[kci];
2159a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2160a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				ms = xkbmodifiers[kc][grp][lvl];
2161a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (! ms || ms != (unsigned int) b) {
2162a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					continue;
2163a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2164a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2165a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (skipkeycode[kc] && debug_keyboard) {
2166a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    fprintf(stderr, "    xxx skipping keycode:"
2167a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					" %d G%d/L%d\n", kc, grp+1, lvl+1);
2168a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2169a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (skipkeycode[kc]) {
2170a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					continue;
2171a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2172a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2173a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				ks = xkbkeysyms[kc][grp][lvl];
2174a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (! ks) {
2175a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					continue;
2176a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2177a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2178a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (ks == XK_Shift_L) {
2179a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					skip = 0;
2180a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				} else if (ks == XK_Shift_R) {
2181a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					skip = 0;
2182a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				} else if (ks == XK_Mode_switch) {
2183a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					skip = 0;
2184a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				} else if (ks == XK_ISO_Level3_Shift) {
2185a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					skip = 0;
2186a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2187a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2188a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (watch_capslock && kbstate.locked_mods & LockMask) {
2189a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    if (keysym >= 'A' && keysym <= 'Z') {
2190a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					if (ks == XK_Shift_L || ks == XK_Shift_R) {
2191a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (debug_keyboard > 1) {
2192a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							fprintf(stderr, "    A-Z caplock skip Shift\n");
2193a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
2194a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						skip = 1;
2195a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					} else if (ks == XK_Caps_Lock) {
2196a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						if (debug_keyboard > 1) {
2197a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat							fprintf(stderr, "    A-Z caplock noskip CapsLock\n");
2198a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						}
2199a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat						skip = 0;
2200a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					}
2201a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    }
2202a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2203a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/*
2204a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Alt, Meta, Control, Super,
2205a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Hyper, Num, Caps are skipped.
2206a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 *
2207a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * XXX need more work on Locks,
2208a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * and non-standard modifiers.
2209a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * (e.g. XF86_Next_VMode using
2210a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Ctrl+Alt)
2211a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 */
2212a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard > 1) {
2213a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					char *str = XKeysymToString(ks);
2214a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					int kt = keystate[kc];
2215a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    === for mod=%s "
2216a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "found kc=%03d/G%d/L%d it is %d "
2217a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "%s skip=%d (%s)\n", bitprint(b,8),
2218a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    kc, grp+1, lvl+1, kt, kt ?
2219a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "down" : "up  ", skip, str ?
2220a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    str : "null");
2221a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2222a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2223a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (! skip && needmods[i] !=
2224a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    keystate[kc] && sentmods[i] == 0) {
2225a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					sentmods[i] = kc;
2226a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					dbmsg = 1;
2227a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2228a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2229a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard > 1 && dbmsg) {
2230a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					int nm = needmods[i];
2231a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "    >>> we choose "
2232a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "kc=%03d=0x%02x to change it to: "
2233a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "%d %s\n", kc, kc, nm, nm ?
2234a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "down" : "up");
2235a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2236a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2237a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    }
2238a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			  }
2239a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2240a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2241a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<8; i++) {
2242a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
2243a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * reverse order is useful for tweaking
2244a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * ISO_Level3_Shift before Shift, but assumes they
2245a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * are in that order (i.e. Shift is first bit).
2246a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
2247a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int reverse = 1;
2248a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (reverse) {
2249a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				Ilist[i] = 7 - i;
2250a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else {
2251a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				Ilist[i] = i;
2252a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2253a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2254a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2255a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2256a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * check to see if Multi_key is bound to one of the Mods
2257a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * we have to tweak
2258a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2259a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		involves_multi_key = 0;
2260a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (j=0; j<8; j++) {
2261a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			i = Ilist[j];
2262a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sentmods[i] == 0) continue;
2263a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			dn = (Bool) needmods[i];
2264a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (!dn) continue;
2265a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (multi_key[sentmods[i]]) {
2266a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				involves_multi_key = i+1;
2267a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2268a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2269a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2270a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (involves_multi_key && shift_is_down && needmods[0] < 0) {
2271a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
2272a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Workaround for Multi_key and shift.
2273a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Assumes Shift is bit 1 (needmods[0])
2274a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
2275a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
2276a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    ^^^ trying to avoid "
2277a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "inadvertent Multi_key from Shift "
2278a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "(doing %03d up now)\n", shift_is_down);
2279a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2280a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XTestFakeKeyEvent_wr(dpy, shift_is_down, False,
2281a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    CurrentTime);
2282a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
2283a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			involves_multi_key = 0;
2284a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2285a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2286a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (j=0; j<8; j++) {
2287a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* do the Mod ups */
2288a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			i = Ilist[j];
2289a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sentmods[i] == 0) continue;
2290a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			dn = (Bool) needmods[i];
2291a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (dn) continue;
2292a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime);
2293a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2294a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (j=0; j<8; j++) {
2295a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* next, do the Mod downs */
2296a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			i = Ilist[j];
2297a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sentmods[i] == 0) continue;
2298a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			dn = (Bool) needmods[i];
2299a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (!dn) continue;
2300a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime);
2301a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2302a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2303a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (involves_multi_key) {
2304a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/*
2305a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 * Reverse workaround for Multi_key and shift.
2306a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			 */
2307a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
2308a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "    vvv trying to avoid "
2309a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "inadvertent Multi_key from Shift "
2310a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "(doing %03d down now)\n", shift_is_down);
2311a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2312a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XTestFakeKeyEvent_wr(dpy, shift_is_down, True,
2313a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    CurrentTime);
2314a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2315a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2316a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2317a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * With the above modifier work done, send the actual keycode:
2318a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2319a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime);
2320a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2321a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2322a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * Now undo the modifier work:
2323a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2324a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (j=7; j>=0; j--) {
2325a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* reverse Mod downs we did */
2326a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			i = Ilist[j];
2327a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sentmods[i] == 0) continue;
2328a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			dn = (Bool) needmods[i];
2329a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (!dn) continue;
2330a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn,
2331a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    CurrentTime);
2332a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2333a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (j=7; j>=0; j--) {
2334a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* finally reverse the Mod ups we did */
2335a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			i = Ilist[j];
2336a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sentmods[i] == 0) continue;
2337a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			dn = (Bool) needmods[i];
2338a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (dn) continue;
2339a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn,
2340a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    CurrentTime);
2341a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2342a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2343a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else { /* for up case, hopefully just need to pop it up: */
2344a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2345a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime);
2346a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2347a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_UNLOCK;
2348a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2349a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
2350a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2351a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
2352a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * For tweaking modifiers wrt the Alt-Graph key, etc.
2353a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
2354a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define LEFTSHIFT 1
2355a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define RIGHTSHIFT 2
2356a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define ALTGR 4
2357a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic char mod_state = 0;
2358a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2359a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic char modifiers[0x100];
2360a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic KeyCode keycodes[0x100];
2361a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic KeyCode left_shift_code, right_shift_code, altgr_code, iso_level3_code;
2362a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2363a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* workaround for X11R5, Latin 1 only */
2364a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#ifndef XConvertCase
2365a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define XConvertCase(sym, lower, upper) \
2366a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat*(lower) = sym; \
2367a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat*(upper) = sym; \
2368a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatif (sym >> 8 == 0) { \
2369a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    if ((sym >= XK_A) && (sym <= XK_Z)) \
2370a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat        *(lower) += (XK_a - XK_A); \
2371a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    else if ((sym >= XK_a) && (sym <= XK_z)) \
2372a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat        *(upper) -= (XK_a - XK_A); \
2373a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) \
2374a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat        *(lower) += (XK_agrave - XK_Agrave); \
2375a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) \
2376a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat        *(upper) -= (XK_agrave - XK_Agrave); \
2377a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) \
2378a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat        *(lower) += (XK_oslash - XK_Ooblique); \
2379a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    else if ((sym >= XK_oslash) && (sym <= XK_thorn)) \
2380a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat        *(upper) -= (XK_oslash - XK_Ooblique); \
2381a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2382a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
2383a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2384a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatchar *short_kmbcf(char *str) {
2385a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, saw_k = 0, saw_m = 0, saw_b = 0, saw_c = 0, saw_f = 0, n = 10;
2386a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *p, tmp[10];
2387a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2388a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i=0; i<n; i++) {
2389a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		tmp[i] = '\0';
2390a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2391a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2392a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	p = str;
2393a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	i = 0;
2394a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	while (*p) {
2395a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if ((*p == 'K' || *p == 'k') && !saw_k) {
2396a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			tmp[i++] = 'K';
2397a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			saw_k = 1;
2398a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if ((*p == 'M' || *p == 'm') && !saw_m) {
2399a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			tmp[i++] = 'M';
2400a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			saw_m = 1;
2401a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if ((*p == 'B' || *p == 'b') && !saw_b) {
2402a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			tmp[i++] = 'B';
2403a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			saw_b = 1;
2404a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if ((*p == 'C' || *p == 'c') && !saw_c) {
2405a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			tmp[i++] = 'C';
2406a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			saw_c = 1;
2407a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if ((*p == 'F' || *p == 'f') && !saw_f) {
2408a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			tmp[i++] = 'F';
2409a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			saw_f = 1;
2410a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2411a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		p++;
2412a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2413a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return(strdup(tmp));
2414a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2415a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2416a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_allowed_input(void) {
2417a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *str;
2418a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2419a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (allowed_input_normal) {
2420a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		free(allowed_input_normal);
2421a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		allowed_input_normal = NULL;
2422a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2423a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (allowed_input_view_only) {
2424a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		free(allowed_input_view_only);
2425a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		allowed_input_view_only = NULL;
2426a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2427a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2428a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! allowed_input_str) {
2429a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		allowed_input_normal = strdup("KMBCF");
2430a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		allowed_input_view_only = strdup("");
2431a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
2432a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *p, *str = strdup(allowed_input_str);
2433a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		p = strchr(str, ',');
2434a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (p) {
2435a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			allowed_input_view_only = strdup(p+1);
2436a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*p = '\0';
2437a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			allowed_input_normal = strdup(str);
2438a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
2439a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			allowed_input_normal = strdup(str);
2440a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			allowed_input_view_only = strdup("");
2441a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2442a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		free(str);
2443a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2444a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2445a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* shorten them */
2446a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	str = short_kmbcf(allowed_input_normal);
2447a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	free(allowed_input_normal);
2448a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	allowed_input_normal = str;
2449a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2450a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	str = short_kmbcf(allowed_input_view_only);
2451a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	free(allowed_input_view_only);
2452a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	allowed_input_view_only = str;
2453a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2454a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (screen) {
2455a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbClientIteratorPtr iter;
2456a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbClientPtr cl;
2457a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2458a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		iter = rfbGetClientIterator(screen);
2459a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while( (cl = rfbClientIteratorNext(iter)) ) {
2460a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			ClientData *cd = (ClientData *) cl->clientData;
2461a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2462a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! cd) {
2463a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
2464a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2465a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if 0
2466a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatrfbLog("cd: %p\n", cd);
2467a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatrfbLog("cd->input: %s\n", cd->input);
2468a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatrfbLog("cd->login_viewonly: %d\n", cd->login_viewonly);
2469a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatrfbLog("allowed_input_view_only: %s\n", allowed_input_view_only);
2470a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
2471a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2472a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (cd->input[0] == '=') {
2473a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				;	/* custom setting */
2474a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else if (cd->login_viewonly) {
2475a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (*allowed_input_view_only != '\0') {
2476a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					cl->viewOnly = FALSE;
2477a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					cd->input[0] = '\0';
2478a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					strncpy(cd->input,
2479a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    allowed_input_view_only, CILEN);
2480a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				} else {
2481a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					cl->viewOnly = TRUE;
2482a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2483a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else {
2484a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (allowed_input_normal) {
2485a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					cd->input[0] = '\0';
2486a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					strncpy(cd->input,
2487a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    allowed_input_normal, CILEN);
2488a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2489a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2490a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2491a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbReleaseClientIterator(iter);
2492a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2493a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2494a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2495a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_modtweak(void) {
2496a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
2497a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
2498a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return;
2499a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
2500a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym keysym, *keymap;
2501a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, j, minkey, maxkey, syms_per_keycode;
2502a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int use_lowest_index = 0;
2503a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2504a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (use_xkb_modtweak) {
2505a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		initialize_xkb_modtweak();
2506a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
2507a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2508a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	memset(modifiers, -1, sizeof(modifiers));
2509a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i=0; i<0x100; i++) {
2510a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keycodes[i] = NoSymbol;
2511a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2512a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2513a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
2514a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2515a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (getenv("MODTWEAK_LOWEST")) {
2516a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		use_lowest_index = 1;
2517a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2518a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2519a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_LOCK;
2520a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XDisplayKeycodes(dpy, &minkey, &maxkey);
2521a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2522a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
2523a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    &syms_per_keycode);
2524a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2525a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/* handle alphabetic char with only one keysym (no upper + lower) */
2526a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i = minkey; i <= maxkey; i++) {
2527a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		KeySym lower, upper;
2528a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* 2nd one */
2529a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keysym = keymap[(i - minkey) * syms_per_keycode + 1];
2530a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym != NoSymbol) {
2531a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
2532a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2533a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* 1st one */
2534a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keysym = keymap[(i - minkey) * syms_per_keycode + 0];
2535a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym == NoSymbol) {
2536a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
2537a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2538a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XConvertCase(keysym, &lower, &upper);
2539a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (lower != upper) {
2540a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keymap[(i - minkey) * syms_per_keycode + 0] = lower;
2541a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keymap[(i - minkey) * syms_per_keycode + 1] = upper;
2542a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2543a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2544a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i = minkey; i <= maxkey; i++) {
2545a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (debug_keyboard) {
2546a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (i == minkey) {
2547a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("initialize_modtweak: keycode -> "
2548a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    "keysyms mapping info:\n");
2549a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2550a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			fprintf(stderr, "  %03d  ", i);
2551a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2552a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (j = 0; j < syms_per_keycode; j++) {
2553a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
2554a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				char *sym;
2555a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if 0
2556a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				sym =XKeysymToString(XKeycodeToKeysym(dpy,i,j));
2557a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
2558a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				keysym = keymap[(i-minkey)*syms_per_keycode+j];
2559a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				sym = XKeysymToString(keysym);
2560a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
2561a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				fprintf(stderr, "%-18s ", sym ? sym : "null");
2562a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (j == syms_per_keycode - 1) {
2563a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					fprintf(stderr, "\n");
2564a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2565a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2566a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (j >= 4) {
2567a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				/*
2568a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Something wacky in the keymapping.
2569a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * Ignore these non Shift/AltGr chords
2570a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * for now... n.b. we try to automatically
2571a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 * switch to -xkb for this case.
2572a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				 */
2573a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
2574a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2575a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keysym = keymap[ (i - minkey) * syms_per_keycode + j ];
2576a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if ( keysym >= ' ' && keysym < 0x100
2577a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    && i == XKeysymToKeycode(dpy, keysym) ) {
2578a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (use_lowest_index && keycodes[keysym] != NoSymbol) {
2579a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					continue;
2580a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2581a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				keycodes[keysym] = i;
2582a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				modifiers[keysym] = j;
2583a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2584a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2585a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2586a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2587a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	left_shift_code = XKeysymToKeycode(dpy, XK_Shift_L);
2588a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	right_shift_code = XKeysymToKeycode(dpy, XK_Shift_R);
2589a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	altgr_code = XKeysymToKeycode(dpy, XK_Mode_switch);
2590a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	iso_level3_code = NoSymbol;
2591a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#ifdef XK_ISO_Level3_Shift
2592a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	iso_level3_code = XKeysymToKeycode(dpy, XK_ISO_Level3_Shift);
2593a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
2594a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2595a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	XFree_wr ((void *) keymap);
2596a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2597a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_UNLOCK;
2598a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
2599a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2600a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2601a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
2602a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * does the actual tweak:
2603a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
2604a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void tweak_mod(signed char mod, rfbBool down) {
2605a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbBool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT);
2606a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	Bool dn = (Bool) down;
2607a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeyCode altgr = altgr_code;
2608a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2609a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
2610a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2611a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (mod < 0) {
2612a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (debug_keyboard) {
2613a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("tweak_mod: Skip:  down=%d index=%d\n", down,
2614a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    (int) mod);
2615a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2616a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
2617a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2618a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
2619a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("tweak_mod: Start:  down=%d index=%d mod_state=0x%x"
2620a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    " is_shift=%d\n", down, (int) mod, (int) mod_state,
2621a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    is_shift);
2622a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2623a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2624a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (use_iso_level3 && iso_level3_code) {
2625a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		altgr = iso_level3_code;
2626a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2627a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2628a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_LOCK;
2629a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (is_shift && mod != 1) {
2630a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    if (mod_state & LEFTSHIFT) {
2631a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XTestFakeKeyEvent_wr(dpy, left_shift_code, !dn, CurrentTime);
2632a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    }
2633a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    if (mod_state & RIGHTSHIFT) {
2634a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XTestFakeKeyEvent_wr(dpy, right_shift_code, !dn, CurrentTime);
2635a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    }
2636a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2637a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if ( ! is_shift && mod == 1 ) {
2638a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    XTestFakeKeyEvent_wr(dpy, left_shift_code, dn, CurrentTime);
2639a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2640a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if ( altgr && (mod_state & ALTGR) && mod != 2 ) {
2641a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    XTestFakeKeyEvent_wr(dpy, altgr, !dn, CurrentTime);
2642a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2643a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if ( altgr && ! (mod_state & ALTGR) && mod == 2 ) {
2644a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    XTestFakeKeyEvent_wr(dpy, altgr, dn, CurrentTime);
2645a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2646a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_UNLOCK;
2647a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2648a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
2649a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("tweak_mod: Finish: down=%d index=%d mod_state=0x%x"
2650a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    " is_shift=%d\n", down, (int) mod, (int) mod_state,
2651a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    is_shift);
2652a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2653a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2654a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2655a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
2656a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * tweak the modifier under -modtweak
2657a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
2658a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
2659a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat    rfbClientPtr client) {
2660a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#if NO_X11
2661a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
2662a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!down || !keysym || !client) {}
2663a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return;
2664a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
2665a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeyCode k;
2666a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int tweak = 0;
2667a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2668a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
2669a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2670a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (use_xkb_modtweak) {
2671a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		xkb_tweak_keyboard(down, keysym, client);
2672a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
2673a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2674a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
2675a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("modifier_tweak_keyboard: %s keysym=0x%x\n",
2676a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    down ? "down" : "up", (int) keysym);
2677a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2678a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2679a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define ADJUSTMOD(sym, state) \
2680a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (keysym == sym) { \
2681a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (down) { \
2682a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			mod_state |= state; \
2683a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else { \
2684a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			mod_state &= ~state; \
2685a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} \
2686a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2687a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2688a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	ADJUSTMOD(XK_Shift_L, LEFTSHIFT)
2689a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	ADJUSTMOD(XK_Shift_R, RIGHTSHIFT)
2690a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	ADJUSTMOD(XK_Mode_switch, ALTGR)
2691a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2692a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if ( down && keysym >= ' ' && keysym < 0x100 ) {
2693a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		unsigned int state = 0;
2694a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		tweak = 1;
2695a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (watch_capslock && keysym >= 'A' && keysym <= 'Z') {
2696a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			X_LOCK;
2697a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			state = mask_state();
2698a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			X_UNLOCK;
2699a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2700a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (state & LockMask) {
2701a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* capslock set for A-Z, so no tweak */
2702a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			X_LOCK;
2703a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k = XKeysymToKeycode(dpy, (KeySym) keysym);
2704a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			X_UNLOCK;
2705a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			tweak = 0;
2706a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
2707a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			tweak_mod(modifiers[keysym], True);
2708a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k = keycodes[keysym];
2709a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2710a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
2711a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_LOCK;
2712a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		k = XKeysymToKeycode(dpy, (KeySym) keysym);
2713a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
2714a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2715a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) {
2716a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int new_kc = add_keysym(keysym);
2717a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (new_kc) {
2718a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k = new_kc;
2719a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2720a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2721a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2722a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (sloppy_keys) {
2723a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int new_kc;
2724a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (sloppy_key_check((int) k, down, keysym, &new_kc)) {
2725a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k = (KeyCode) new_kc;
2726a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2727a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2728a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2729a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
2730a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *str = XKeysymToString(keysym);
2731a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("modifier_tweak_keyboard: KeySym 0x%x \"%s\" -> "
2732a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    "KeyCode 0x%x%s\n", (int) keysym, str ? str : "null",
2733a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    (int) k, k ? "" : " *ignored*");
2734a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2735a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if ( k != NoSymbol ) {
2736a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_LOCK;
2737a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime);
2738a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
2739a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2740a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2741a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if ( tweak ) {
2742a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		tweak_mod(modifiers[keysym], False);
2743a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2744a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif	/* NO_X11 */
2745a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2746a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2747a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid initialize_keyboard_and_pointer(void) {
2748a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2749a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#ifdef MACOSX
2750a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (macosx_console) {
2751a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		initialize_remap(remap_file);
2752a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		initialize_pointer_map(pointer_remap);
2753a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2754a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
2755a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2756a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
2757a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2758a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (use_modifier_tweak) {
2759a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		initialize_modtweak();
2760a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2761a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2762a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	initialize_remap(remap_file);
2763a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	initialize_pointer_map(pointer_remap);
2764a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2765a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_LOCK;
2766a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	clear_modifiers(1);
2767a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (clear_mods == 1) {
2768a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		clear_modifiers(0);
2769a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2770a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (clear_mods == 3) {
2771a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		clear_locks();
2772a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2773a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_UNLOCK;
2774a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2775a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2776a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid get_allowed_input(rfbClientPtr client, allowed_input_t *input) {
2777a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	ClientData *cd;
2778a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *str;
2779a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2780a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	input->keystroke = 0;
2781a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	input->motion    = 0;
2782a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	input->button    = 0;
2783a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	input->clipboard = 0;
2784a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	input->files     = 0;
2785a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2786a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! client) {
2787a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		input->keystroke = 1;
2788a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		input->motion    = 1;
2789a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		input->button    = 1;
2790a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		input->clipboard = 1;
2791a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		input->files     = 1;
2792a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
2793a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2794a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2795a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	cd = (ClientData *) client->clientData;
2796a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2797a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! cd) {
2798a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
2799a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2800a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2801a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (cd->input[0] != '-') {
2802a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		str = cd->input;
2803a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (client->viewOnly) {
2804a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (allowed_input_view_only) {
2805a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			str = allowed_input_view_only;
2806a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
2807a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			str = "";
2808a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2809a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
2810a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (allowed_input_normal) {
2811a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			str = allowed_input_normal;
2812a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
2813a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			str = "KMBCF";
2814a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2815a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2816a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatif (0) fprintf(stderr, "GAI: %s - %s\n", str, cd->input);
2817a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2818a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	while (*str) {
2819a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (*str == 'K') {
2820a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			input->keystroke = 1;
2821a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (*str == 'M') {
2822a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			input->motion = 1;
2823a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (*str == 'B') {
2824a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			input->button = 1;
2825a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (*str == 'C') {
2826a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			input->clipboard = 1;
2827a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (*str == 'F') {
2828a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			input->files = 1;
2829a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2830a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		str++;
2831a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2832a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2833a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2834a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void apply_remap(rfbKeySym *keysym, int *isbutton) {
2835a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (keyremaps) {
2836a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		keyremap_t *remap = keyremaps;
2837a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while (remap != NULL) {
2838a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (remap->before == *keysym) {
2839a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				*keysym = remap->after;
2840a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				*isbutton = remap->isbutton;
2841a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				if (debug_keyboard) {
2842a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					char *str1, *str2;
2843a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					X_LOCK;
2844a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					str1 = XKeysymToString(remap->before);
2845a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					str2 = XKeysymToString(remap->after);
2846a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					rfbLog("keyboard(): remapping keysym: "
2847a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    "0x%x \"%s\" -> 0x%x \"%s\"\n",
2848a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    (int) remap->before,
2849a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    str1 ? str1 : "null",
2850a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    (int) remap->after,
2851a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    remap->isbutton ? "button" :
2852a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					    str2 ? str2 : "null");
2853a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat					X_UNLOCK;
2854a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				}
2855a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				break;
2856a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2857a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			remap = remap->next;
2858a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2859a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2860a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2861a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2862a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* for -pipeinput mode */
2863a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
2864a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int can_input = 0, uid = 0, isbutton = 0;
2865a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	allowed_input_t input;
2866a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	char *name;
2867a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	ClientData *cd = (ClientData *) client->clientData;
2868a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2869a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	apply_remap(&keysym, &isbutton);
2870a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2871a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (isbutton) {
2872a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int mask, button = (int) keysym;
2873a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int x = cursor_x, y = cursor_y;
2874a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *b, bstr[32];
2875a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2876a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (!down) {
2877a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
2878a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2879a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (debug_keyboard) {
2880a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("keyboard(): remapping keystroke to button %d"
2881a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    " click\n", button);
2882a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2883a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		dtime0(&last_key_to_button_remap_time);
2884a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2885a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
2886a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * This in principle can be a little dicey... i.e. even
2887a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * remap the button click to keystroke sequences!
2888a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * Usually just will simulate the button click.
2889a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
2890a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2891a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* loop over possible multiclicks: Button123 */
2892a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		sprintf(bstr, "%d", button);
2893a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		b = bstr;
2894a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while (*b != '\0') {
2895a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			char t[2];
2896a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int butt;
2897a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			t[0] = *b;
2898a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			t[1] = '\0';
2899a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sscanf(t, "%d", &butt) == 1) {
2900a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				mask = 1<<(butt-1);
2901a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				pointer_event(mask, x, y, client);
2902a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				mask = 0;
2903a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				pointer_event(mask, x, y, client);
2904a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
2905a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			b++;
2906a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2907a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
2908a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2909a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2910a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (pipeinput_int == PIPEINPUT_VID) {
2911a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		v4l_key_command(down, keysym, client);
2912a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (pipeinput_int == PIPEINPUT_CONSOLE) {
2913a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		console_key_command(down, keysym, client);
2914a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (pipeinput_int == PIPEINPUT_UINPUT) {
2915a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		uinput_key_command(down, keysym, client);
2916a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (pipeinput_int == PIPEINPUT_MACOSX) {
2917a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		macosx_key_command(down, keysym, client);
2918a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (pipeinput_int == PIPEINPUT_VNC) {
2919a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		vnc_reflect_send_key((uint32_t) keysym, down);
2920a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2921a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (pipeinput_fh == NULL) {
2922a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
2923a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2924a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2925a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! view_only) {
2926a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		get_allowed_input(client, &input);
2927a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (input.keystroke) {
2928a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			can_input = 1;	/* XXX distinguish later */
2929a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2930a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2931a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (cd) {
2932a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		uid = cd->uid;
2933a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2934a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! can_input) {
2935a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		uid = -uid;
2936a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2937a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2938a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_LOCK;
2939a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	name = XKeysymToString(keysym);
2940a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_UNLOCK;
2941a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2942a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fprintf(pipeinput_fh, "Keysym %d %d %u %s %s\n", uid, down,
2943a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	    keysym, name ? name : "null", down ? "KeyPress" : "KeyRelease");
2944a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2945a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	fflush(pipeinput_fh);
2946a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	check_pipeinput();
2947a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
2948a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2949a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehattypedef struct keyevent {
2950a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbKeySym sym;
2951a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	rfbBool down;
2952a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	double time;
2953a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} keyevent_t;
2954a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2955a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define KEY_HIST 256
2956a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic int key_history_idx = -1;
2957a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic keyevent_t key_history[KEY_HIST];
2958a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2959a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatdouble typing_rate(double time_window, int *repeating) {
2960a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	double dt = 1.0, now = dnow();
2961a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeySym key = NoSymbol;
2962a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int i, idx, cnt = 0, repeat_keys = 0;
2963a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2964a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (key_history_idx == -1) {
2965a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (repeating) {
2966a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*repeating = 0;
2967a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2968a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return 0.0;
2969a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2970a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (time_window > 0.0) {
2971a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		dt = time_window;
2972a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2973a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	for (i=0; i<KEY_HIST; i++) {
2974a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		idx = key_history_idx - i;
2975a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (idx < 0) {
2976a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			idx += KEY_HIST;
2977a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2978a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! key_history[idx].down) {
2979a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			continue;
2980a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2981a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (now > key_history[idx].time + dt) {
2982a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			break;
2983a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2984a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		cnt++;
2985a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (key == NoSymbol) {
2986a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			key = key_history[idx].sym;
2987a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			repeat_keys = 1;
2988a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (key == key_history[idx].sym) {
2989a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			repeat_keys++;
2990a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2991a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
2992a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
2993a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (repeating) {
2994a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (repeat_keys >= 2) {
2995a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*repeating = repeat_keys;
2996a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
2997a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			*repeating = 0;
2998a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
2999a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3000a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3001a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	/*
3002a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * n.b. keyrate could seem very high with libvncserver buffering them
3003a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 * so avoid using small dt.
3004a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	 */
3005a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	return ((double) cnt)/dt;
3006a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
3007a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3008a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatint skip_cr_when_scaling(char *mode) {
3009a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int got = 0;
3010a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3011a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!scaling) {
3012a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return 0;
3013a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3014a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3015a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (scaling_copyrect != scaling_copyrect0) {
3016a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* user override via -scale: */
3017a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! scaling_copyrect) {
3018a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return 1;
3019a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
3020a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return 0;
3021a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3022a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3023a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (*mode == 's') {
3024a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		got = got_scrollcopyrect;
3025a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else if (*mode == 'w') {
3026a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		got = got_wirecopyrect;
3027a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3028a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (scaling_copyrect || got) {
3029a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int lat, rate;
3030a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int link = link_rate(&lat, &rate);
3031a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (link == LR_DIALUP) {
3032a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return 1;
3033a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (rate < 25) {
3034a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* the fill-in of the repair may be too slow */
3035a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return 1;
3036a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
3037a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return 0;
3038a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3039a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	} else {
3040a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return 1;
3041a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3042a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
3043a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3044a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*
3045a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * key event handler.  See the above functions for contortions for
3046a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * running under -modtweak.
3047a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */
3048a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic rfbClientPtr last_keyboard_client = NULL;
3049a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3050a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatvoid keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
3051a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	KeyCode k;
3052a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	int idx, isbutton = 0;
3053a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	allowed_input_t input;
3054a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	time_t now = time(NULL);
3055a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	double tnow;
3056a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static int skipped_last_down;
3057a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static rfbBool last_down;
3058a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static rfbKeySym last_keysym = NoSymbol;
3059a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static rfbKeySym max_keyrepeat_last_keysym = NoSymbol;
3060a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static double max_keyrepeat_last_time = 0.0;
3061a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	static double max_keyrepeat_always = -1.0;
3062a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3063a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (threads_drop_input) {
3064a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
3065a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3066a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3067a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	dtime0(&tnow);
3068a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	got_keyboard_calls++;
3069a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3070a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
3071a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *str;
3072a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_LOCK;
3073a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		str = XKeysymToString((KeySym) keysym);
3074a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
3075a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("# keyboard(%s, 0x%x \"%s\") uip=%d  %.4f\n",
3076a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    down ? "down":"up", (int) keysym, str ? str : "null",
3077a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    unixpw_in_progress, tnow - x11vnc_start);
3078a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3079a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3080a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (keysym <= 0) {
3081a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("keyboard: skipping 0x0 keysym\n");
3082a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
3083a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3084a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3085a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (unixpw_in_progress) {
3086a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (unixpw_denied) {
3087a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("keyboard: ignoring keystroke 0x%x in "
3088a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    "unixpw_denied=1 state\n", (int) keysym);
3089a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
3090a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3091a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (client != unixpw_client) {
3092a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("keyboard: skipping other client in unixpw\n");
3093a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
3094a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3095a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3096a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		unixpw_keystroke(down, keysym, 0);
3097a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3098a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
3099a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3100a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3101a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (skip_duplicate_key_events) {
3102a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym == last_keysym && down == last_down) {
3103a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
3104a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("skipping dup key event: %d 0x%x\n",
3105a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    down, keysym);
3106a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3107a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
3108a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3109a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3110a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3111a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (skip_lockkeys) {
3112a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*  we don't handle XK_ISO*_Lock or XK_Kana_Lock ... */
3113a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym == XK_Scroll_Lock || keysym == XK_Num_Lock ||
3114a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    keysym == XK_Caps_Lock || keysym == XK_Shift_Lock) {
3115a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
3116a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("skipping lock key event: %d 0x%x\n",
3117a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    down, keysym);
3118a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3119a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
3120a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (keysym >= XK_KP_0 && keysym <= XK_KP_9) {
3121a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			/* ugh this is probably what they meant... assume NumLock. */
3122a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
3123a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("changed KP digit to regular digit: %d 0x%x\n",
3124a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    down, keysym);
3125a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3126a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keysym = (keysym - XK_KP_0) + XK_0;
3127a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (keysym == XK_KP_Decimal) {
3128a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_keyboard) {
3129a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("changed XK_KP_Decimal to XK_period: %d 0x%x\n",
3130a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    down, keysym);
3131a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3132a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			keysym = XK_period;
3133a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3134a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3135a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3136a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	INPUT_LOCK;
3137a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3138a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_down = down;
3139a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_keysym = keysym;
3140a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_keyboard_time = tnow;
3141a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3142a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_down = down;
3143a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_keysym = keysym;
3144a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_keytime = tnow;
3145a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_key_accepted = FALSE;
3146a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3147a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (key_history_idx == -1) {
3148a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (idx=0; idx<KEY_HIST; idx++) {
3149a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			key_history[idx].sym = NoSymbol;
3150a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			key_history[idx].down = FALSE;
3151a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			key_history[idx].time = 0.0;
3152a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3153a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3154a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	idx = ++key_history_idx;
3155a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (key_history_idx >= KEY_HIST) {
3156a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		key_history_idx = 0;
3157a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		idx = 0;
3158a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3159a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	key_history[idx].sym = keysym;
3160a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	key_history[idx].down = down;
3161a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	key_history[idx].time = tnow;
3162a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3163a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (down && (keysym == XK_Alt_L || keysym == XK_Super_L)) {
3164a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int i, k, run = 0, ups = 0;
3165a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		double delay = 1.0;
3166a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		KeySym ks;
3167a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		for (i=0; i<16; i++) {
3168a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k = idx - i;
3169a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (k < 0) k += KEY_HIST;
3170a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (!key_history[k].down) {
3171a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				ups++;
3172a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				continue;
3173a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3174a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			ks = key_history[k].sym;
3175a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (key_history[k].time < tnow - delay) {
3176a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				break;
3177a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else if (ks == keysym && ks == XK_Alt_L) {
3178a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				run++;
3179a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else if (ks == keysym && ks == XK_Super_L) {
3180a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				run++;
3181a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			} else {
3182a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				break;
3183a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3184a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3185a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (ups < 2) {
3186a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			;
3187a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (run == 3 && keysym == XK_Alt_L) {
3188a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("3*Alt_L, calling: refresh_screen(0)\n");
3189a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			refresh_screen(0);
3190a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (run == 4 && keysym == XK_Alt_L) {
3191a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("4*Alt_L, setting: do_copy_screen\n");
3192a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			do_copy_screen = 1;
3193a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (run == 5 && keysym == XK_Alt_L) {
3194a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			;
3195a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (run == 3 && keysym == XK_Super_L) {
3196a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("3*Super_L, calling: set_xdamage_mark()\n");
3197a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			set_xdamage_mark(0, 0, dpy_x, dpy_y);
3198a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (run == 4 && keysym == XK_Super_L) {
3199a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("4*Super_L, calling: check_xrecord_reset()\n");
3200a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			check_xrecord_reset(1);
3201a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (run == 5 && keysym == XK_Super_L) {
3202a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("5*Super_L, calling: push_black_screen(0)\n");
3203a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			push_black_screen(0);
3204a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3205a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3206a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3207a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#ifdef MAX_KEYREPEAT
3208a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (max_keyrepeat_always < 0.0) {
3209a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (getenv("MAX_KEYREPEAT")) {
3210a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			max_keyrepeat_always = atof(getenv("MAX_KEYREPEAT"));
3211a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
3212a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			max_keyrepeat_always = 0.0;
3213a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3214a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3215a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (max_keyrepeat_always > 0.0) {
3216a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		max_keyrepeat_time = max_keyrepeat_always;
3217a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3218a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#else
3219a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (0) {max_keyrepeat_always=0;}
3220a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#endif
3221a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (!down && skipped_last_down) {
3222a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int db = debug_scroll;
3223a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (keysym == max_keyrepeat_last_keysym) {
3224a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			skipped_last_down = 0;
3225a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s "
3226a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    "%.4f  %.4f\n", keysym, down ? "down":"up  ",
3227a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
3228a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			INPUT_UNLOCK;
3229a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
3230a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3231a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3232a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (down && max_keyrepeat_time > 0.0) {
3233a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int skip = 0;
3234a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int db = debug_scroll;
3235a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3236a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (max_keyrepeat_last_keysym != NoSymbol &&
3237a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    max_keyrepeat_last_keysym != keysym) {
3238a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			;
3239a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
3240a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (tnow < max_keyrepeat_last_time+max_keyrepeat_time) {
3241a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				skip = 1;
3242a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3243a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3244a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		max_keyrepeat_time = 0.0;
3245a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (skip) {
3246a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s "
3247a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    "%.4f  %.4f\n", keysym, down ? "down":"up  ",
3248a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
3249a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			max_keyrepeat_last_keysym = keysym;
3250a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			skipped_last_down = 1;
3251a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			INPUT_UNLOCK;
3252a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
3253a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
3254a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (db) rfbLog("--- scroll keyrate KEEPING  0x%lx %s "
3255a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    "%.4f  %.4f\n", keysym, down ? "down":"up  ",
3256a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
3257a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3258a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3259a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	max_keyrepeat_last_keysym = keysym;
3260a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	max_keyrepeat_last_time = tnow;
3261a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	skipped_last_down = 0;
3262a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_key_accepted = TRUE;
3263a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3264a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (pipeinput_fh != NULL || pipeinput_int) {
3265a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		pipe_keyboard(down, keysym, client);	/* MACOSX here. */
3266a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! pipeinput_tee) {
3267a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (! view_only || raw_fb) {	/* raw_fb hack */
3268a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_keyboard_client = client;
3269a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_event = last_input = now;
3270a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_keyboard_input = now;
3271a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3272a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_keysym = keysym;
3273a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3274a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_rfb_down = down;
3275a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_rfb_keysym = keysym;
3276a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_rfb_keytime = tnow;
3277a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				last_rfb_key_injected = dnow();
3278a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3279a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				got_user_input++;
3280a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				got_keyboard_input++;
3281a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3282a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			INPUT_UNLOCK;
3283a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;
3284a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3285a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3286a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3287a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (view_only) {
3288a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		INPUT_UNLOCK;
3289a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
3290a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3291a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	get_allowed_input(client, &input);
3292a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (! input.keystroke) {
3293a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		INPUT_UNLOCK;
3294a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
3295a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3296a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3297a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	track_mod_state(keysym, down, TRUE);	/* ignores remaps */
3298a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3299a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_keyboard_client = client;
3300a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_event = last_input = now;
3301a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_keyboard_input = now;
3302a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3303a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_keysym = keysym;
3304a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3305a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_down = down;
3306a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_keysym = keysym;
3307a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_keytime = tnow;
3308a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	last_rfb_key_injected = dnow();
3309a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3310a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	got_user_input++;
3311a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	got_keyboard_input++;
3312a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3313a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	RAWFB_RET_VOID
3314a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3315a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3316a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	apply_remap(&keysym, &isbutton);
3317a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3318a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (use_xrecord && ! xrecording && down) {
3319a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3320a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (!strcmp(scroll_copyrect, "never")) {
3321a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			;
3322a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (!strcmp(scroll_copyrect, "mouse")) {
3323a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			;
3324a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (skip_cr_when_scaling("scroll")) {
3325a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			;
3326a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else if (! xrecord_skip_keysym(keysym)) {
3327a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			snapshot_stack_list(0, 0.25);
3328a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xrecord_watch(1, SCR_KEY);
3329a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xrecord_set_by_keys = 1;
3330a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			xrecord_keysym = keysym;
3331a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		} else {
3332a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (debug_scroll) {
3333a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				char *str = XKeysymToString(keysym);
3334a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				rfbLog("xrecord_skip_keysym: %s\n",
3335a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				    str ? str : "NoSymbol");
3336a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3337a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3338a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3339a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3340a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (isbutton) {
3341a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int mask, button = (int) keysym;
3342a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *b, bstr[32];
3343a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3344a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (! down) {
3345a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			INPUT_UNLOCK;
3346a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			return;	/* nothing to send */
3347a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3348a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (debug_keyboard) {
3349a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			rfbLog("keyboard(): remapping keystroke to button %d"
3350a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			    " click\n", button);
3351a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3352a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		dtime0(&last_key_to_button_remap_time);
3353a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3354a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_LOCK;
3355a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/*
3356a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * This in principle can be a little dicey... i.e. even
3357a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * remap the button click to keystroke sequences!
3358a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 * Usually just will simulate the button click.
3359a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		 */
3360a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3361a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		/* loop over possible multiclicks: Button123 */
3362a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		sprintf(bstr, "%d", button);
3363a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		b = bstr;
3364a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		while (*b != '\0') {
3365a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			char t[2];
3366a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			int butt;
3367a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			t[0] = *b;
3368a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			t[1] = '\0';
3369a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			if (sscanf(t, "%d", &butt) == 1) {
3370a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				mask = 1<<(butt-1);
3371a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				do_button_mask_change(mask, butt);	/* down */
3372a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				mask = 0;
3373a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat				do_button_mask_change(mask, butt);	/* up */
3374a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			}
3375a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			b++;
3376a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3377a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XFlush_wr(dpy);
3378a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
3379a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		INPUT_UNLOCK;
3380a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
3381a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3382a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3383a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (use_modifier_tweak) {
3384a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		modifier_tweak_keyboard(down, keysym, client);
3385a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_LOCK;
3386a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XFlush_wr(dpy);
3387a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		X_UNLOCK;
3388a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		INPUT_UNLOCK;
3389a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		return;
3390a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3391a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3392a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_LOCK;
3393a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3394a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	k = XKeysymToKeycode(dpy, (KeySym) keysym);
3395a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3396a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) {
3397a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		int new_kc = add_keysym(keysym);
3398a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		if (new_kc) {
3399a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat			k = new_kc;
3400a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		}
3401a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3402a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if (debug_keyboard) {
3403a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		char *str = XKeysymToString(keysym);
3404a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x%s\n",
3405a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    (int) keysym, str ? str : "null", (int) k,
3406a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		    k ? "" : " *ignored*");
3407a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3408a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3409a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	if ( k != NoSymbol ) {
3410a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime);
3411a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat		XFlush_wr(dpy);
3412a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	}
3413a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3414a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	X_UNLOCK;
3415a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat	INPUT_UNLOCK;
3416a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat}
3417a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3418a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat
3419