Unverified Commit a8c65ab6 authored by Mike Gabriel's avatar Mike Gabriel

Merge branch 'uli42-pr/improve_keyboard2' into 3.6.x

parents ab3e1485 a70ec920
...@@ -78,12 +78,11 @@ is" without express or implied warranty. ...@@ -78,12 +78,11 @@ is" without express or implied warranty.
#include <errno.h> #include <errno.h>
static int nxagentXkbGetNames(char **rules, char **model, char **layout, static void nxagentXkbGetNames(void);
char **variant, char **options);
static void nxagentKeycodeConversionSetup(char *rules, char *model); void nxagentKeycodeConversionSetup(void);
void nxagentWriteKeyboardFile(char *rules, char *model, char *layout, char *variant, char *options); static void nxagentWriteKeyboardFile(char *rules, char *model, char *layout, char *variant, char *options);
#endif /* XKB */ #endif /* XKB */
...@@ -140,6 +139,13 @@ extern Status XkbGetControls( ...@@ -140,6 +139,13 @@ extern Status XkbGetControls(
extern int XkbDfltRepeatDelay; extern int XkbDfltRepeatDelay;
extern int XkbDfltRepeatInterval; extern int XkbDfltRepeatInterval;
/* xkb configuration of the real X server */
static char *nxagentRemoteRules = NULL;
static char *nxagentRemoteModel = NULL;
static char *nxagentRemoteLayout = NULL;
static char *nxagentRemoteVariant = NULL;
static char *nxagentRemoteOptions = NULL;
#endif /* XKB */ #endif /* XKB */
/* /*
...@@ -571,8 +577,10 @@ int nxagentKeyboardProc(DeviceIntPtr pDev, int onoff) ...@@ -571,8 +577,10 @@ int nxagentKeyboardProc(DeviceIntPtr pDev, int onoff)
CARD8 modmap[MAP_LENGTH]; CARD8 modmap[MAP_LENGTH];
int i, j; int i, j;
XKeyboardState values; XKeyboardState values;
#ifdef XKB
char *model = NULL, *layout = NULL; char *model = NULL, *layout = NULL;
XkbDescPtr xkb = NULL; XkbDescPtr xkb = NULL;
#endif
switch (onoff) switch (onoff)
{ {
...@@ -694,20 +702,13 @@ N/A ...@@ -694,20 +702,13 @@ N/A
keySyms.mapWidth = mapWidth; keySyms.mapWidth = mapWidth;
keySyms.map = keymap; keySyms.map = keymap;
if (XkbQueryExtension(nxagentDisplay, #ifdef XKB
&nxagentXkbInfo.Opcode, if (!nxagentGetRemoteXkbExtension())
&nxagentXkbInfo.EventBase,
&nxagentXkbInfo.ErrorBase,
&nxagentXkbInfo.MajorVersion,
&nxagentXkbInfo.MinorVersion) == 0)
{ {
ErrorF("Unable to initialize XKEYBOARD extension.\n"); ErrorF("Unable to query XKEYBOARD extension.\n");
goto XkbError; goto XkbError;
} }
#ifdef XKB
if (noXkbExtension) { if (noXkbExtension) {
#ifdef TEST #ifdef TEST
fprintf(stderr, "nxagentKeyboardProc: No XKB extension.\n"); fprintf(stderr, "nxagentKeyboardProc: No XKB extension.\n");
...@@ -761,7 +762,9 @@ XkbError: ...@@ -761,7 +762,9 @@ XkbError:
layout. layout.
*/ */
if (nxagentKeyboard && (strcmp(nxagentKeyboard, "query") != 0)) if (nxagentKeyboard &&
(strcmp(nxagentKeyboard, "query") != 0) &&
(strcmp(nxagentKeyboard, "clone") != 0))
{ {
for (i = 0; nxagentKeyboard[i] != '/' && nxagentKeyboard[i] != 0; i++); for (i = 0; nxagentKeyboard[i] != '/' && nxagentKeyboard[i] != 0; i++);
...@@ -772,8 +775,33 @@ XkbError: ...@@ -772,8 +775,33 @@ XkbError:
goto XkbError; goto XkbError;
} }
/*
The original nxagent only supports model/layout values
here. It uses these values together with the default rules
and empty variant and options. We use a more or less
compatible hack here: The special keyword rlmvo for model
means that the layout part of the string will contain a
full RMLVO config, separated by #, e.g.
rlmvo/base#pc105#de,us#nodeadkeys#lv3:rwin_switch
*/
if (strncmp(nxagentKeyboard, "rlmvo/", 6) == 0)
{
const char * sep = "#";
char * rmlvo = strdup(&nxagentKeyboard[i+1]);
char * tmp = rmlvo;
/* strtok cannot handle empty fields, so use strsep */
rules = strdup(strsep(&tmp, sep));
model = strdup(strsep(&tmp, sep));
layout = strdup(strsep(&tmp, sep));
variant = strdup(strsep(&tmp, sep));
options = strdup(strsep(&tmp, sep));
free(rmlvo);
}
else
{
model = strndup(nxagentKeyboard, i); model = strndup(nxagentKeyboard, i);
layout = strdup(&nxagentKeyboard[i + 1]); layout = strdup(&nxagentKeyboard[i + 1]);
}
/* /*
* There is no description for pc105 on Solaris. * There is no description for pc105 on Solaris.
...@@ -781,8 +809,8 @@ XkbError: ...@@ -781,8 +809,8 @@ XkbError:
*/ */
#ifdef TEST #ifdef TEST
fprintf(stderr, "nxagentKeyboardProc: Using keyboard model [%s] with layout [%s].\n", fprintf(stderr, "%s: Using [rules='%s',model='%s',layout='%s',variant='%s',options='%s'].\n",
model, layout); __func__, rules, model, layout, variant, options);
#endif #endif
#ifdef __sun #ifdef __sun
...@@ -791,7 +819,6 @@ XkbError: ...@@ -791,7 +819,6 @@ XkbError:
{ {
#ifdef TEST #ifdef TEST
fprintf(stderr, "nxagentKeyboardProc: WARNING! Keyboard model 'pc105' unsupported on Solaris.\n"); fprintf(stderr, "nxagentKeyboardProc: WARNING! Keyboard model 'pc105' unsupported on Solaris.\n");
fprintf(stderr, "nxagentKeyboardProc: WARNING! Forcing keyboard model to 'pc104'.\n"); fprintf(stderr, "nxagentKeyboardProc: WARNING! Forcing keyboard model to 'pc104'.\n");
#endif #endif
...@@ -812,36 +839,47 @@ XkbError: ...@@ -812,36 +839,47 @@ XkbError:
fprintf(stderr, "nxagentKeyboardProc: Init XKB extension.\n"); fprintf(stderr, "nxagentKeyboardProc: Init XKB extension.\n");
#endif #endif
if (nxagentRemoteRules && nxagentRemoteModel)
{ {
char *remoterules = NULL; #ifdef DEBUG
char *remotemodel = NULL; fprintf(stderr, "%s: Remote: [rules='%s',model='%s',layout='%s',variant='%s',options='%s'].\n",
char *remotelayout = NULL; __func__, nxagentRemoteRules, nxagentRemoteModel, nxagentRemoteLayout, nxagentRemoteVariant, nxagentRemoteOptions);
char *remotevariant = NULL; #endif
char *remoteoptions = NULL;
unsigned int remoteruleslen = nxagentXkbGetNames(&remoterules, &remotemodel, &remotelayout, /*
&remotevariant, &remoteoptions); * Keyboard has always been tricky with nxagent. For that
* reason X2Go offers "auto" keyboard configuration. You can
* specify it in the client side session configuration. In
* "auto" mode x2goserver expects nxagent to write the
* remote keyboard config to a file on startup and
* x2goserver would then pick that file and pass it to
* setxkbmap. This functionality is obsoleted by the "clone"
* stuff but we still need it because x2goserver does not
* know about that yet. Once x2go starts using clone
* we can drop this here.
*/
nxagentWriteKeyboardFile(nxagentRemoteRules, nxagentRemoteModel, nxagentRemoteLayout, nxagentRemoteVariant, nxagentRemoteOptions);
#ifdef DEBUG /* Only setup keycode conversion if we are NOT in clone mode */
if (remoteruleslen && remoterules && remotemodel) if (nxagentKeyboard && (strcmp(nxagentKeyboard, "clone") == 0))
{ {
fprintf(stderr, "%s: Remote: [rules='%s',model='%s',layout='%s',variant='%s',options='%s'].\n", free(rules); rules = strdup(nxagentRemoteRules);
__func__, remoterules, remotemodel, remotelayout, remotevariant, remoteoptions); free(model); model = strdup(nxagentRemoteModel);
free(layout); layout = strdup(nxagentRemoteLayout);
free(variant); variant = strdup(nxagentRemoteVariant);
free(options); options = strdup(nxagentRemoteOptions);
} }
else else
{ {
fprintf(stderr, "%s: Failed to retrieve remote rules.\n", __func__); nxagentKeycodeConversionSetup();
} }
#endif
nxagentWriteKeyboardFile(remoterules, remotemodel, remotelayout, remotevariant, remoteoptions);
nxagentKeycodeConversionSetup(remoterules, remotemodel);
if (remoterules)
{
XFree(remoterules);
} }
#ifdef DEBUG
else
{
fprintf(stderr, "%s: Failed to retrieve remote rules.\n", __func__);
} }
#endif
xkb = XkbGetKeyboard(nxagentDisplay, XkbGBN_AllComponentsMask, XkbUseCoreKbd); xkb = XkbGetKeyboard(nxagentDisplay, XkbGBN_AllComponentsMask, XkbUseCoreKbd);
...@@ -1498,8 +1536,16 @@ void nxagentTuneXkbWrapper(void) ...@@ -1498,8 +1536,16 @@ void nxagentTuneXkbWrapper(void)
} }
} }
static int nxagentXkbGetNames(char **rules, char **model, char **layout, void nxagentXkbClearNames(void)
char **variant, char **options) {
free(nxagentRemoteRules); nxagentRemoteRules = NULL;
free(nxagentRemoteModel); nxagentRemoteModel = NULL;
free(nxagentRemoteLayout); nxagentRemoteLayout = NULL;
free(nxagentRemoteVariant); nxagentRemoteVariant = NULL;
free(nxagentRemoteOptions); nxagentRemoteOptions = NULL;
}
static void nxagentXkbGetNames(void)
{ {
Atom atom; Atom atom;
#ifdef _XSERVER64 #ifdef _XSERVER64
...@@ -1514,28 +1560,25 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout, ...@@ -1514,28 +1560,25 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout,
char *name; char *name;
Status result; Status result;
data = name = NULL; if (nxagentRemoteRules)
return;
*rules = NULL;
*model = NULL;
*layout = NULL;
*variant = NULL;
*options = NULL;
atom = XInternAtom(nxagentDisplay, "_XKB_RULES_NAMES", 1); atom = XInternAtom(nxagentDisplay, "_XKB_RULES_NAMES", 1);
if (atom == 0) if (atom == 0)
{ {
return 0; return;
} }
data = name = NULL;
result = XGetWindowProperty(nxagentDisplay, DefaultRootWindow(nxagentDisplay), result = XGetWindowProperty(nxagentDisplay, DefaultRootWindow(nxagentDisplay),
atom, 0, 256, 0, XA_STRING, &type, &format, atom, 0, 256, 0, XA_STRING, &type, &format,
&n, &after, (unsigned char **)&data); &n, &after, (unsigned char **)&data);
if (result != Success || !data) if (result != Success || !data)
{ {
return 0; return;
} }
if ((after > 0) || (type != XA_STRING) || (format != 8)) if ((after > 0) || (type != XA_STRING) || (format != 8))
...@@ -1543,7 +1586,7 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout, ...@@ -1543,7 +1586,7 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout,
if (data) if (data)
{ {
XFree(data); XFree(data);
return 0; return;
} }
} }
...@@ -1551,38 +1594,40 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout, ...@@ -1551,38 +1594,40 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout,
if (name < data + n) if (name < data + n)
{ {
*rules = name; nxagentRemoteRules = strdup(name);
name += strlen(name) + 1; name += strlen(name) + 1;
} }
if (name < data + n) if (name < data + n)
{ {
*model = name; nxagentRemoteModel = strdup(name);
name += strlen(name) + 1; name += strlen(name) + 1;
} }
if (name < data + n) if (name < data + n)
{ {
*layout = name; nxagentRemoteLayout = strdup(name);
name += strlen(name) + 1; name += strlen(name) + 1;
} }
if (name < data + n) if (name < data + n)
{ {
*variant = name; nxagentRemoteVariant = strdup(name);
name += strlen(name) + 1; name += strlen(name) + 1;
} }
if (name < data + n) if (name < data + n)
{ {
*options = name; nxagentRemoteOptions = strdup(name);
name += strlen(name) + 1; name += strlen(name) + 1;
} }
return n; XFree(data);
return;
} }
void writeKeyboardfileData(FILE *out, char *rules, char *model, char *layout, char *variant, char *options) static void writeKeyboardfileData(FILE *out, char *rules, char *model, char *layout, char *variant, char *options)
{ {
/* /*
How to set "empty" values with setxkbmap, result of trial and error: How to set "empty" values with setxkbmap, result of trial and error:
...@@ -1600,7 +1645,7 @@ void writeKeyboardfileData(FILE *out, char *rules, char *model, char *layout, ch ...@@ -1600,7 +1645,7 @@ void writeKeyboardfileData(FILE *out, char *rules, char *model, char *layout, ch
fprintf(out, "options=\",%s\"\n", options ? options : ""); fprintf(out, "options=\",%s\"\n", options ? options : "");
} }
void nxagentWriteKeyboardFile(char *rules, char *model, char *layout, char *variant, char *options) static void nxagentWriteKeyboardFile(char *rules, char *model, char *layout, char *variant, char *options)
{ {
if (rules && rules[0] != '\0') if (rules && rules[0] != '\0')
{ {
...@@ -1644,12 +1689,16 @@ void nxagentWriteKeyboardFile(char *rules, char *model, char *layout, char *vari ...@@ -1644,12 +1689,16 @@ void nxagentWriteKeyboardFile(char *rules, char *model, char *layout, char *vari
} }
} }
void nxagentKeycodeConversionSetup(char * rules, char * model) void nxagentKeycodeConversionSetup(void)
{ {
nxagentKeycodeConversion = False;
if (nxagentXkbInfo.Opcode == -1)
return;
if (nxagentOption(KeycodeConversion) == KeycodeConversionOff) if (nxagentOption(KeycodeConversion) == KeycodeConversionOff)
{ {
fprintf(stderr, "Info: Keycode conversion is off\n"); fprintf(stderr, "Info: Keycode conversion is off\n");
nxagentKeycodeConversion = False;
} }
else if (nxagentOption(KeycodeConversion) == KeycodeConversionOn) else if (nxagentOption(KeycodeConversion) == KeycodeConversionOn)
{ {
...@@ -1658,9 +1707,9 @@ void nxagentKeycodeConversionSetup(char * rules, char * model) ...@@ -1658,9 +1707,9 @@ void nxagentKeycodeConversionSetup(char * rules, char * model)
} }
else else
{ {
if (rules && model && if (nxagentRemoteRules && nxagentRemoteModel &&
(strcmp(rules, "evdev") == 0 || (strcmp(nxagentRemoteRules, "evdev") == 0 ||
strcmp(model, "evdev") == 0)) strcmp(nxagentRemoteModel, "evdev") == 0))
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Activating KeyCode conversion.\n", __func__); fprintf(stderr, "%s: Activating KeyCode conversion.\n", __func__);
...@@ -1676,47 +1725,33 @@ void nxagentKeycodeConversionSetup(char * rules, char * model) ...@@ -1676,47 +1725,33 @@ void nxagentKeycodeConversionSetup(char * rules, char * model)
#endif #endif
fprintf(stderr, "Info: Keycode conversion auto-determined as off\n"); fprintf(stderr, "Info: Keycode conversion auto-determined as off\n");
nxagentKeycodeConversion = False;
} }
} }
} }
void nxagentResetKeycodeConversion(void) Bool nxagentGetRemoteXkbExtension(void)
{ {
int result; Bool result;
XkbAgentInfoRec info;
result = XkbQueryExtension(nxagentDisplay, &info.Opcode, &info.EventBase, nxagentXkbInfo.Opcode = nxagentXkbInfo.EventBase = nxagentXkbInfo.ErrorBase = nxagentXkbInfo.MajorVersion = nxagentXkbInfo.MinorVersion = -1;
&info.ErrorBase, &info.MajorVersion, nxagentXkbClearNames();
&info.MinorVersion);
if (result != 0) if ((result = XkbQueryExtension(nxagentDisplay,
&nxagentXkbInfo.Opcode,
&nxagentXkbInfo.EventBase,
&nxagentXkbInfo.ErrorBase,
&nxagentXkbInfo.MajorVersion,
&nxagentXkbInfo.MinorVersion)))
{ {
char *remoterules = NULL; nxagentXkbGetNames();
char *remotemodel = NULL;
char *remotelayout = NULL;
char *remotevariant = NULL;
char *remoteoptions = NULL;
unsigned int remoteruleslen;
remoteruleslen = nxagentXkbGetNames(&remoterules, &remotemodel, &remotelayout,
&remotevariant, &remoteoptions);
if (remoteruleslen && remoterules && remotemodel)
nxagentKeycodeConversionSetup(remoterules, remotemodel);
if (remoterules)
XFree(remoterules);
} }
#ifdef WARNING
else else
{ {
#ifdef WARNING fprintf(stderr, "%s: WARNING! Failed to query XKB extension.\n", __func__);
fprintf(stderr, "nxagentResetKeycodeConversion: " }
"WARNING! Failed to query XKB extension.\n");
#endif #endif
nxagentKeycodeConversion = False; return result;
}
} }
#endif /* XKB */ #endif /* XKB */
...@@ -117,8 +117,9 @@ void nxagentEnableXkbExtension(void); ...@@ -117,8 +117,9 @@ void nxagentEnableXkbExtension(void);
void nxagentTuneXkbWrapper(void); void nxagentTuneXkbWrapper(void);
void nxagentResetKeycodeConversion(void); void nxagentKeycodeConversionSetup(void);
Bool nxagentGetRemoteXkbExtension(void);
#endif #endif
CARD8 nxagentConvertKeycode(CARD8 k); CARD8 nxagentConvertKeycode(CARD8 k);
......
...@@ -584,6 +584,9 @@ Bool nxagentReconnectSession(void) ...@@ -584,6 +584,9 @@ Bool nxagentReconnectSession(void)
goto nxagentReconnectError; goto nxagentReconnectError;
} }
/* Update remote XKB information */
nxagentGetRemoteXkbExtension();
/* if there's no keyboard definition in the options file /* if there's no keyboard definition in the options file
restore the previous value. */ restore the previous value. */
#ifdef DEBUG #ifdef DEBUG
...@@ -598,7 +601,8 @@ Bool nxagentReconnectSession(void) ...@@ -598,7 +601,8 @@ Bool nxagentReconnectSession(void)
if (nxagentOption(ResetKeyboardAtResume) == 1 && if (nxagentOption(ResetKeyboardAtResume) == 1 &&
(nxagentKeyboard == NULL || nxagentOldKeyboard == NULL || (nxagentKeyboard == NULL || nxagentOldKeyboard == NULL ||
strcmp(nxagentKeyboard, nxagentOldKeyboard) != 0 || strcmp(nxagentKeyboard, nxagentOldKeyboard) != 0 ||
strcmp(nxagentKeyboard, "query") == 0)) strcmp(nxagentKeyboard, "query") == 0 ||
strcmp(nxagentKeyboard, "clone") == 0))
{ {
if (nxagentResetKeyboard() == 0) if (nxagentResetKeyboard() == 0)
{ {
...@@ -616,7 +620,7 @@ Bool nxagentReconnectSession(void) ...@@ -616,7 +620,7 @@ Bool nxagentReconnectSession(void)
} }
else else
{ {
nxagentResetKeycodeConversion(); nxagentKeycodeConversionSetup();
} }
nxagentXkbState.Initialized = 0; nxagentXkbState.Initialized = 0;
......
...@@ -525,8 +525,8 @@ don't reset keyboard device if the session is resumed ...@@ -525,8 +525,8 @@ don't reset keyboard device if the session is resumed
this is only relevant if you also specify \-keyboard=query. In that this is only relevant if you also specify \-keyboard=query. In that
case \fBnxagent\fR will lock the keyboard settings and clients will case \fBnxagent\fR will lock the keyboard settings and clients will
get an error when trying to change keyboard settings via get an error when trying to change keyboard settings via
XKEYBOARD. With \-noxkblock the lock is not applied and clients can XKEYBOARD. With \-noxkblock the lock is not applied and clients are
change the keyboard settings through XKEYBOARD. allowed change the keyboard settings through XKEYBOARD.
.TP 8 .TP 8
.B \-tile WxH .B \-tile WxH
size of image tiles (minimum allowed: 32x32) size of image tiles (minimum allowed: 32x32)
...@@ -603,7 +603,7 @@ start or resume a session in fullscreen mode (default: off) ...@@ -603,7 +603,7 @@ start or resume a session in fullscreen mode (default: off)
.TP 8 .TP 8
.B keyboard=<string> or kbtype=<string> .B keyboard=<string> or kbtype=<string>
.BR query | <model>/<layout> .BR query | clone | <model>/<layout> | rmlvo/<rules>#<model>#<layout>#<variant>#<options>
.RS 8 .RS 8
.TP 8 .TP 8
...@@ -617,10 +617,22 @@ this platform. Note that in this case XKEYBOARD will always report ...@@ -617,10 +617,22 @@ this platform. Note that in this case XKEYBOARD will always report
the default layout which will most likely not match the experienced the default layout which will most likely not match the experienced
settings. settings.
.TP 8 .TP 8
.I clone
ask the real X server for the keyboard settings using XKEYBOARD
protocol functions and clone them. This is the recommended setting. For
compatibility reasons it is not the default.
.TP 8
.I <model>/<layout> .I <model>/<layout>
use the given model and layout. You can not modify keyboard rules, use the given model and layout. You can not modify keyboard rules,
variant or options. Instead preset values are used. These are variant or options this way. Instead preset values are used. These are
\fIbase\fR for rules and empty strings for variant and options. \fIbase\fR for rules and empty strings for variant and options.
.TP 8
.I rmlvo/<rules>#<model>#<layout>#<variant>#<options>
configure the keyboard according to the rmlvo
(Rules+Model+Layout+Variant+Options) description given after the / and
separated by #. This can be used to fully pass the keyboard
configuration of \fBnxagent\fR right after the start. Example:
rmlvo/base#pc105#de,us#nodeadkeys#lv3:rwin_switch
.RE .RE
.TP 8 .TP 8
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment