key_history[idx].time = dnow;  if (0 && max_scroll_keyrate) {  static int hlen = 256, hidx = 0; static keyevent_t history[256]; static rfbKeySym last_down_skip_keysym = None; double key_dt, keytimes[256]; int idx, i, nrep = 0, skip = 0;  if (!down) { if (last_down_skip_keysym != None) { if (keysym == last_down_skip_keysym) { skip = 1; } }
key_history[idx].time = tnow;  if (use_xdamage && down && skip_duplicate_key_events && (keysym == XK_Alt_L || keysym == XK_Super_L)) { int i, k, run = 0; double delay = 1.0; for (i=0; i<16; i++) { k = idx - i; if (k < 0) k += KEY_HIST; if (!key_history[k].down) { continue; } if (key_history[k].time < tnow - delay) { break; } else if (key_history[k].sym == XK_Alt_L) { run++; } else if (key_history[k].sym == XK_Super_L) { run++; } else { break; } } if (run == 3) { rfbLog("3*Alt_L, calling: set_xdamage_mark()\n"); set_xdamage_mark(0, 0, dpy_x, dpy_y); } else if (run == 4) { rfbLog("4*Alt_L, calling: refresh_screen(0)\n"); refresh_screen(0); } else if (run == 5) { rfbLog("5*Alt_L, setting: do_copy_screen\n"); do_copy_screen = 1; } }  if (!down && skipped_last_down) { int db = debug_scroll; if (keysym == max_keyrepeat_last_keysym) { skipped_last_down = 0; if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s " "%.4f  %.4f\n", keysym, down ? "down":"up  ", tnow - x11vnc_start, tnow - max_keyrepeat_last_time); return; } } if (down && max_keyrepeat_time > 0.0) { int skip = 0; int db = debug_scroll;  if (max_keyrepeat_last_keysym != NoSymbol && max_keyrepeat_last_keysym != keysym) { ;
void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {	KeyCode k;	int idx, isbutton = 0;	allowed_input_t input;	time_t now = time(0);	double dnow;	static rfbBool last_down;	static rfbKeySym last_keysym;	dtime0(&dnow);	if (debug_keyboard) {		char *str;		X_LOCK;		str = XKeysymToString(keysym);		rfbLog("keyboard(%s, 0x%x \"%s\")  %.4f\n", down ? "down":"up",		    (int) keysym, str ? str : "null", dnow - x11vnc_start);		X_UNLOCK;	}	if (skip_duplicate_key_events) {		if (keysym == last_keysym && down == last_down) {			if (debug_keyboard) {				rfbLog("skipping dup key event: %d 0x%x\n",				    down, keysym);			}			return;		}	}	last_down = down;	last_keysym = keysym;	last_keyboard_time = dnow;	if (key_history_idx == -1) {		for (idx=0; idx<KEY_HIST; idx++) {			key_history[idx].sym = NoSymbol;			key_history[idx].down = FALSE;			key_history[idx].time = 0.0;		}	}	idx = ++key_history_idx;	if (key_history_idx >= KEY_HIST) {		key_history_idx = 0;		idx = 0;	}	key_history[idx].sym = keysym;	key_history[idx].down = down;	key_history[idx].time = dnow;	if (0 && max_scroll_keyrate) {		/* XXX not working... */		static int hlen = 256, hidx = 0;		static keyevent_t history[256];		static rfbKeySym last_down_skip_keysym = None;		double key_dt, keytimes[256];		int idx, i, nrep = 0, skip = 0;		if (!down) {			if (last_down_skip_keysym != None) {				if (keysym == last_down_skip_keysym) {					skip = 1;				}			}		} else {			if (last_scroll_type == SCR_KEY &&			    dnow < last_scroll_event + 1.0) {				key_dt = 1.0/max_scroll_keyrate;if (0) fprintf(stderr, "key_dt: %.4f\n", key_dt);				for (i=0; i<hlen; i++) {					idx = hidx - i - 1;					if (idx < 0) idx += hlen;					if (history[idx].sym != keysym) {						break;					}					if (dnow > history[idx].time + 1.5) {						break;					}					if (history[idx].down == down) {if (0) fprintf(stderr, "key_dt: %.4f  %d %d %.4f\n", key_dt, history[idx].sym,	history[idx].down, history[idx].time - x11vnc_start);						keytimes[nrep++] =						    history[idx].time;					}				}				if (nrep > 0) {					idx = hidx - 1;					if (idx < 0) idx += hlen;					if (dnow < keytimes[0] + key_dt) {						skip = 1;					}				}			}		}		if (skip) {			rfbLog("--- scroll keyrate skipping 0x%lx %s rep:%d  "			    "%.4f\n", keysym, down ? "down":"up", nrep,			    down ? dnow - keytimes[0] : dnow - x11vnc_start); 			if (down) {				last_down_skip_keysym = keysym;			}			return;		}		last_down_skip_keysym = None;		history[hidx].sym = keysym;		history[hidx].time = dnow;		history[hidx].down = down;		if (++hidx >= hlen) {			hidx = 0;		}	}	if (pipeinput_fh != NULL) {		pipe_keyboard(down, keysym, client);		if (! pipeinput_tee) {			if (! view_only || raw_fb) {	/* raw_fb hack */				last_keyboard_client = client;				last_event = last_input = now;				last_keyboard_input = now;						last_keysym = keysym;				got_user_input++;				got_keyboard_input++;			}			return;		}	}	if (view_only) {		return;	}	get_allowed_input(client, &input);	if (! input.keystroke) {		return;	}	last_keyboard_client = client;	last_event = last_input = now;	last_keyboard_input = now;	last_keysym = keysym;	got_user_input++;	got_keyboard_input++;		if (raw_fb && ! dpy) return;	/* raw_fb hack */	if (keyremaps) {		keyremap_t *remap = keyremaps;		while (remap != NULL) {			if (remap->before == keysym) {				keysym = remap->after;				isbutton = remap->isbutton;				if (debug_keyboard) {					X_LOCK;					rfbLog("keyboard(): remapping keysym: "					    "0x%x \"%s\" -> 0x%x \"%s\"\n",					    (int) remap->before,					    XKeysymToString(remap->before),					    (int) remap->after,					    remap->isbutton ? "button" :					    XKeysymToString(remap->after));					X_UNLOCK;				}				break;			}			remap = remap->next;		}	}	if (use_xrecord && ! xrecording && down) {		if (scaling && ! got_scrollcopyrect) {			;		} else if (!strcmp(scroll_copyrect, "never")) {			;		} else if (!strcmp(scroll_copyrect, "mouse")) {			;		} else if (! xrecord_skip_keysym(keysym)) {			snapshot_stack_list(0, 0.25);			xrecord_watch(1, SCR_KEY);			xrecord_set_by_keys = 1;			xrecord_keysym = keysym;		} else {			if (debug_scroll) {				char *str = XKeysymToString(keysym);				rfbLog("xrecord_skip_keysym: %s\n",				    str ? str : "NoSymbol");			}		}	}	if (isbutton) {		int mask, button = (int) keysym;		if (! down) {			return;	/* nothing to send */		}		if (debug_keyboard) {			rfbLog("keyboard(): remapping keystroke to button %d"			    " click\n", button);		}		X_LOCK;		/*		 * This in principle can be a little dicey... i.e. even		 * remap the button click to keystroke sequences!		 * Usually just will simulate the button click.		 */		mask = 1<<(button-1);		do_button_mask_change(mask, button);	/* down */		mask = 0;		do_button_mask_change(mask, button);	/* up */		XFlush(dpy);		X_UNLOCK;		return;	}	if (use_modifier_tweak) {		modifier_tweak_keyboard(down, keysym, client);		X_LOCK;		XFlush(dpy);		X_UNLOCK;		return;	}	X_LOCK;	k = XKeysymToKeycode(dpy, (KeySym) keysym);	if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) {		int new_kc = add_keysym(keysym);		if (new_kc) {			k = new_kc;		}	}	if (debug_keyboard) {		char *str = XKeysymToString(keysym);		rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x%s\n",		    (int) keysym, str ? str : "null", (int) k,		    k ? "" : " *ignored*");	}	if ( k != NoSymbol ) {		XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime);		XFlush(dpy);	}	X_UNLOCK;}