diff options
author | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2018-12-19 12:36:28 +0100 |
---|---|---|
committer | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2018-12-19 12:36:28 +0100 |
commit | a8c65ab6290d9516b733273098db50721e84bcec (patch) | |
tree | b52b16887a35591263b19d8d0f0dc4d11b11ec03 | |
parent | ab3e1485010ecb549bb09c4321d24b391eac82a1 (diff) | |
parent | a70ec920dd33a04b74af876444602c587fe9ec80 (diff) | |
download | nx-libs-a8c65ab6290d9516b733273098db50721e84bcec.tar.gz nx-libs-a8c65ab6290d9516b733273098db50721e84bcec.tar.bz2 nx-libs-a8c65ab6290d9516b733273098db50721e84bcec.zip |
Merge branch 'uli42-pr/improve_keyboard2' into 3.6.x
Attributes GH PR #743: https://github.com/ArcticaProject/nx-libs/pull/743
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Keyboard.c | 229 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Keyboard.h | 3 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Reconnect.c | 8 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 | 20 |
4 files changed, 156 insertions, 104 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c index 1da6a0149..cfe73ac5b 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c @@ -78,12 +78,11 @@ is" without express or implied warranty. #include <errno.h> -static int nxagentXkbGetNames(char **rules, char **model, char **layout, - char **variant, char **options); +static void nxagentXkbGetNames(void); -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 */ @@ -140,6 +139,13 @@ extern Status XkbGetControls( extern int XkbDfltRepeatDelay; 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 */ /* @@ -571,8 +577,10 @@ int nxagentKeyboardProc(DeviceIntPtr pDev, int onoff) CARD8 modmap[MAP_LENGTH]; int i, j; XKeyboardState values; +#ifdef XKB char *model = NULL, *layout = NULL; XkbDescPtr xkb = NULL; +#endif switch (onoff) { @@ -694,20 +702,13 @@ N/A keySyms.mapWidth = mapWidth; keySyms.map = keymap; - if (XkbQueryExtension(nxagentDisplay, - &nxagentXkbInfo.Opcode, - &nxagentXkbInfo.EventBase, - &nxagentXkbInfo.ErrorBase, - &nxagentXkbInfo.MajorVersion, - &nxagentXkbInfo.MinorVersion) == 0) +#ifdef XKB + if (!nxagentGetRemoteXkbExtension()) { - ErrorF("Unable to initialize XKEYBOARD extension.\n"); - goto XkbError; + ErrorF("Unable to query XKEYBOARD extension.\n"); + goto XkbError; } - -#ifdef XKB - if (noXkbExtension) { #ifdef TEST fprintf(stderr, "nxagentKeyboardProc: No XKB extension.\n"); @@ -761,7 +762,9 @@ XkbError: 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++); @@ -772,8 +775,33 @@ XkbError: goto XkbError; } - model = strndup(nxagentKeyboard, i); - layout = strdup(&nxagentKeyboard[i + 1]); + /* + 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); + layout = strdup(&nxagentKeyboard[i + 1]); + } /* * There is no description for pc105 on Solaris. @@ -781,8 +809,8 @@ XkbError: */ #ifdef TEST - fprintf(stderr, "nxagentKeyboardProc: Using keyboard model [%s] with layout [%s].\n", - model, layout); + fprintf(stderr, "%s: Using [rules='%s',model='%s',layout='%s',variant='%s',options='%s'].\n", + __func__, rules, model, layout, variant, options); #endif #ifdef __sun @@ -791,7 +819,6 @@ XkbError: { #ifdef TEST fprintf(stderr, "nxagentKeyboardProc: WARNING! Keyboard model 'pc105' unsupported on Solaris.\n"); - fprintf(stderr, "nxagentKeyboardProc: WARNING! Forcing keyboard model to 'pc104'.\n"); #endif @@ -812,36 +839,47 @@ XkbError: fprintf(stderr, "nxagentKeyboardProc: Init XKB extension.\n"); #endif + if (nxagentRemoteRules && nxagentRemoteModel) { - char *remoterules = NULL; - char *remotemodel = NULL; - char *remotelayout = NULL; - char *remotevariant = NULL; - char *remoteoptions = NULL; + #ifdef DEBUG + fprintf(stderr, "%s: Remote: [rules='%s',model='%s',layout='%s',variant='%s',options='%s'].\n", + __func__, nxagentRemoteRules, nxagentRemoteModel, nxagentRemoteLayout, nxagentRemoteVariant, nxagentRemoteOptions); + #endif - 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 - if (remoteruleslen && remoterules && remotemodel) + /* Only setup keycode conversion if we are NOT in clone mode */ + if (nxagentKeyboard && (strcmp(nxagentKeyboard, "clone") == 0)) { - fprintf(stderr, "%s: Remote: [rules='%s',model='%s',layout='%s',variant='%s',options='%s'].\n", - __func__, remoterules, remotemodel, remotelayout, remotevariant, remoteoptions); + free(rules); rules = strdup(nxagentRemoteRules); + free(model); model = strdup(nxagentRemoteModel); + free(layout); layout = strdup(nxagentRemoteLayout); + free(variant); variant = strdup(nxagentRemoteVariant); + free(options); options = strdup(nxagentRemoteOptions); } else { - fprintf(stderr, "%s: Failed to retrieve remote rules.\n", __func__); - } - #endif - - nxagentWriteKeyboardFile(remoterules, remotemodel, remotelayout, remotevariant, remoteoptions); - nxagentKeycodeConversionSetup(remoterules, remotemodel); - - if (remoterules) - { - XFree(remoterules); + nxagentKeycodeConversionSetup(); } } + #ifdef DEBUG + else + { + fprintf(stderr, "%s: Failed to retrieve remote rules.\n", __func__); + } + #endif xkb = XkbGetKeyboard(nxagentDisplay, XkbGBN_AllComponentsMask, XkbUseCoreKbd); @@ -1498,8 +1536,16 @@ void nxagentTuneXkbWrapper(void) } } -static int nxagentXkbGetNames(char **rules, char **model, char **layout, - char **variant, char **options) +void nxagentXkbClearNames(void) +{ + 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; #ifdef _XSERVER64 @@ -1514,28 +1560,25 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout, char *name; Status result; - data = name = NULL; - - *rules = NULL; - *model = NULL; - *layout = NULL; - *variant = NULL; - *options = NULL; + if (nxagentRemoteRules) + return; atom = XInternAtom(nxagentDisplay, "_XKB_RULES_NAMES", 1); if (atom == 0) { - return 0; + return; } + data = name = NULL; + result = XGetWindowProperty(nxagentDisplay, DefaultRootWindow(nxagentDisplay), atom, 0, 256, 0, XA_STRING, &type, &format, &n, &after, (unsigned char **)&data); if (result != Success || !data) { - return 0; + return; } if ((after > 0) || (type != XA_STRING) || (format != 8)) @@ -1543,7 +1586,7 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout, if (data) { XFree(data); - return 0; + return; } } @@ -1551,38 +1594,40 @@ static int nxagentXkbGetNames(char **rules, char **model, char **layout, if (name < data + n) { - *rules = name; + nxagentRemoteRules = strdup(name); name += strlen(name) + 1; } if (name < data + n) { - *model = name; + nxagentRemoteModel = strdup(name); name += strlen(name) + 1; } if (name < data + n) { - *layout = name; + nxagentRemoteLayout = strdup(name); name += strlen(name) + 1; } if (name < data + n) { - *variant = name; + nxagentRemoteVariant = strdup(name); name += strlen(name) + 1; } if (name < data + n) { - *options = name; + nxagentRemoteOptions = strdup(name); 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: @@ -1600,7 +1645,7 @@ void writeKeyboardfileData(FILE *out, char *rules, char *model, char *layout, ch 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') { @@ -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) { fprintf(stderr, "Info: Keycode conversion is off\n"); - nxagentKeycodeConversion = False; } else if (nxagentOption(KeycodeConversion) == KeycodeConversionOn) { @@ -1658,9 +1707,9 @@ void nxagentKeycodeConversionSetup(char * rules, char * model) } else { - if (rules && model && - (strcmp(rules, "evdev") == 0 || - strcmp(model, "evdev") == 0)) + if (nxagentRemoteRules && nxagentRemoteModel && + (strcmp(nxagentRemoteRules, "evdev") == 0 || + strcmp(nxagentRemoteModel, "evdev") == 0)) { #ifdef DEBUG fprintf(stderr, "%s: Activating KeyCode conversion.\n", __func__); @@ -1676,47 +1725,33 @@ void nxagentKeycodeConversionSetup(char * rules, char * model) #endif fprintf(stderr, "Info: Keycode conversion auto-determined as off\n"); - nxagentKeycodeConversion = False; } } } -void nxagentResetKeycodeConversion(void) +Bool nxagentGetRemoteXkbExtension(void) { - int result; - XkbAgentInfoRec info; + Bool result; - result = XkbQueryExtension(nxagentDisplay, &info.Opcode, &info.EventBase, - &info.ErrorBase, &info.MajorVersion, - &info.MinorVersion); + nxagentXkbInfo.Opcode = nxagentXkbInfo.EventBase = nxagentXkbInfo.ErrorBase = nxagentXkbInfo.MajorVersion = nxagentXkbInfo.MinorVersion = -1; + nxagentXkbClearNames(); - if (result != 0) + if ((result = XkbQueryExtension(nxagentDisplay, + &nxagentXkbInfo.Opcode, + &nxagentXkbInfo.EventBase, + &nxagentXkbInfo.ErrorBase, + &nxagentXkbInfo.MajorVersion, + &nxagentXkbInfo.MinorVersion))) { - char *remoterules = NULL; - 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); + nxagentXkbGetNames(); } + #ifdef WARNING else { - #ifdef WARNING - fprintf(stderr, "nxagentResetKeycodeConversion: " - "WARNING! Failed to query XKB extension.\n"); - #endif - - nxagentKeycodeConversion = False; + fprintf(stderr, "%s: WARNING! Failed to query XKB extension.\n", __func__); } -} + #endif + return result; +} #endif /* XKB */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.h b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.h index ba95a3a22..dbfb47733 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.h +++ b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.h @@ -117,8 +117,9 @@ void nxagentEnableXkbExtension(void); void nxagentTuneXkbWrapper(void); -void nxagentResetKeycodeConversion(void); +void nxagentKeycodeConversionSetup(void); +Bool nxagentGetRemoteXkbExtension(void); #endif CARD8 nxagentConvertKeycode(CARD8 k); diff --git a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c index 4b1ae03f9..91445a383 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c @@ -584,6 +584,9 @@ Bool nxagentReconnectSession(void) goto nxagentReconnectError; } + /* Update remote XKB information */ + nxagentGetRemoteXkbExtension(); + /* if there's no keyboard definition in the options file restore the previous value. */ #ifdef DEBUG @@ -598,7 +601,8 @@ Bool nxagentReconnectSession(void) if (nxagentOption(ResetKeyboardAtResume) == 1 && (nxagentKeyboard == NULL || nxagentOldKeyboard == NULL || strcmp(nxagentKeyboard, nxagentOldKeyboard) != 0 || - strcmp(nxagentKeyboard, "query") == 0)) + strcmp(nxagentKeyboard, "query") == 0 || + strcmp(nxagentKeyboard, "clone") == 0)) { if (nxagentResetKeyboard() == 0) { @@ -616,7 +620,7 @@ Bool nxagentReconnectSession(void) } else { - nxagentResetKeycodeConversion(); + nxagentKeycodeConversionSetup(); } nxagentXkbState.Initialized = 0; diff --git a/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 index 892248d60..938c2eb57 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 +++ b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 @@ -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 case \fBnxagent\fR will lock the keyboard settings and clients will get an error when trying to change keyboard settings via -XKEYBOARD. With \-noxkblock the lock is not applied and clients can -change the keyboard settings through XKEYBOARD. +XKEYBOARD. With \-noxkblock the lock is not applied and clients are +allowed change the keyboard settings through XKEYBOARD. .TP 8 .B \-tile WxH size of image tiles (minimum allowed: 32x32) @@ -603,7 +603,7 @@ start or resume a session in fullscreen mode (default: off) .TP 8 .B keyboard=<string> or kbtype=<string> -.BR query | <model>/<layout> +.BR query | clone | <model>/<layout> | rmlvo/<rules>#<model>#<layout>#<variant>#<options> .RS 8 .TP 8 @@ -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 settings. .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> 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. +.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 .TP 8 |