x11vnc: better -xkb tie-breaking for up keystrokes. Add Xsrv/FD_XSRV custom server to FINDCREATEDISPLAY list.

pull/1/head
runge 17 years ago
parent a69ed666eb
commit 222ecab5ca

@ -1,3 +1,7 @@
2007-08-19 Karl Runge <runge@karlrunge.com>
* x11vnc: better -xkb tie-breaking for up keystrokes. Add
Xsrv/FD_XSRV custom server to FINDCREATEDISPLAY list.
2007-08-18 Karl Runge <runge@karlrunge.com>
* x11vnc: improve FINDCREATEDISPLAY (-create) script. Document
FD_GEOM, FD_SESS, FD_OPTS, FD_PROG env vars, add Xvnc support.

@ -1,5 +1,5 @@
x11vnc README file Date: Fri Aug 17 23:09:12 EDT 2007
x11vnc README file Date: Sun Aug 19 14:30:12 EDT 2007
The following information is taken from these URLs:
@ -11075,7 +11075,7 @@ x11vnc: a VNC server for real X displays
Here are all of x11vnc command line options:
% x11vnc -opts (see below for -help long descriptions)
x11vnc: allow VNC connections to real X11 displays. 0.9.3 lastmod: 2007-08-17
x11vnc: allow VNC connections to real X11 displays. 0.9.3 lastmod: 2007-08-19
x11vnc options:
-display disp -auth file -N
@ -11189,7 +11189,7 @@ libvncserver-tight-extension options:
% x11vnc -help
x11vnc: allow VNC connections to real X11 displays. 0.9.3 lastmod: 2007-08-17
x11vnc: allow VNC connections to real X11 displays. 0.9.3 lastmod: 2007-08-19
(type "x11vnc -opts" to just list the options.)
@ -12065,7 +12065,7 @@ Options:
to find an existing display. However, if it does not
find one it will try to *start* up an X server session
for the user. This is the only time x11vnc tries to
start up an X server.
actually start up an X server.
By default FINDCREATEDISPLAY will try Xdummy and
then Xvfb. The Xdummy wrapper is part of the x11vnc
@ -12100,22 +12100,30 @@ Options:
X11VNC_FINDDISPLAY_ALWAYS_FAILS=1 (also -env ...)
Use WAIT:cmd=FINDCREATEDISPLAY-print to print out the
script used. You can specify the preferred order via
e.g., WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb,X and/or
leave out ones you do not want. The the extra case
"X" means try to start up a real, hardware X server
using xinit(1) or startx(1). "Xvnc" also works. If
there is already an X server running the X case may
only work on Linux (see startx(1)).
script used.
You can specify the preferred X server order via e.g.,
WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb,X and/or leave
out ones you do not want. The the case "X" means try
to start up a real, hardware X server using xinit(1)
or startx(1). If there is already an X server running
the X case may only work on Linux (see startx(1)).
"Xvnc" will start up a VNC X server (real-
or tight-vnc, e.g. use if Xvfb is not available).
"Xsrv" will start up the server program in the
variable "FD_XSRV" if it is non-empty. You can make
this be a wrapper script if you like (it must handle :N,
-geometry, and -depth and other X server options).
You can set the environment variable FD_GEOM (or
X11VNC_CREATE_GEOM) to WxH or WxHxD to set the width
and height and optionally the color depth of the
created display. You can also set FD_SESS to be the
session (short name of the windowmanager: kde, gnome,
twm, failsafe), and FD_OPTS as extra options to pass
to the created X server. You can also set FD_PROG to
be the full path to the session/windowmanager program.
X11VNC_CREATE_GEOM) to WxH or WxHxD to set the width and
height and optionally the color depth of the created
display. You can also set FD_SESS to be the session
(short name of the windowmanager: kde, gnome, twm,
failsafe, etc.). FD_OPTS as extra options to pass to
the X server. You can also set FD_PROG to be the full
path to the session/windowmanager program.
If you want the FINDCREATEDISPLAY session to contact an
XDMCP login manager (xdm/gdm/kdm) on the same machine,
@ -13089,6 +13097,16 @@ t
so then automatically enable the mode. To disable this
automatic detection use -noxkb.
When -xkb mode is active you can set these env. vars.
They apply only when there is ambiguity as to which
key to choose (i.e the mapping is not one-to-one).
NOKEYHINTS=1: for up ascii keystrokes do not use score
hints saved when the keep was press down. NOANYDOWN=1:
for up keystrokes do not resort to searching through
keys that are currently pressed down. KEYSDOWN=N:
remember the last N keys press down for tie-breaking
when an up keystroke comes in.
-capslock When in -modtweak (the default) or -xkb mode,
if a keysym in the range A-Z comes in check the X
server to see if the Caps_Lock is set. If it is do

@ -899,7 +899,7 @@ void print_help(int mode) {
" to find an existing display. However, if it does not\n"
" find one it will try to *start* up an X server session\n"
" for the user. This is the only time x11vnc tries to\n"
" start up an X server.\n"
" actually start up an X server.\n"
"\n"
" By default FINDCREATEDISPLAY will try Xdummy and\n"
" then Xvfb. The Xdummy wrapper is part of the x11vnc\n"
@ -934,22 +934,30 @@ void print_help(int mode) {
" X11VNC_FINDDISPLAY_ALWAYS_FAILS=1 (also -env ...)\n"
"\n"
" Use WAIT:cmd=FINDCREATEDISPLAY-print to print out the\n"
" script used. You can specify the preferred order via\n"
" e.g., WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb,X and/or\n"
" leave out ones you do not want. The the extra case\n"
" \"X\" means try to start up a real, hardware X server\n"
" using xinit(1) or startx(1). \"Xvnc\" also works. If\n"
" there is already an X server running the X case may\n"
" only work on Linux (see startx(1)).\n"
" script used.\n"
"\n"
" You can specify the preferred X server order via e.g.,\n"
" WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb,X and/or leave\n"
" out ones you do not want. The the case \"X\" means try\n"
" to start up a real, hardware X server using xinit(1)\n"
" or startx(1). If there is already an X server running\n"
" the X case may only work on Linux (see startx(1)).\n"
"\n"
" \"Xvnc\" will start up a VNC X server (real-\n"
" or tight-vnc, e.g. use if Xvfb is not available).\n"
" \"Xsrv\" will start up the server program in the\n"
" variable \"FD_XSRV\" if it is non-empty. You can make\n"
" this be a wrapper script if you like (it must handle :N,\n"
" -geometry, and -depth and other X server options).\n"
"\n"
" You can set the environment variable FD_GEOM (or\n"
" X11VNC_CREATE_GEOM) to WxH or WxHxD to set the width\n"
" and height and optionally the color depth of the\n"
" created display. You can also set FD_SESS to be the\n"
" session (short name of the windowmanager: kde, gnome,\n"
" twm, failsafe), and FD_OPTS as extra options to pass\n"
" to the created X server. You can also set FD_PROG to\n"
" be the full path to the session/windowmanager program.\n"
" X11VNC_CREATE_GEOM) to WxH or WxHxD to set the width and\n"
" height and optionally the color depth of the created\n"
" display. You can also set FD_SESS to be the session\n"
" (short name of the windowmanager: kde, gnome, twm,\n"
" failsafe, etc.). FD_OPTS as extra options to pass to\n"
" the X server. You can also set FD_PROG to be the full\n"
" path to the session/windowmanager program.\n"
"\n"
" If you want the FINDCREATEDISPLAY session to contact an\n"
" XDMCP login manager (xdm/gdm/kdm) on the same machine,\n"
@ -1931,6 +1939,16 @@ void print_help(int mode) {
" so then automatically enable the mode. To disable this\n"
" automatic detection use -noxkb.\n"
"\n"
" When -xkb mode is active you can set these env. vars.\n"
" They apply only when there is ambiguity as to which\n"
" key to choose (i.e the mapping is not one-to-one).\n"
" NOKEYHINTS=1: for up ascii keystrokes do not use score\n"
" hints saved when the keep was press down. NOANYDOWN=1:\n"
" for up keystrokes do not resort to searching through\n"
" keys that are currently pressed down. KEYSDOWN=N:\n"
" remember the last N keys press down for tie-breaking\n"
" when an up keystroke comes in.\n"
"\n"
"-capslock When in -modtweak (the default) or -xkb mode,\n"
" if a keysym in the range A-Z comes in check the X\n"
" server to see if the Caps_Lock is set. If it is do\n"

@ -1466,6 +1466,7 @@ xkbmodifiers[] For the KeySym bound to this (keycode,group,level) store
}
}
static int score_hint[0x100][0x100];
/*
* Called on user keyboard input. Try to solve the reverse mapping
* problem: KeySym (from VNC client) => KeyCode(s) to press to generate
@ -1485,8 +1486,10 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
XkbStateRec kbstate;
int got_kbstate = 0;
int Kc_f, Grp_f = 0, Lvl_f = 0;
static int Kc_last_down = -1;
static KeySym Ks_last_down = NoSymbol;
# define KLAST 10
static int Kc_last_down[KLAST];
static KeySym Ks_last_down[KLAST];
static int klast = 0, khints = 1, anydown = 1;
if (!client || !down || !keysym) {} /* unused vars warning: */
@ -1494,6 +1497,32 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
X_LOCK;
if (klast == 0) {
int i, j;
for (i=0; i<KLAST; i++) {
Kc_last_down[i] = -1;
Ks_last_down[i] = NoSymbol;
}
if (getenv("NOKEYHINTS")) {
khints = 0;
}
if (getenv("NOANYDOWN")) {
anydown = 0;
}
if (getenv("KEYSDOWN")) {
klast = atoi(getenv("KEYSDOWN"));
if (klast < 1) klast = 1;
if (klast > KLAST) klast = KLAST;
} else {
klast = 3;
}
for (i=0; i<0x100; i++) {
for (j=0; j<0x100; j++) {
score_hint[i][j] = -1;
}
}
}
if (debug_keyboard) {
char *str = XKeysymToString(keysym);
@ -1636,6 +1665,12 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
got_kbstate = 1;
}
if (khints && keysym < 0x100) {
int ks = (int) keysym, j;
for (j=0; j< 0x100; j++) {
score_hint[ks][j] = -1;
}
}
for (l=0; l < found; l++) {
int myscore = 0, b = 0x1, i;
int curr, curr_state = kbstate.mods;
@ -1678,6 +1713,9 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
"keycode %03d: %4d\n",
kc_f[l], myscore);
}
if (khints && keysym < 0x100 && kc_f[l] < 0x100) {
score_hint[(int) keysym][kc_f[l]] = score[l];
}
}
for (l=0; l < found; l++) {
int myscore = score[l];
@ -1693,39 +1731,125 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
} else {
/* up */
int i, Kc_loc = -1;
Kc_f = -1;
if (keysym == Ks_last_down) {
int l;
/* first try the scores we remembered when the key went down: */
if (khints && keysym < 0x100) {
/* low keysyms, ascii, only */
int ks = (int) keysym;
int ok = 1, sbest = -1, lbest, l;
for (l=0; l < found; l++) {
if (Kc_last_down == kc_f[l]) {
Kc_f = Kc_last_down;
if (kc_f[l] < 0x100) {
int key = (int) kc_f[l];
if (! keycode_state[key]) {
continue;
}
if (score_hint[ks][key] < 0) {
ok = 0;
break;
}
if (sbest < 0 || score_hint[ks][key] < sbest) {
sbest = score_hint[ks][key];
lbest = l;
}
} else {
ok = 0;
break;
}
}
if (ok && sbest != -1) {
Kc_f = kc_f[lbest];
}
if (debug_keyboard && Kc_f != -1) {
fprintf(stderr, " UP: found via score_hint, s/l=%d/%d\n",
sbest, lbest);
}
}
/* next look at our list of recently pressed down keys */
if (Kc_f == -1) {
for (i=klast-1; i>=0; i--) {
/*
* some people type really fast and leave
* lots of keys down before releasing
* them. this gives problem on weird
* qwerty+dvorak keymappings where each
* alpha character is on TWO keys.
*/
if (keysym == Ks_last_down[i]) {
int l;
for (l=0; l < found; l++) {
if (Kc_last_down[i] == kc_f[l]) {
int key = (int) kc_f[l];
if (keycode_state[key]) {
Kc_f = Kc_last_down[i];
Kc_loc = i;
break;
}
}
}
}
if (Kc_f != -1) {
break;
}
}
if (debug_keyboard && Kc_f != -1) {
fprintf(stderr, " UP: found via klast, i=%d\n", Kc_loc);
}
}
/* next just check for any one that is down */
if (Kc_f == -1 && anydown) {
int l;
int best = -1, lbest;
/*
* If it is already down, that is
* a great hint. Use it.
*
* note: keycode_state in internal and
* note: keycode_state is internal and
* ignores someone pressing keys on the
* physical display (but is updated
* periodically to clean out stale info).
*/
/* we could probably break ties based on lowest XKeycodeToKeysym index */
for (l=0; l < found; l++) {
int key = (int) kc_f[l];
int j, jmatch = -1;
if (keycode_state[key]) {
Kc_f = kc_f[l];
break;
continue;
}
for (j=0; j<8; j++) {
KeySym ks = XKeycodeToKeysym(dpy, kc_f[l], j);
if (ks != NoSymbol && ks == keysym) {
jmatch = j;
break;
}
}
if (jmatch == -1) {
continue;
}
if (best == -1 || jmatch < best) {
best = jmatch;
lbest = l;
}
}
if (best != -1) {
Kc_f = kc_f[lbest];
}
if (debug_keyboard && Kc_f != -1) {
fprintf(stderr, " UP: found via downlist, l=%d\n", lbest);
}
}
/* last, use the first one found */
if (Kc_f == -1) {
/* hope for the best... XXX check mods */
Kc_f = kc_f[0];
if (debug_keyboard && Kc_f != -1) {
fprintf(stderr, " UP: set to first one, kc_f[0]!!\n");
}
}
}
} else {
@ -1747,7 +1871,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
fprintf(stderr, " \"%s\"", str ? str : "null");
}
fprintf(stderr, ", picked this one: %03d (last down: %03d)\n",
Kc_f, Kc_last_down);
Kc_f, Kc_last_down[0]);
}
if (sloppy_keys) {
@ -1769,8 +1893,12 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
Bool dn;
/* remember these to aid the subsequent up case: */
Ks_last_down = keysym;
Kc_last_down = Kc_f;
for (i=KLAST-1; i >= 1; i--) {
Ks_last_down[i] = Ks_last_down[i-1];
Kc_last_down[i] = Kc_last_down[i-1];
}
Ks_last_down[0] = keysym;
Kc_last_down[0] = Kc_f;
if (! got_kbstate) {
/* get the current modifier state if we haven't yet */

@ -1208,6 +1208,15 @@ char create_display[] =
" server $have_Xvnc :$N -geometry $geom -depth $depth\n"
"}\n"
"\n"
"try_Xsrv() {\n"
" if [ \"X$FD_XSRV\" = \"X\" ]; then\n"
" return\n"
" fi\n"
"\n"
" server $FD_XSRV :$N -geometry $geom -depth $depth\n"
"}\n"
"\n"
"\n"
"try_Xvfb() {\n"
" if [ \"X$have_Xvfb\" = \"X\" ]; then\n"
" return\n"
@ -1427,13 +1436,15 @@ char create_display[] =
" fi\n"
" curr_try=`echo \"$curr_try\" | sed -e 's/[+.-]xdmcp//'`\n"
" \n"
" if echo \"$curr_try\" | grep -iw \"Xdummy\" > /dev/null; then\n"
" if echo \"$curr_try\" | grep -iw \"^Xdummy\" > /dev/null; then\n"
" try_Xdummy\n"
" elif echo \"$curr_try\" | grep -iw \"Xvfb\" > /dev/null; then\n"
" elif echo \"$curr_try\" | grep -iw \"^Xvfb\" > /dev/null; then\n"
" try_Xvfb\n"
" elif echo \"$curr_try\" | grep -iw \"Xvnc\" > /dev/null; then\n"
" elif echo \"$curr_try\" | grep -iw \"^Xvnc\" > /dev/null; then\n"
" try_Xvnc\n"
" elif echo \"$curr_try\" | grep -iw \"X\" > /dev/null; then\n"
" elif echo \"$curr_try\" | grep -iw \"^Xsrv\" > /dev/null; then\n"
" try_Xsrv\n"
" elif echo \"$curr_try\" | grep -iw \"^X\" > /dev/null; then\n"
" try_X\n"
" fi\n"
" if [ \"X$result\" = \"X1\" ]; then\n"

@ -1789,7 +1789,7 @@ if (0) db = 1;
if (strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
char *opts = strchr(cmd, '-');
char st[] = "";
char geom[128], xsess[128], fdopts[128], fdprog[128];
char geom[128], xsess[128], fdopts[128], fdprog[128], fdxsrv[128];
if (opts) {
opts++;
if (strstr(opts, "xdmcp")) {
@ -1803,6 +1803,7 @@ if (0) db = 1;
geom[0] = '\0';
fdopts[0] = '\0';
fdprog[0] = '\0';
fdxsrv[0] = '\0';
#if 0
if (!keep_unixpw_opts) {
fprintf(stderr, "no keep_unixpw_opts\n");
@ -1878,11 +1879,15 @@ if (!keep_unixpw_opts) {
if (fdprog[0] == '\0' && getenv("FD_PROG")) {
snprintf(fdprog, 120, "%s", getenv("FD_PROG"));
}
if (fdxsrv[0] == '\0' && getenv("FD_XSRV")) {
snprintf(fdxsrv, 120, "%s", getenv("FD_XSRV"));
}
set_env("FD_GEOM", geom);
set_env("FD_SESS", xsess);
set_env("FD_OPTS", fdopts);
set_env("FD_PROG", fdprog);
set_env("FD_XSRV", fdxsrv);
if (usslpeer || (unixpw && keep_unixpw_user)) {
char *uu = usslpeer;
@ -1894,15 +1899,17 @@ if (!keep_unixpw_opts) {
+ strlen("FD_GEOM='' ")
+ strlen("FD_OPTS='' ")
+ strlen("FD_PROG='' ")
+ strlen("FD_XSRV='' ")
+ strlen("FD_SESS='' /bin/sh ")
+ strlen(uu) + 1
+ strlen(geom) + 1
+ strlen(xsess) + 1
+ strlen(fdopts) + 1
+ strlen(fdprog) + 1
+ strlen(fdxsrv) + 1
+ strlen(opts) + 1);
sprintf(create_cmd, "env USER='%s' FD_GEOM='%s' FD_SESS='%s' FD_OPTS='%s' FD_PROG='%s' /bin/sh %s %s",
uu, geom, xsess, fdopts, fdprog, tmp, opts);
sprintf(create_cmd, "env USER='%s' FD_GEOM='%s' FD_SESS='%s' FD_OPTS='%s' FD_PROG='%s' FD_XSRV='%s' /bin/sh %s %s",
uu, geom, xsess, fdopts, fdprog, fdxsrv, tmp, opts);
} else {
create_cmd = (char *) malloc(strlen(tmp)
+ strlen("/bin/sh ") + 1 + strlen(opts) + 1);

@ -2,7 +2,7 @@
.TH X11VNC "1" "August 2007" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.9.3, lastmod: 2007-08-17
version: 0.9.3, lastmod: 2007-08-19
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@ -1050,7 +1050,7 @@ that is like FINDDISPLAY in that is uses the same method
to find an existing display. However, if it does not
find one it will try to *start* up an X server session
for the user. This is the only time x11vnc tries to
start up an X server.
actually start up an X server.
.IP
By default FINDCREATEDISPLAY will try Xdummy and
then Xvfb. The Xdummy wrapper is part of the x11vnc
@ -1087,28 +1087,35 @@ try to find an existing display set the env. var
X11VNC_FINDDISPLAY_ALWAYS_FAILS=1 (also \fB-env\fR ...)
.IP
Use WAIT:cmd=FINDCREATEDISPLAY-print to print out the
script used. You can specify the preferred order via
e.g., WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb,X and/or
leave out ones you do not want. The the extra case
"X" means try to start up a real, hardware X server
using
script used.
.IP
You can specify the preferred X server order via e.g.,
WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb,X and/or leave
out ones you do not want. The the case "X" means try
to start up a real, hardware X server using
.IR xinit (1)
or
.IR startx (1).
"Xvnc" also works. If
there is already an X server running the X case may
only work on Linux (see
If there is already an X server running
the X case may only work on Linux (see
.IR startx (1)
).
.IP
"Xvnc" will start up a VNC X server (real-
or tight-vnc, e.g. use if Xvfb is not available).
"Xsrv" will start up the server program in the
variable "FD_XSRV" if it is non-empty. You can make
this be a wrapper script if you like (it must handle :N,
\fB-geometry,\fR and \fB-depth\fR and other X server options).
.IP
You can set the environment variable FD_GEOM (or
X11VNC_CREATE_GEOM) to WxH or WxHxD to set the width
and height and optionally the color depth of the
created display. You can also set FD_SESS to be the
session (short name of the windowmanager: kde, gnome,
twm, failsafe), and FD_OPTS as extra options to pass
to the created X server. You can also set FD_PROG to
be the full path to the session/windowmanager program.
X11VNC_CREATE_GEOM) to WxH or WxHxD to set the width and
height and optionally the color depth of the created
display. You can also set FD_SESS to be the session
(short name of the windowmanager: kde, gnome, twm,
failsafe, etc.). FD_OPTS as extra options to pass to
the X server. You can also set FD_PROG to be the full
path to the session/windowmanager program.
.IP
If you want the FINDCREATEDISPLAY session to contact an
XDMCP login manager (xdm/gdm/kdm) on the same machine,
@ -2233,6 +2240,16 @@ The default is to check whether some common keysyms,
e.g. !, @, [, are only accessible via \fB-xkb\fR mode and if
so then automatically enable the mode. To disable this
automatic detection use \fB-noxkb.\fR
.IP
When \fB-xkb\fR mode is active you can set these env. vars.
They apply only when there is ambiguity as to which
key to choose (i.e the mapping is not one-to-one).
NOKEYHINTS=1: for up ascii keystrokes do not use score
hints saved when the keep was press down. NOANYDOWN=1:
for up keystrokes do not resort to searching through
keys that are currently pressed down. KEYSDOWN=N:
remember the last N keys press down for tie-breaking
when an up keystroke comes in.
.PP
\fB-capslock\fR
.IP

@ -15,7 +15,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.9.3 lastmod: 2007-08-17";
char lastmod[] = "0.9.3 lastmod: 2007-08-19";
/* X display info */

Loading…
Cancel
Save