aboutsummaryrefslogtreecommitdiff
path: root/debian/patches/0320_nxagent_configurable-keystrokes.full.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0320_nxagent_configurable-keystrokes.full.patch')
-rw-r--r--debian/patches/0320_nxagent_configurable-keystrokes.full.patch1050
1 files changed, 0 insertions, 1050 deletions
diff --git a/debian/patches/0320_nxagent_configurable-keystrokes.full.patch b/debian/patches/0320_nxagent_configurable-keystrokes.full.patch
deleted file mode 100644
index 495e00770..000000000
--- a/debian/patches/0320_nxagent_configurable-keystrokes.full.patch
+++ /dev/null
@@ -1,1050 +0,0 @@
-Author: Alexander Wuerstlein <arw@arw.name>
-Description: Make nxagent-specific keyboard bindings configurable
- Replaces the hardcoded nxagent keybindings by a configurable
- table of keybindings. The default configuration is the same as the
- original one, to maintain compatibility. A user/administrator can either
- specify a command line parameter, environment variable or place a file
- in ~/.nx/config/keystrokes.cfg or /etc/nxagent/keystrokes.cfg to reconfigure
- these keybindings.
- .
- The configuration file format is XML, a dependency on libxml2 is added
- to allow parsing the configuration.
---- a/nx-X11/programs/Xserver/Imakefile
-+++ b/nx-X11/programs/Xserver/Imakefile
-@@ -1013,15 +1013,18 @@ $(NXAGENTOBJS) $(NXAGENTLIBS) $(NXAGENTS
- #if defined(SunArchitecture)
- NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext -L ../../../nxcompshad \
- -lXcomp -lXcompext -lXcompshad -lrt -L/usr/sfw/lib -lXrender -lXfixes \
-- -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXdmcp
-+ -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXdmcp \
-+`pkg-config --libs libxml-2.0`
- #elif defined(cygwinArchitecture)
- NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext \
- -lXcomp -lXcompext -lXrender -lX11 -lXext -lXcomposite -lXfixes \
-- -L ../../../nxcompshad -lXcompshad -L../../../nx-X11/exports/lib -lXtst -lXdmcp
-+ -L ../../../nxcompshad -lXcompshad -L../../../nx-X11/exports/lib -lXtst -lXdmcp \
-+`pkg-config --libs libxml-2.0`
- #else
- NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext -L ../../../nxcompshad \
- -lXcomp -lXcompext -lXcompshad -lXrender -lX11 -lXext -lXfixes \
-- -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXinerama -lXdmcp
-+ -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXinerama -lXdmcp \
-+`pkg-config --libs libxml-2.0`
- #endif
-
- #endif
---- a/nx-X11/programs/Xserver/hw/nxagent/Imakefile
-+++ b/nx-X11/programs/Xserver/hw/nxagent/Imakefile
-@@ -142,7 +142,8 @@ INCLUDES = -I. -I../../../../../nxcomp -
- -I../../miext/damage -I../../miext/cw \
- -I../../GL/glx -I../../GL/include -I../../../../lib/GL/include -I../../Xext \
- -I$(EXTINCSRC) -I$(XINCLUDESRC) \
-- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES)
-+ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \
-+ `pkg-config --cflags-only-I libxml-2.0`
- #ifdef SunArchitecture
- INCLUDES = -I. -I../../../../../nxcomp -I../../../../../nxcompext -I../../../../../nxcompshad \
- -I../../../../extras/Mesa/include \
-@@ -152,7 +153,8 @@ INCLUDES = -I. -I../../../../../nxcomp -
- -I../../GL/glx -I../../GL/include -I../../../../lib/GL/include -I../../Xext \
- -I../../miext/damage -I../../miext/cw \
- -I$(EXTINCSRC) -I$(XINCLUDESRC) \
-- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES)
-+ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \
-+ `pkg-config --cflags-only-I libxml-2.0`
- #else
- #ifdef cygwinArchitecture
- INCLUDES = -I. -I$(XBUILDINCDIR) -I$(FONTINCSRC) \
-@@ -162,7 +164,8 @@ INCLUDES = -I. -I$(XBUILDINCDIR) -I$(FON
- -I../../../../../nxcomp -I../../../../../nxcompext -I../../../../../nxcompshad \
- -I../../../../extras/Mesa/include \
- -I$(EXTINCSRC) -I$(XINCLUDESRC) \
-- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES)
-+ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \
-+ `pkg-config --cflags-only-I libxml-2.0`
- #endif
- #endif
-
---- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c
-+++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c
-@@ -28,8 +28,15 @@
- #include "Keystroke.h"
- #include "Drawable.h"
-
-+#include <unistd.h>
-+
-+#include <libxml/parser.h>
-+#include <libxml/tree.h>
-+
- extern Bool nxagentWMIsRunning;
- extern Bool nxagentIpaq;
-+extern char *nxagentKeystrokeFile;
-+Bool nxagentKeystrokeFileParsed = False;
-
- #ifdef NX_DEBUG_INPUT
- int nxagentDebugInputDevices = 0;
-@@ -47,297 +54,528 @@ extern void nxagentDeactivateInputDevice
- #undef DEBUG
- #undef DUMP
-
--int nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result)
--{
-- KeySym sym;
-- int index = 0;
-
-- *result = doNothing;
-+/* this table is used to parse actions given on the command line or in the
-+ * config file, therefore indices have to match the enum in Keystroke.h */
-+char * nxagentSpecialKeystrokeNames[] = {
-+ "end_marker",
-+ "close_session",
-+ "switch_all_screens",
-+ "minimize",
-+ "left",
-+ "up",
-+ "right",
-+ "down",
-+ "resize",
-+ "defer",
-+ "ignore",
-+ "force_synchronization",
-+
-+ "debug_tree",
-+ "regions_on_screen",
-+ "test_input",
-+ "deactivate_input_devices_grab",
-+
-+ "fullscreen",
-+ "viewport_move_left",
-+ "viewport_move_up",
-+ "viewport_move_right",
-+ "viewport_move_down",
-+ NULL,
-+};
-+
-+struct nxagentSpecialKeystrokeMap default_map[] = {
-+ /* stroke, modifierMask, modifierAltMeta, keysym */
-+ {KEYSTROKE_DEBUG_TREE, ControlMask, 1, XK_q},
-+ {KEYSTROKE_DEBUG_TREE, ControlMask, 1, XK_Q},
-+ {KEYSTROKE_CLOSE_SESSION, ControlMask, 1, XK_t},
-+ {KEYSTROKE_CLOSE_SESSION, ControlMask, 1, XK_T},
-+ {KEYSTROKE_SWITCH_ALL_SCREENS, ControlMask, 1, XK_f},
-+ {KEYSTROKE_SWITCH_ALL_SCREENS, ControlMask, 1, XK_F},
-+ {KEYSTROKE_MINIMIZE, ControlMask, 1, XK_m},
-+ {KEYSTROKE_MINIMIZE, ControlMask, 1, XK_M},
-+ {KEYSTROKE_LEFT, ControlMask, 1, XK_Left},
-+ {KEYSTROKE_LEFT, ControlMask, 1, XK_KP_Left},
-+ {KEYSTROKE_UP, ControlMask, 1, XK_Up},
-+ {KEYSTROKE_UP, ControlMask, 1, XK_KP_Up},
-+ {KEYSTROKE_RIGHT, ControlMask, 1, XK_Right},
-+ {KEYSTROKE_RIGHT, ControlMask, 1, XK_KP_Right},
-+ {KEYSTROKE_DOWN, ControlMask, 1, XK_Down},
-+ {KEYSTROKE_DOWN, ControlMask, 1, XK_KP_Down},
-+ {KEYSTROKE_RESIZE, ControlMask, 1, XK_r},
-+ {KEYSTROKE_RESIZE, ControlMask, 1, XK_R},
-+ {KEYSTROKE_DEFER, ControlMask, 1, XK_e},
-+ {KEYSTROKE_DEFER, ControlMask, 1, XK_E},
-+ {KEYSTROKE_IGNORE, ControlMask, 1, XK_BackSpace},
-+ {KEYSTROKE_IGNORE, 0, 0, XK_Terminate_Server},
-+ {KEYSTROKE_FORCE_SYNCHRONIZATION, ControlMask, 1, XK_j},
-+ {KEYSTROKE_FORCE_SYNCHRONIZATION, ControlMask, 1, XK_J},
-+ {KEYSTROKE_REGIONS_ON_SCREEN, ControlMask, 1, XK_a},
-+ {KEYSTROKE_REGIONS_ON_SCREEN, ControlMask, 1, XK_A},
-+ {KEYSTROKE_TEST_INPUT, ControlMask, 1, XK_x},
-+ {KEYSTROKE_TEST_INPUT, ControlMask, 1, XK_X},
-+ {KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, ControlMask, 1, XK_y},
-+ {KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, ControlMask, 1, XK_Y},
-+ {KEYSTROKE_FULLSCREEN, ControlMask | ShiftMask, 1, XK_f},
-+ {KEYSTROKE_FULLSCREEN, ControlMask | ShiftMask, 1, XK_F},
-+ {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, 1, XK_Left},
-+ {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, 1, XK_KP_Left},
-+ {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, 1, XK_Up},
-+ {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, 1, XK_KP_Up},
-+ {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, 1, XK_Right},
-+ {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, 1, XK_KP_Right},
-+ {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, 1, XK_Down},
-+ {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, 1, XK_KP_Down},
-+ {KEYSTROKE_END_MARKER, 0, 0, 0},
-+};
-+struct nxagentSpecialKeystrokeMap *map = default_map;
-
-- /*
-- * I don't know how much hard work is doing this operation.
-- * Do we need a cache ?
-+static int modifier_matches(unsigned int mask, int compare_alt_meta, unsigned int state)
-+{
-+ /* nxagentAltMetaMask needs special handling
-+ * it seems to me its an and-ed mask of all possible meta and alt keys
-+ * somehow...
-+ *
-+ * otherwise this function would be just a simple bitop
- */
-+ int ret = 1;
-
-- sym = XKeycodeToKeysym(nxagentDisplay, X -> keycode, index);
-+ if (compare_alt_meta) {
-+ if (! (state & nxagentAltMetaMask)) {
-+ ret = 0;
-+ }
-
-- if (sym == XK_VoidSymbol || sym == NoSymbol)
-- {
-- return 0;
-+ mask &= ~nxagentAltMetaMask;
- }
-
-- #ifdef TEST
-- fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - sym %lx\n",
-- X -> keycode, X -> state, sym);
-- #endif
--
-- /*
-- * Check special keys.
-- */
--
-- /*
-- * FIXME: We should use the keysym instead that the keycode
-- * here.
-- */
-+ /* all modifiers except meta/alt have to match exactly, extra bits are evil */
-+ if ((mask & state) != mask) {
-+ ret = 0;
-+ }
-
-- if (X -> keycode == 130 && nxagentIpaq)
-- {
-- *result = doStartKbd;
-+ return ret;
-+}
-
-- return 1;
-- }
-+static int read_binding_from_xmlnode(xmlNode *node, struct nxagentSpecialKeystrokeMap *ret)
-+{
-+ int successful = 0;
-+ struct nxagentSpecialKeystrokeMap new = {0, 0, 0, 0};
-+ xmlAttr *attr;
-
-- if ((X -> state & nxagentAltMetaMask) &&
-- ((X -> state & (ControlMask | ShiftMask)) == ControlMask))
-+ for (attr = node->properties; attr; attr = attr->next)
- {
-- switch (sym)
-+ /* ignore attributes without data (which should never happen anyways) */
-+ if (attr->children->content == NULL)
- {
-- #ifdef DEBUG_TREE
--
-- case XK_q:
-- case XK_Q:
-- {
-- *result = doDebugTree;
--
-- break;
-- }
--
-- #endif /* DEBUG_TREE */
--
-- case XK_t:
-- case XK_T:
-- {
-- *result = doCloseSession;
--
-- break;
-- }
-- case XK_f:
-- case XK_F:
-+ char *aname = (attr->name)?(attr->name):"unknown";
-+ fprintf(stderr, "attribute %s with NULL value", aname);
-+ continue;
-+ }
-+ if (strcmp((char *)attr->name, "action") == 0)
-+ {
-+ int i;
-+ for (i = 0; nxagentSpecialKeystrokeNames[i] != NULL; i++)
- {
-- if (nxagentOption(Rootless) == False)
-+ if (strcmp(nxagentSpecialKeystrokeNames[i],(char *)attr->children->content) == 0)
- {
-- *result = doSwitchAllScreens;
-+ /* this relies on the values of enum nxagentSpecialKeystroke and the
-+ * indices of nxagentSpecialKeystrokeNames being in sync */
-+ new.stroke = i;
-+ break;
- }
--
-- break;
- }
-- case XK_m:
-- case XK_M:
-+ continue;
-+ }
-+ else if (strcmp((char *)attr->name, "key") == 0)
-+ {
-+ new.keysym = XStringToKeysym((char *)attr->children->content);
-+ /* NoSymbol is usually 0, but could there be weird implementations? */
-+ if (new.keysym == NoSymbol)
- {
-- if (nxagentOption(Rootless) == False)
-- {
-- *result = doMinimize;
-- }
--
-- break;
-+ new.keysym = 0;
- }
-- case XK_Left:
-- case XK_KP_Left:
-- {
-- if (nxagentOption(Rootless) == False &&
-- nxagentOption(DesktopResize) == False)
-- {
-- *result = doViewportLeft;
-- }
-+ continue;
-+ }
-
-- break;
-- }
-- case XK_Up:
-- case XK_KP_Up:
-- {
-- if (nxagentOption(Rootless) == False &&
-- nxagentOption(DesktopResize) == False)
-- {
-- *result = doViewportUp;
-- }
-+ /* ignore attributes with value="0" or "false", everything else is interpreted as true */
-+ if (strcmp((char *)attr->children->content, "0") == 0 || strcmp((char *)attr->children->content, "false") == 0)
-+ continue;
-
-- break;
-- }
-- case XK_Right:
-- case XK_KP_Right:
-- {
-- if (nxagentOption(Rootless) == False &&
-- nxagentOption(DesktopResize) == False)
-- {
-- *result = doViewportRight;
-- }
-+ if (strcmp((char *)attr->name, "Mod1") == 0)
-+ {
-+ new.modifierMask |= Mod1Mask;
-+ }
-+ else if (strcmp((char *)attr->name, "Mod2") == 0)
-+ {
-+ new.modifierMask |= Mod2Mask;
-+ }
-+ else if (strcmp((char *)attr->name, "Mod3") == 0)
-+ {
-+ new.modifierMask |= Mod3Mask;
-+ }
-+ else if (strcmp((char *)attr->name, "Mod4") == 0)
-+ {
-+ new.modifierMask |= Mod4Mask;
-+ }
-+ else if (strcmp((char *)attr->name, "Control") == 0)
-+ {
-+ new.modifierMask |= ControlMask;
-+ }
-+ else if (strcmp((char *)attr->name, "Shift") == 0)
-+ {
-+ new.modifierMask |= ShiftMask;
-+ }
-+ else if (strcmp((char *)attr->name, "Lock") == 0)
-+ {
-+ new.modifierMask |= LockMask;
-+ }
-+ else if (strcmp((char *)attr->name, "AltMeta") == 0)
-+ {
-+ new.modifierAltMeta = 1;
-+ }
-+ }
-
-- break;
-- }
-- case XK_Down:
-- case XK_KP_Down:
-- {
-- if (nxagentOption(Rootless) == 0 &&
-- nxagentOption(DesktopResize) == 0)
-- {
-- *result = doViewportDown;
-- }
-+ if (new.stroke != 0 && new.keysym != 0)
-+ {
-+ /* keysym and stroke are required, everything else is optional */
-+ successful = 1;
-+ memcpy(ret, &new, sizeof(struct nxagentSpecialKeystrokeMap));
-+ }
-+ return successful;
-+}
-
-- break;
-- }
-- case XK_R:
-- case XK_r:
-- {
-- if (nxagentOption(Rootless) == 0)
-- {
-- *result = doSwitchResizeMode;
-- }
-+/*
-+ * searches a keystroke xml file
-+ *
-+ * search order:
-+ * - '-keystrokefile' commandline parameter
-+ * - $NXAGENT_KEYSTROKEFILE environment variable
-+ * - $HOME/.nx/config/keystrokes.cfg
-+ * - /etc/nxagent/keystrokes.cfg
-+ * - hardcoded traditional NX default settings
-+ */
-+static void parse_keystroke_file(void)
-+{
-+ char *filename = NULL;
-
-- break;
-- }
-- case XK_E:
-- case XK_e:
-- {
-- *result = doSwitchDeferMode;
-+ char *homefile = "/.nx/config/keystrokes.cfg";
-+ char *etcfile = "/etc/nxagent/keystrokes.cfg";
-
-- break;
-+ if (nxagentKeystrokeFile != NULL && access(nxagentKeystrokeFile, R_OK) == 0)
-+ {
-+ filename = strdup(nxagentKeystrokeFile);
-+ if (filename == NULL)
-+ {
-+ fprintf(stderr, "malloc failed");
-+ exit(EXIT_FAILURE);
-+ }
-+ }
-+ else if ((filename = getenv("NXAGENT_KEYSTROKEFILE")) != NULL && access(filename, R_OK) == 0)
-+ {
-+ filename = strdup(filename);
-+ if (filename == NULL)
-+ {
-+ fprintf(stderr, "malloc failed");
-+ exit(EXIT_FAILURE);
-+ }
-+ }
-+ else
-+ {
-+ char *homedir = getenv("HOME");
-+ filename = NULL;
-+ if (homedir != NULL)
-+ {
-+ homedir = strdup(homedir);
-+ if (homedir == NULL)
-+ {
-+ fprintf(stderr, "malloc failed");
-+exit(EXIT_FAILURE);
- }
-- case XK_BackSpace:
-- case XK_Terminate_Server:
-+ filename = calloc(1, strlen(homefile) + strlen(homedir) + 1);
-+ if (filename == NULL)
- {
-- /*
-- * Discard Ctrl-Alt-BackSpace key.
-- */
--
-- return 1;
--
-- break;
-+ fprintf(stderr, "malloc failed");
-+ exit(EXIT_FAILURE);
- }
--
-- case XK_J:
-- case XK_j:
-+ strcpy(filename, homedir);
-+ strcpy(filename + strlen(homedir), homefile);
-+ if (homedir)
- {
-- nxagentForceSynchronization = 1;
--
-- return 1;
-+ free(homedir);
- }
-+ }
-
-- #ifdef DUMP
--
-- case XK_A:
-- case XK_a:
-+ if (access(filename, R_OK) == 0)
-+ {
-+ /* empty */
-+ }
-+ else if (access(etcfile, R_OK) == 0)
-+ {
-+ if (filename)
-+ free(filename);
-+ filename = strdup(etcfile);
-+ if (filename == NULL)
- {
-- /*
-- * Used to test the lazy encoding.
-- */
--
-- nxagentRegionsOnScreen();
--
-- return 1;
-+ fprintf(stderr, "malloc failed");
-+ exit(EXIT_FAILURE);
- }
-+ }
-+ else
-+ {
-+ if (filename)
-+free(filename);
-+ filename = NULL;
-+ }
-+ }
-
-- #endif
--
-- #ifdef NX_DEBUG_INPUT
-+ /* now we know which file to read, if any */
-+ if (filename)
-+ {
-+ xmlDoc *doc = NULL;
-+ xmlNode *root = NULL;
-+ LIBXML_TEST_VERSION
-+ doc = xmlReadFile(filename, NULL, 0);
-+ if (doc != NULL)
-+ {
-+ xmlNode *cur = NULL;
-+ root = xmlDocGetRootElement(doc);
-
-- case XK_X:
-- case XK_x:
-+ for (cur = root; cur; cur = cur->next)
- {
-- /*
-- * Used to test the input devices state.
-- */
-+ if (cur->type == XML_ELEMENT_NODE && strcmp((char *)cur->name, "keystrokes") == 0)
-+{
-+ xmlNode *bindings = NULL;
-+ int num = 0;
-+ int idx = 0;
-
-- if (X -> type == KeyPress)
-- {
-- if (nxagentDebugInputDevices == 0)
-+ for (bindings = cur->children; bindings; bindings = bindings->next)
- {
-- fprintf(stderr, "Info: Turning input devices debug ON.\n");
--
-- nxagentDebugInputDevices = 1;
-+ if (bindings->type == XML_ELEMENT_NODE && strcmp((char *)bindings->name, "keystroke") == 0)
-+ {
-+ num++;
-+ }
- }
-- else
-+ map = calloc((num + 1), sizeof(struct nxagentSpecialKeystrokeMap));
-+ if (map == NULL)
- {
-- fprintf(stderr, "Info: Turning input devices debug OFF.\n");
--
-- nxagentDebugInputDevices = 0;
--
-- nxagentLastInputDevicesDumpTime = 0;
-+ fprintf(stderr, "malloc failed");
-+ exit(EXIT_FAILURE);
- }
-- }
--
-- return 1;
-- }
-
-- case XK_Y:
-- case XK_y:
-- {
-- /*
-- * Used to deactivate input devices grab.
-- */
-+ for (bindings = cur->children; bindings; bindings = bindings->next)
-+ {
-+ if (bindings->type == XML_ELEMENT_NODE && strcmp((char *)bindings->name, "keystroke") == 0)
-+ {
-+ int res = 0;
-+ res = read_binding_from_xmlnode(bindings, &(map[idx]));
-+ if (res)
-+ idx++;
-+ }
-+ }
-
-- if (X -> type == KeyPress)
-- {
-- nxagentDeactivateInputDevicesGrabs();
-+ map[idx].stroke = KEYSTROKE_END_MARKER;
- }
--
-- return 1;
- }
-
-+ xmlFreeDoc(doc);
-+ xmlCleanupParser();
-+ }
-+ else
-+ {
-+ #ifdef DEBUG
-+ fprintf("XML parsing for %s failed\n", filename);
- #endif
- }
-+ free(filename);
- }
-- else if ((X -> state & nxagentAltMetaMask) &&
-- ((X -> state & (ControlMask | ShiftMask)) == (ControlMask |
-- ShiftMask)))
-+}
-+
-+static enum nxagentSpecialKeystroke find_keystroke(XKeyEvent *X)
-+{
-+ KeySym keysym = XKeycodeToKeysym(nxagentDisplay, X->keycode, 0);
-+ struct nxagentSpecialKeystrokeMap *cur = map;
-+
-+ if (! nxagentKeystrokeFileParsed)
- {
-- switch (sym)
-- {
-- case XK_f:
-- case XK_F:
-- {
-- if (nxagentOption(Rootless) == 0)
-- {
-- *result = doSwitchFullscreen;
-- }
-+ parse_keystroke_file();
-+ nxagentKeystrokeFileParsed = True;
-+ }
-
-- break;
-- }
-- case XK_Left:
-- case XK_KP_Left:
-- {
-- if (nxagentOption(Rootless) == 0 &&
-- nxagentOption(DesktopResize) == 0)
-- {
-- *result = doViewportMoveLeft;
-- }
-+ enum nxagentSpecialKeystroke ret = KEYSTROKE_NOTHING;
-
-- break;
-- }
-- case XK_Up:
-- case XK_KP_Up:
-- {
-- if (nxagentOption(Rootless) == 0 &&
-- nxagentOption(DesktopResize) == 0)
-- {
-- *result = doViewportMoveUp;
-- }
-+ while (cur->stroke != KEYSTROKE_END_MARKER) {
-+ if (cur->keysym == keysym && modifier_matches(cur->modifierMask, cur->modifierAltMeta, X->state)) {
-+ return cur->stroke;
-+ }
-+ cur++;
-+ }
-
-- break;
-- }
-- case XK_Right:
-- case XK_KP_Right:
-- {
-- if (nxagentOption(Rootless) == 0 &&
-- nxagentOption(DesktopResize) == 0)
-- {
-- *result = doViewportMoveRight;
-- }
-+ return ret;
-+}
-
-- break;
-- }
-- case XK_Down:
-- case XK_KP_Down:
-- {
-- if (nxagentOption(Rootless) == 0 &&
-- nxagentOption(DesktopResize) == 0)
-- {
-- *result = doViewportMoveDown;
-- }
-+int nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result)
-+{
-+ KeySym sym;
-+ int index = 0;
-+ enum nxagentSpecialKeystroke stroke = find_keystroke(X);
-
-- break;
-- }
-- }
-+ *result = doNothing;
-+
-+ /*
-+ * I don't know how much hard work is doing this operation.
-+ * Do we need a cache ?
-+ */
-+
-+ sym = XKeycodeToKeysym(nxagentDisplay, X -> keycode, index);
-+
-+ if (sym == XK_VoidSymbol || sym == NoSymbol)
-+ {
-+ return 0;
- }
-
-+ #ifdef TEST
-+ fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - sym %lx\n",
-+ X -> keycode, X -> state, sym);
-+ #endif
-+
-+ /*
-+ * Check special keys.
-+ */
-+
-+ /*
-+ * FIXME: We should use the keysym instead that the keycode
-+ * here.
-+ */
-+
-+ if (X -> keycode == 130 && nxagentIpaq)
-+ {
-+ *result = doStartKbd;
-+
-+ return 1;
-+ }
-+
-+ switch (stroke) {
-+ case KEYSTROKE_DEBUG_TREE:
-+ #ifdef DEBUG_TREE
-+ *result = doDebugTree;
-+ #endif
-+ break;
-+ case KEYSTROKE_CLOSE_SESSION:
-+ *result = doCloseSession;
-+ break;
-+ case KEYSTROKE_SWITCH_ALL_SCREENS:
-+ if (nxagentOption(Rootless) == False) {
-+ *result = doSwitchAllScreens;
-+ }
-+ break;
-+ case KEYSTROKE_MINIMIZE:
-+ if (nxagentOption(Rootless) == False) {
-+ *result = doMinimize;
-+ }
-+ break;
-+ case KEYSTROKE_LEFT:
-+ if (nxagentOption(Rootless) == False &&
-+ nxagentOption(DesktopResize) == False) {
-+ *result = doViewportLeft;
-+ }
-+ break;
-+ case KEYSTROKE_UP:
-+ if (nxagentOption(Rootless) == False &&
-+ nxagentOption(DesktopResize) == False) {
-+ *result = doViewportUp;
-+ }
-+ break;
-+ case KEYSTROKE_RIGHT:
-+ if (nxagentOption(Rootless) == False &&
-+ nxagentOption(DesktopResize) == False) {
-+ *result = doViewportRight;
-+ }
-+ break;
-+ case KEYSTROKE_DOWN:
-+ if (nxagentOption(Rootless) == False &&
-+ nxagentOption(DesktopResize) == False) {
-+ *result = doViewportDown;
-+ }
-+ break;
-+ case KEYSTROKE_RESIZE:
-+ if (nxagentOption(Rootless) == False) {
-+ *result = doSwitchResizeMode;
-+ }
-+ break;
-+ case KEYSTROKE_DEFER:
-+ *result = doSwitchDeferMode;
-+ break;
-+ case KEYSTROKE_IGNORE:
-+ /* this is used e.g. to ignore C-A-Backspace aka XK_Terminate_Server */
-+ return 1;
-+ break;
-+ case KEYSTROKE_FORCE_SYNCHRONIZATION:
-+ nxagentForceSynchronization = 1;
-+ break;
-+ case KEYSTROKE_REGIONS_ON_SCREEN:
-+ #ifdef DUMP
-+ nxagentRegionsOnScreen();
-+ #endif
-+ break;
-+ case KEYSTROKE_TEST_INPUT:
-+ /*
-+ * Used to test the input devices state.
-+ */
-+ #ifdef NX_DEBUG_INPUT
-+ if (X -> type == KeyPress) {
-+ if (nxagentDebugInputDevices == 0) {
-+ fprintf(stderr, "Info: Turning input devices debug ON.\n");
-+ nxagentDebugInputDevices = 1;
-+ } else {
-+ fprintf(stderr, "Info: Turning input devices debug OFF.\n");
-+ nxagentDebugInputDevices = 0;
-+ nxagentLastInputDevicesDumpTime = 0;
-+ }
-+ }
-+ return 1;
-+ #endif
-+ break;
-+ case KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB:
-+ #ifdef NX_DEBUG_INPUT
-+ if (X->type == KeyPress) {
-+ nxagentDeactivateInputDevicesGrab();
-+ }
-+ return 1;
-+ #endif
-+ break;
-+ case KEYSTROKE_FULLSCREEN:
-+ if (nxagentOption(Rootless) == 0) {
-+ *result = doSwitchFullscreen;
-+ }
-+ break;
-+ case KEYSTROKE_VIEWPORT_MOVE_LEFT:
-+ if (nxagentOption(Rootless) == 0 &&
-+ nxagentOption(DesktopResize) == 0) {
-+ *result = doViewportMoveLeft;
-+ }
-+ break;
-+ case KEYSTROKE_VIEWPORT_MOVE_UP:
-+ if (nxagentOption(Rootless) == 0 &&
-+ nxagentOption(DesktopResize) == 0) {
-+ *result = doViewportMoveUp;
-+ }
-+ break;
-+ case KEYSTROKE_VIEWPORT_MOVE_RIGHT:
-+ if (nxagentOption(Rootless) == 0 &&
-+ nxagentOption(DesktopResize) == 0) {
-+ *result = doViewportMoveRight;
-+ }
-+ break;
-+ case KEYSTROKE_VIEWPORT_MOVE_DOWN:
-+ if (nxagentOption(Rootless) == 0 &&
-+ nxagentOption(DesktopResize) == 0) {
-+ *result = doViewportMoveDown;
-+ }
-+ break;
-+ case KEYSTROKE_NOTHING: /* do nothing. difference to KEYSTROKE_IGNORE is the return value */
-+ case KEYSTROKE_END_MARKER: /* just to make gcc STFU */
-+ case KEYSTROKE_MAX:
-+ break;
-+ }
- return (*result == doNothing) ? 0 : 1;
- }
---- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h
-+++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h
-@@ -24,4 +24,51 @@ extern int nxagentCheckSpecialKeystroke(
-
- unsigned int nxagentAltMetaMask;
-
-+/* keep this sorted, do not rely on any numerical value in this enum, and be aware
-+ * that KEYSTROKE_MAX may be used in a malloc */
-+
-+/* also be aware that if changing any numerical values, you also need to change values
-+ * Keystroke.c nxagentSpecialKeystrokeNames */
-+enum nxagentSpecialKeystroke {
-+ /* 0 is used as end marker */
-+ KEYSTROKE_END_MARKER = 0,
-+ KEYSTROKE_CLOSE_SESSION = 1,
-+ KEYSTROKE_SWITCH_ALL_SCREENS = 2,
-+ KEYSTROKE_MINIMIZE = 3,
-+ KEYSTROKE_LEFT = 4,
-+ KEYSTROKE_UP = 5,
-+ KEYSTROKE_RIGHT = 6,
-+ KEYSTROKE_DOWN = 7,
-+ KEYSTROKE_RESIZE = 8,
-+ KEYSTROKE_DEFER = 9,
-+ KEYSTROKE_IGNORE = 10,
-+ KEYSTROKE_FORCE_SYNCHRONIZATION = 11,
-+
-+ /* stuff used for debugging, probably not useful for most people */
-+ KEYSTROKE_DEBUG_TREE = 12,
-+ KEYSTROKE_REGIONS_ON_SCREEN = 13,
-+ KEYSTROKE_TEST_INPUT = 14,
-+ KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB = 15,
-+
-+ KEYSTROKE_FULLSCREEN = 16,
-+ KEYSTROKE_VIEWPORT_MOVE_LEFT = 17,
-+ KEYSTROKE_VIEWPORT_MOVE_UP = 18,
-+ KEYSTROKE_VIEWPORT_MOVE_RIGHT = 19,
-+ KEYSTROKE_VIEWPORT_MOVE_DOWN = 20,
-+
-+ KEYSTROKE_NOTHING = 21,
-+
-+ /* insert more here, increment KEYSTROKE_MAX accordingly.
-+ * then update string translation below */
-+
-+ KEYSTROKE_MAX=22,
-+};
-+
-+struct nxagentSpecialKeystrokeMap {
-+ enum nxagentSpecialKeystroke stroke;
-+ unsigned int modifierMask; /* everything except alt/meta */
-+ int modifierAltMeta; /* modifier combination should include alt/meta */
-+ KeySym keysym;
-+};
-+
- #endif /* __Keystroke_H__ */
---- /dev/null
-+++ b/README.keystrokes
-@@ -0,0 +1,102 @@
-+Configurable keybindings in nxagent
-+
-+Keybindings in the redistributed x2go version of nxagent can now be configured
-+by the user. This is done via a configuration file.
-+
-+File location
-+-------------
-+
-+nxagent parses the first available configuration file and ignores all others.
-+
-+If nxagent is called without branding, it searches:
-+- in the location given by the '-keystrokefile' command line parameter
-+- in the location given by the NXAGENT_KEYSTROKEFILE environment variable
-+- in ~/.nx/config/keystrokes.cfg
-+- in /etc/nxagent/keystrokes.cfg
-+
-+If nxagent is called with X2Go branding (i.e., as x2goagent), it searches:
-+- in the location given by the '-keystrokefile' command line parameter
-+- in the location given by the NXAGENT_KEYSTROKEFILE environment variable
-+- in ~/.x2go/config/keystrokes.cfg
-+- in /etc/x2go/keystrokes.cfg
-+
-+If none of these files are accessible, the default configuration is used which
-+is the same as the old, traditional nxagent keybindings.
-+
-+File format
-+-----------
-+
-+The configuration file is XML with the following format:
-+
-+<!DOCTYPE NXKeystroke>
-+<keystrokes>
-+<keystroke action="fullscreen" AltMeta="1" Control="1" key="b" />
-+<keystroke action="minimize" AltMeta="1" Control="1" key="space" />
-+<keystroke action="minimize" key="Escape" Shift="1" />
-+<keystroke action="close_session" key="F7" />
-+<keystroke action="fullscreen" key="F7" Mod1="1" />
-+<keystroke action="fullscreen" key="F6" Mod1="1" />
-+<keystroke action="force_synchronization" key="f" />
-+<keystroke action="fullscreen" key="space" Mod1="0" Mod2="0" Control="0" Shift="0" AltMeta="0" />
-+</keystrokes>
-+
-+Each 'action' defines an action to be executed when receiving that keystroke. A
-+list of possible actions is given below. Some of those actions are only
-+available with debug builds of nxagent.
-+
-+Keys are given as a combination of 'key' and (optionally) a number of
-+modifiers. The key attribute is evaluated into a X11 key via the usual
-+XStringToKeysym function. A list of possible keys can be found in
-+/usr/include/X11/keysymdef.h, the names are specified without the leading
-+'XK_'. Evaluation is case-sensitive, so, 'space' and 'Escape' will work while
-+'Space' and 'escape' won't.
-+
-+Modifiers are given as boolean attributes, possible modifiers are Mod1, Mod2,
-+Mod3, Mod4, Control, Shift, Lock. Sensible combinations strongly depend on your
-+keyboard configuration, but usually you will need Mod1 and Control. Boolean in
-+this context means '0', 'false' and an unspecified attribute are false, anything
-+else is considered true.
-+
-+Everything in this file is case-sensitive. Unknown lines are ignored.
-+Keybindings are evaluated from top to bottom, so if a keybinding matches, other
-+keybindings further down will be ignored. The contents of the file replaces the
-+default keybindings, and only one file is read, no merging between different
-+configuration files is done. This also means that an empty or invalid configuration
-+file deactivates all keybindings.
-+
-+List of possible 'action' attributes:
-+-------------------------------------
-+
-+close_session
-+ This terminates the session.
-+switch_all_screens
-+minimize
-+ This will minimize the client window (even for fullscreen sessions.)
-+left
-+up
-+right
-+down
-+resize
-+ This action switches between the auto-resize and viewport mode (static size). The default is auto-resize. In viewport mode one can use the 'viewport_move_up', 'viewport_move_down', 'viewport_move_left' and 'viewport_move_right' actions to move within the image.
-+defer
-+ Works like 'ignore' to make some keys be ignored/defunct inside the session.
-+ignore
-+ Makes it possible to add 'ignore', as in nothing happens when certain keys are pressed.
-+fullscreen
-+ Switches the client window into or out of fullscreen mode.
-+viewport_move_left
-+ Moves the image viewport to the left.
-+viewport_move_up
-+ Moves the image viewport up.
-+viewport_move_right
-+ Moves the image viewport to the right.
-+viewport_move_down
-+ Moves the image viewport down.
-+
-+Only in builds with certain debugging options enabled, ignored otherwise:
-+force_synchronization
-+ Forces the drawing of elements to be synchronized which can fix some visual bugs.
-+debug_tree
-+regions_on_screen
-+test_input
-+deactivate_input_devices_grab
---- a/nx-X11/programs/Xserver/hw/nxagent/Args.c
-+++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c
-@@ -149,6 +149,8 @@ static int nxagentGetDialogName(void);
-
- char nxagentVerbose = 0;
-
-+char *nxagentKeystrokeFile = NULL;
-+
- int ddxProcessArgument(int argc, char *argv[], int i)
- {
- /*
-@@ -1022,6 +1024,20 @@ int ddxProcessArgument(int argc, char *a
- return 1;
- }
-
-+ if (!strcmp(argv[i], "-keystrokefile"))
-+ {
-+ if (i + 1 < argc)
-+ {
-+ if (NULL != (nxagentKeystrokeFile = strdup(argv[i + 1])))
-+ {
-+ return 2;
-+ } else {
-+ FatalError("malloc failed");
-+ }
-+ }
-+ return 0;
-+ }
-+
- return 0;
- }
-
---- a/nx-X11/programs/Xserver/hw/nxagent/Args.h
-+++ b/nx-X11/programs/Xserver/hw/nxagent/Args.h
-@@ -83,4 +83,6 @@ extern int nxagentUserDefinedFontPath;
-
- extern int nxagentRemoteMajor;
-
-+extern char *nxagentKeystrokeFile;
-+
- #endif /* __Args_H__ */