You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/01/30 19:08:35 UTC

[07/11] guacamole-server git commit: GUACAMOLE-313: Refactor guaclog to produce simpler, greppable output.

GUACAMOLE-313: Refactor guaclog to produce simpler, greppable output.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-server/commit/5b612b85
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-server/tree/5b612b85
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-server/diff/5b612b85

Branch: refs/heads/master
Commit: 5b612b856afc29073595d7ce450560b0bff65415
Parents: 86b09c8
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Dec 6 21:25:58 2017 -0800
Committer: Michael Jumper <mj...@apache.org>
Committed: Fri Jan 26 16:24:45 2018 -0800

----------------------------------------------------------------------
 src/guaclog/Makefile.am |   4 +-
 src/guaclog/key-name.c  | 276 -------------------------------------------
 src/guaclog/key-name.h  |  50 --------
 src/guaclog/keydef.c    | 276 +++++++++++++++++++++++++++++++++++++++++++
 src/guaclog/keydef.h    |  73 ++++++++++++
 src/guaclog/state.c     | 111 ++++++++++++-----
 src/guaclog/state.h     |   5 +-
 7 files changed, 434 insertions(+), 361 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5b612b85/src/guaclog/Makefile.am
----------------------------------------------------------------------
diff --git a/src/guaclog/Makefile.am b/src/guaclog/Makefile.am
index 5007708..6acced3 100644
--- a/src/guaclog/Makefile.am
+++ b/src/guaclog/Makefile.am
@@ -28,7 +28,7 @@ noinst_HEADERS =   \
     guaclog.h      \
     instructions.h \
     interpret.h    \
-    key-name.h     \
+    keydef.h       \
     log.h          \
     state.h
 
@@ -37,7 +37,7 @@ guaclog_SOURCES =     \
     instructions.c    \
     instruction-key.c \
     interpret.c       \
-    key-name.c        \
+    keydef.c          \
     log.c             \
     state.c
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5b612b85/src/guaclog/key-name.c
----------------------------------------------------------------------
diff --git a/src/guaclog/key-name.c b/src/guaclog/key-name.c
deleted file mode 100644
index 5ae73b5..0000000
--- a/src/guaclog/key-name.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "config.h"
-#include "key-name.h"
-#include "log.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-/**
- * A mapping of X11 keysym to its corresponding human-readable name.
- */
-typedef struct guaclog_known_key {
-
-    /**
-     * The X11 keysym of the key.
-     */
-    const int keysym;
-
-    /**
-     * A human-readable name for the key.
-     */
-    const char* name;
-
-} guaclog_known_key;
-
-/**
- * All known keys.
- */
-const guaclog_known_key known_keys[] = {
-    { 0x0020, "Space" },
-    { 0xFE03, "AltGr" },
-    { 0xFF08, "Backspace" },
-    { 0xFF09, "Tab" },
-    { 0xFF0B, "Clear" },
-    { 0xFF0D, "Return" },
-    { 0xFF13, "Pause" },
-    { 0xFF1B, "Escape" },
-    { 0xFF51, "Left" },
-    { 0xFF52, "Up" },
-    { 0xFF53, "Right" },
-    { 0xFF54, "Down" },
-    { 0xFF55, "Page Up" },
-    { 0xFF56, "Page Down" },
-    { 0xFF63, "Insert" },
-    { 0xFF65, "Undo" },
-    { 0xFF6A, "Help" },
-    { 0xFF80, "Space" },
-    { 0xFF8D, "Enter" },
-    { 0xFFBD, "Equals" },
-    { 0xFFBE, "F1" },
-    { 0xFFBF, "F2" },
-    { 0xFFC0, "F3" },
-    { 0xFFC1, "F4" },
-    { 0xFFC2, "F5" },
-    { 0xFFC3, "F6" },
-    { 0xFFC4, "F7" },
-    { 0xFFC5, "F8" },
-    { 0xFFC6, "F9" },
-    { 0xFFC7, "F10" },
-    { 0xFFC8, "F11" },
-    { 0xFFC9, "F12" },
-    { 0xFFCA, "F13" },
-    { 0xFFCB, "F14" },
-    { 0xFFCC, "F15" },
-    { 0xFFCD, "F16" },
-    { 0xFFCE, "F17" },
-    { 0xFFCF, "F18" },
-    { 0xFFD0, "F19" },
-    { 0xFFD1, "F20" },
-    { 0xFFD2, "F21" },
-    { 0xFFD3, "F22" },
-    { 0xFFD4, "F23" },
-    { 0xFFD5, "F24" },
-    { 0xFFE1, "Shift" },
-    { 0xFFE2, "Shift" },
-    { 0xFFE3, "Ctrl" },
-    { 0xFFE4, "Ctrl" },
-    { 0xFFE5, "Caps" },
-    { 0xFFE7, "Meta" },
-    { 0xFFE8, "Meta" },
-    { 0xFFE9, "Alt" },
-    { 0xFFEA, "Alt" },
-    { 0xFFEB, "Super" },
-    { 0xFFEB, "Win" },
-    { 0xFFEC, "Super" },
-    { 0xFFED, "Hyper" },
-    { 0xFFEE, "Hyper" },
-    { 0xFFFF, "Delete" }
-};
-
-/**
- * Comparator for the standard bsearch() function which compares an integer
- * keysym against the keysym associated with a guaclog_known_key.
- *
- * @param key
- *     The key value being compared against the member. This MUST be the
- *     keysym value, passed through typecasting to an intptr_t (NOT a pointer
- *     to the int itself).
- *
- * @param member
- *     The member within the known_keys array being compared against the given
- *     key.
- *
- * @return
- *     Zero if the given keysym is equal to that of the given member, a
- *     positive value if the given keysym is greater than that of the given
- *     member, or a negative value if the given keysym is less than that of the
- *     given member.
- */
-static int guaclog_known_key_bsearch_compare(const void* key,
-        const void* member) {
-
-    int keysym = (int) ((intptr_t) key);
-    guaclog_known_key* current = (guaclog_known_key*) member;
-
-    /* Compare given keysym to keysym of current member */
-    return keysym  - current->keysym;
-
-}
-
-/**
- * Searches through the known_keys array of known keys for the name of the key
- * having the given keysym. If found, the name of the keysym is copied into the
- * given buffer, which must be at least GUACLOG_MAX_KEY_NAME_LENGTH bytes long.
- *
- * @param key_name
- *     The buffer to copy the key name into, which must be at least
- *     GUACLOG_MAX_KEY_NAME_LENGTH.
- *
- * @param keysym
- *     The X11 keysym of the key whose name should be stored in
- *     key_name.
- *
- * @return
- *     The length of the name, in bytes, excluding null terminator, or zero if
- *     the key could not be found.
- */
-static int guaclog_locate_key_name(char* key_name, int keysym) {
-
-    /* Search through known keys for given keysym */
-    guaclog_known_key* found = bsearch((void*) ((intptr_t) keysym),
-            known_keys, sizeof(known_keys) / sizeof(known_keys[0]),
-            sizeof(known_keys[0]), guaclog_known_key_bsearch_compare);
-
-    /* If found, format name and return length of result */
-    if (found != NULL)
-        return snprintf(key_name, GUACLOG_MAX_KEY_NAME_LENGTH,
-                "[ %s ]", found->name);
-
-    /* Key not found */
-    return 0;
-
-}
-
-/**
- * Produces a name for the key having the given keysym using its corresponding
- * Unicode character. If possible, the name of the keysym is copied into the
- * given buffer, which must be at least GUAC_MAX_KEY_NAME_LENGTH bytes long.
- *
- * @param key_name
- *     The buffer to copy the key name into, which must be at least
- *     GUACLOG_MAX_KEY_NAME_LENGTH.
- *
- * @param keysym
- *     The X11 keysym of the key whose name should be stored in
- *     key_name.
- *
- * @return
- *     The length of the name, in bytes, excluding null terminator, or zero if
- *     a readable name cannot be directly produced via Unicode alone.
- */
-static int guaclog_unicode_key_name(char* key_name, int keysym) {
-
-    int i;
-    int mask, bytes;
-
-    /* Translate only if keysym maps to Unicode */
-    if (keysym < 0x00 || (keysym > 0xFF && (keysym & 0xFFFF0000) != 0x01000000))
-        return 0;
-
-    /* Do not translate whitespace - it will be unreadable */
-    if (keysym == 0x20)
-        return 0;
-
-    int codepoint = keysym & 0xFFFF;
-
-    /* Determine size and initial byte mask */
-    if (codepoint <= 0x007F) {
-        mask  = 0x00;
-        bytes = 1;
-    }
-    else if (codepoint <= 0x7FF) {
-        mask  = 0xC0;
-        bytes = 2;
-    }
-    else if (codepoint <= 0xFFFF) {
-        mask  = 0xE0;
-        bytes = 3;
-    }
-    else if (codepoint <= 0x1FFFFF) {
-        mask  = 0xF0;
-        bytes = 4;
-    }
-
-    /* Otherwise, invalid codepoint */
-    else {
-        *(key_name++) = '?';
-        return 1;
-    }
-
-    /* Offset buffer by size */
-    key_name += bytes;
-
-    /* Add null terminator */
-    *(key_name--) = '\0';
-
-    /* Add trailing bytes, if any */
-    for (i=1; i<bytes; i++) {
-        *(key_name--) = 0x80 | (codepoint & 0x3F);
-        codepoint >>= 6;
-    }
-
-    /* Set initial byte */
-    *key_name = mask | codepoint;
-
-    /* Done */
-    return bytes;
-
-}
-
-int guaclog_key_name(char* key_name, int keysym) {
-
-    int name_length;
-
-    /* Attempt to translate straight into a Unicode character */
-    name_length = guaclog_unicode_key_name(key_name, keysym);
-
-    /* If not Unicode, search for name within list of known keys */
-    if (name_length == 0)
-        name_length = guaclog_locate_key_name(key_name, keysym);
-
-    /* Fallback to using hex keysym as name */
-    if (name_length == 0)
-        name_length = snprintf(key_name, GUACLOG_MAX_KEY_NAME_LENGTH,
-                "0x%X", keysym);
-
-    /* Truncate name if necessary */
-    if (name_length >= GUACLOG_MAX_KEY_NAME_LENGTH) {
-        name_length = GUACLOG_MAX_KEY_NAME_LENGTH - 1;
-        key_name[name_length] = '\0';
-        guaclog_log(GUAC_LOG_DEBUG, "Name for key 0x%X was "
-                "truncated.", keysym);
-    }
-
-    return name_length;
-
-}
-

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5b612b85/src/guaclog/key-name.h
----------------------------------------------------------------------
diff --git a/src/guaclog/key-name.h b/src/guaclog/key-name.h
deleted file mode 100644
index a033b36..0000000
--- a/src/guaclog/key-name.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef GUACLOG_KEY_NAME_H
-#define GUACLOG_KEY_NAME_H
-
-#include "config.h"
-
-/**
- * The maximum size of the name of any key, in bytes.
- */
-#define GUACLOG_MAX_KEY_NAME_LENGTH 64
-
-/**
- * Copies the name of the key having the given keysym into the given buffer,
- * which must be at least GUACLOG_MAX_KEY_NAME_LENGTH bytes long. This function
- * always succeeds, ultimately resorting to using the hex value of the keysym
- * as the name if no other human-readable name is known.
- *
- * @param key_name
- *     The buffer to copy the key name into, which must be at least
- *     GUACLOG_MAX_KEY_NAME_LENGTH.
- *
- * @param keysym
- *     The X11 keysym of the key whose name should be stored in
- *     key_name.
- *
- * @return
- *     The length of the name, in bytes, excluding null terminator.
- */
-int guaclog_key_name(char* key_name, int keysym);
-
-#endif
-

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5b612b85/src/guaclog/keydef.c
----------------------------------------------------------------------
diff --git a/src/guaclog/keydef.c b/src/guaclog/keydef.c
new file mode 100644
index 0000000..9616500
--- /dev/null
+++ b/src/guaclog/keydef.c
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "config.h"
+#include "keydef.h"
+#include "log.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * All known keys.
+ */
+const guaclog_keydef known_keys[] = {
+    { 0xFE03, "AltGr" },
+    { 0xFF08, "Backspace" },
+    { 0xFF09, "Tab", "<Tab>" },
+    { 0xFF0B, "Clear" },
+    { 0xFF0D, "Return", "\n" },
+    { 0xFF13, "Pause" },
+    { 0xFF1B, "Escape" },
+    { 0xFF51, "Left" },
+    { 0xFF52, "Up" },
+    { 0xFF53, "Right" },
+    { 0xFF54, "Down" },
+    { 0xFF55, "Page Up" },
+    { 0xFF56, "Page Down" },
+    { 0xFF63, "Insert" },
+    { 0xFF65, "Undo" },
+    { 0xFF6A, "Help" },
+    { 0xFF80, "Space", " " },
+    { 0xFF8D, "Enter", "\n" },
+    { 0xFFBE, "F1" },
+    { 0xFFBF, "F2" },
+    { 0xFFC0, "F3" },
+    { 0xFFC1, "F4" },
+    { 0xFFC2, "F5" },
+    { 0xFFC3, "F6" },
+    { 0xFFC4, "F7" },
+    { 0xFFC5, "F8" },
+    { 0xFFC6, "F9" },
+    { 0xFFC7, "F10" },
+    { 0xFFC8, "F11" },
+    { 0xFFC9, "F12" },
+    { 0xFFCA, "F13" },
+    { 0xFFCB, "F14" },
+    { 0xFFCC, "F15" },
+    { 0xFFCD, "F16" },
+    { 0xFFCE, "F17" },
+    { 0xFFCF, "F18" },
+    { 0xFFD0, "F19" },
+    { 0xFFD1, "F20" },
+    { 0xFFD2, "F21" },
+    { 0xFFD3, "F22" },
+    { 0xFFD4, "F23" },
+    { 0xFFD5, "F24" },
+    { 0xFFE1, "Shift", "" },
+    { 0xFFE2, "Shift", "" },
+    { 0xFFE3, "Ctrl" },
+    { 0xFFE4, "Ctrl" },
+    { 0xFFE5, "Caps" },
+    { 0xFFE7, "Meta" },
+    { 0xFFE8, "Meta" },
+    { 0xFFE9, "Alt" },
+    { 0xFFEA, "Alt" },
+    { 0xFFEB, "Super" },
+    { 0xFFEB, "Win" },
+    { 0xFFEC, "Super" },
+    { 0xFFED, "Hyper" },
+    { 0xFFEE, "Hyper" },
+    { 0xFFFF, "Delete" }
+};
+
+/**
+ * Comparator for the standard bsearch() function which compares an integer
+ * keysym against the keysym associated with a guaclog_keydef.
+ *
+ * @param key
+ *     The key value being compared against the member. This MUST be the
+ *     keysym value, passed through typecasting to an intptr_t (NOT a pointer
+ *     to the int itself).
+ *
+ * @param member
+ *     The member within the known_keys array being compared against the given
+ *     key.
+ *
+ * @return
+ *     Zero if the given keysym is equal to that of the given member, a
+ *     positive value if the given keysym is greater than that of the given
+ *     member, or a negative value if the given keysym is less than that of the
+ *     given member.
+ */
+static int guaclog_keydef_bsearch_compare(const void* key,
+        const void* member) {
+
+    int keysym = (int) ((intptr_t) key);
+    guaclog_keydef* current = (guaclog_keydef*) member;
+
+    /* Compare given keysym to keysym of current member */
+    return keysym  - current->keysym;
+
+}
+
+/**
+ * Searches through the known_keys array of known keys for the name of the key
+ * having the given keysym, returning a pointer to the static guaclog_keydef
+ * within the array if found.
+ *
+ * @param keysym
+ *     The X11 keysym of the key.
+ *
+ * @return
+ *     A pointer to the static guaclog_keydef associated with the given keysym,
+ *     or NULL if the key could not be found.
+ */
+static guaclog_keydef* guaclog_get_known_key(int keysym) {
+
+    /* Search through known keys for given keysym */
+    return bsearch((void*) ((intptr_t) keysym),
+            known_keys, sizeof(known_keys) / sizeof(known_keys[0]),
+            sizeof(known_keys[0]), guaclog_keydef_bsearch_compare);
+
+}
+
+/**
+ * Returns a statically-allocated guaclog_keydef representing the key
+ * associated with the given keysym, deriving the name and value of the key
+ * using its corresponding Unicode character.
+ *
+ * @param keysym
+ *     The X11 keysym of the key.
+ *
+ * @return
+ *     A statically-allocated guaclog_keydef representing the key associated
+ *     with the given keysym, or NULL if the given keysym has no corresponding
+ *     Unicode character.
+ */
+static guaclog_keydef* guaclog_get_unicode_key(int keysym) {
+
+    static char unicode_keydef_name[8];
+
+    static guaclog_keydef unicode_keydef;
+
+    int i;
+    int mask, bytes;
+
+    /* Translate only if keysym maps to Unicode */
+    if (keysym < 0x00 || (keysym > 0xFF && (keysym & 0xFFFF0000) != 0x01000000))
+        return NULL;
+
+    int codepoint = keysym & 0xFFFF;
+
+    /* Determine size and initial byte mask */
+    if (codepoint <= 0x007F) {
+        mask  = 0x00;
+        bytes = 1;
+    }
+    else if (codepoint <= 0x7FF) {
+        mask  = 0xC0;
+        bytes = 2;
+    }
+    else if (codepoint <= 0xFFFF) {
+        mask  = 0xE0;
+        bytes = 3;
+    }
+    else if (codepoint <= 0x1FFFFF) {
+        mask  = 0xF0;
+        bytes = 4;
+    }
+
+    /* Otherwise, invalid codepoint */
+    else
+        return NULL;
+
+    /* Offset buffer by size */
+    char* key_name = unicode_keydef_name + bytes;
+
+    /* Add null terminator */
+    *(key_name--) = '\0';
+
+    /* Add trailing bytes, if any */
+    for (i=1; i<bytes; i++) {
+        *(key_name--) = 0x80 | (codepoint & 0x3F);
+        codepoint >>= 6;
+    }
+
+    /* Set initial byte */
+    *key_name = mask | codepoint;
+
+    /* Return static key definition */
+    unicode_keydef.keysym = keysym;
+    unicode_keydef.name = unicode_keydef.value = unicode_keydef_name;
+    return &unicode_keydef;
+
+}
+
+/**
+ * Copies the given guaclog_keydef into a newly-allocated guaclog_keydef
+ * structure. The resulting guaclog_keydef must eventually be freed through a
+ * call to guaclog_keydef_free().
+ *
+ * @param keydef
+ *     The guaclog_keydef to copy.
+ *
+ * @return
+ *     A newly-allocated guaclog_keydef structure copied from the given
+ *     guaclog_keydef.
+ */
+static guaclog_keydef* guaclog_copy_key(guaclog_keydef* keydef) {
+
+    guaclog_keydef* copy = malloc(sizeof(guaclog_keydef));
+
+    /* Always copy keysym and name */
+    copy->keysym = keydef->keysym;
+    copy->name = strdup(keydef->name);
+
+    /* Copy value only if defined */
+    if (keydef->value != NULL)
+        copy->value = strdup(keydef->value);
+    else
+        copy->value = NULL;
+
+    return copy;
+
+}
+
+guaclog_keydef* guaclog_keydef_alloc(int keysym) {
+
+    guaclog_keydef* keydef;
+
+    /* Check list of known keys first */
+    keydef = guaclog_get_known_key(keysym);
+    if (keydef != NULL)
+        return guaclog_copy_key(keydef);
+
+    /* Failing that, attempt to translate straight into a Unicode character */
+    keydef = guaclog_get_unicode_key(keysym);
+    if (keydef != NULL)
+        return guaclog_copy_key(keydef);
+
+    /* Key not known */
+    guaclog_log(GUAC_LOG_DEBUG, "Definition not found for key 0x%X.", keysym);
+    return NULL;
+
+}
+
+void guaclog_keydef_free(guaclog_keydef* keydef) {
+
+    /* Ignore NULL keydef */
+    if (keydef == NULL)
+        return;
+
+    free(keydef->name);
+    free(keydef->value);
+    free(keydef);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5b612b85/src/guaclog/keydef.h
----------------------------------------------------------------------
diff --git a/src/guaclog/keydef.h b/src/guaclog/keydef.h
new file mode 100644
index 0000000..d0b2720
--- /dev/null
+++ b/src/guaclog/keydef.h
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef GUACLOG_KEYDEF_H
+#define GUACLOG_KEYDEF_H
+
+#include "config.h"
+
+/**
+ * A mapping of X11 keysym to its corresponding human-readable name.
+ */
+typedef struct guaclog_keydef {
+
+    /**
+     * The X11 keysym of the key.
+     */
+    int keysym;
+
+    /**
+     * A human-readable name for the key.
+     */
+    char* name;
+
+    /**
+     * The value which would be typed in a typical text editor, if any. If the
+     * key is not associated with any typable value, or if the typable value is
+     * not generally useful in an auditing context, this will be NULL.
+     */
+    char* value;
+
+} guaclog_keydef;
+
+/**
+ * Creates a new guaclog_keydef which represents the key having the given
+ * keysym. The resulting guaclog_keydef must eventually be freed through a
+ * call to guaclog_keydef_free().
+ *
+ * @param keysym
+ *     The X11 keysym of the key.
+ *
+ * @return
+ *     A new guaclog_keydef which represents the key having the given keysym,
+ *     or NULL if no such key is known.
+ */
+guaclog_keydef* guaclog_keydef_alloc(int keysym);
+
+/**
+ * Frees all resources associated with the given guaclog_keydef. If the given
+ * guaclog_keydef is NULL, this function has no effect.
+ *
+ * @param keydef
+ *     The guaclog_keydef to free, which may be NULL.
+ */
+void guaclog_keydef_free(guaclog_keydef* keydef);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5b612b85/src/guaclog/state.c
----------------------------------------------------------------------
diff --git a/src/guaclog/state.c b/src/guaclog/state.c
index 616d043..4965985 100644
--- a/src/guaclog/state.c
+++ b/src/guaclog/state.c
@@ -18,7 +18,7 @@
  */
 
 #include "config.h"
-#include "key-name.h"
+#include "keydef.h"
 #include "log.h"
 #include "state.h"
 
@@ -77,10 +77,16 @@ fail_output_fd:
 
 int guaclog_state_free(guaclog_state* state) {
 
+    int i;
+
     /* Ignore NULL state */
     if (state == NULL)
         return 0;
 
+    /* Free keydefs of all tracked keys */
+    for (i = 0; i < state->active_keys; i++)
+        guaclog_keydef_free(state->key_states[i].keydef);
+
     /* Close output file */
     fclose(state->output);
 
@@ -100,8 +106,11 @@ int guaclog_state_free(guaclog_state* state) {
  * @param state
  *     The Guacamole input log interpreter state being updated.
  *
- * @param keysym
- *     The X11 keysym of the key being pressed or released.
+ * @param keydef
+ *     The guaclog_keydef of the key being pressed or released. This
+ *     guaclog_keydef will automatically be freed along with the guaclog_state
+ *     if the key state was successfully added, and must be manually freed
+ *     otherwise.
  *
  * @param pressed
  *     true if the key is being pressed, false if the key is being released.
@@ -109,14 +118,17 @@ int guaclog_state_free(guaclog_state* state) {
  * @return
  *     Zero if the key state was successfully added, non-zero otherwise.
  */
-static int guaclog_state_add_key(guaclog_state* state, int keysym, bool pressed) {
+static int guaclog_state_add_key(guaclog_state* state, guaclog_keydef* keydef,
+        bool pressed) {
 
     int i;
 
     /* Update existing key, if already tracked */
     for (i = 0; i < state->active_keys; i++) {
         guaclog_key_state* key = &state->key_states[i];
-        if (key->keysym == keysym) {
+        if (key->keydef->keysym == keydef->keysym) {
+            guaclog_keydef_free(key->keydef);
+            key->keydef = keydef;
             key->pressed = pressed;
             return 0;
         }
@@ -125,13 +137,13 @@ static int guaclog_state_add_key(guaclog_state* state, int keysym, bool pressed)
     /* If not already tracked, we need space to add it */
     if (state->active_keys == GUACLOG_MAX_KEYS) {
         guaclog_log(GUAC_LOG_WARNING, "Unable to log key 0x%X: Too many "
-                "active keys.", keysym);
+                "active keys.", keydef->keysym);
         return 1;
     }
 
     /* Add key to state */
     guaclog_key_state* key = &state->key_states[state->active_keys++];
-    key->keysym = keysym;
+    key->keydef = keydef;
     key->pressed = pressed;
     return 0;
 
@@ -152,11 +164,16 @@ static void guaclog_state_trim_keys(guaclog_state* state) {
 
     /* Reset active_keys to contain only up to the last pressed key */
     for (i = state->active_keys - 1; i >= 0; i--) {
+
         guaclog_key_state* key = &state->key_states[i];
         if (key->pressed) {
             state->active_keys = i + 1;
             return;
         }
+
+        /* Free all trimmed states */
+        guaclog_keydef_free(key->keydef);
+
     }
 
     /* No keys are active */
@@ -164,44 +181,76 @@ static void guaclog_state_trim_keys(guaclog_state* state) {
 
 }
 
+/**
+ * Returns whether the current tracked key state represents an in-progress
+ * keyboard shortcut.
+ *
+ * @param state
+ *     The Guacamole input log interpreter state to test.
+ *
+ * @return
+ *     true if the given state represents an in-progress keyboard shortcut,
+ *     false otherwise.
+ */
+static bool guaclog_state_is_shortcut(guaclog_state* state) {
+
+    int i;
+
+    /* We are in a shortcut if at least one key is non-printable */
+    for (i = 0; i < state->active_keys; i++) {
+        guaclog_key_state* key = &state->key_states[i];
+        if (key->keydef->value == NULL)
+            return true;
+    }
+
+    /* All keys are printable - no shortcut */
+    return false;
+
+}
+
 int guaclog_state_update_key(guaclog_state* state, int keysym, bool pressed) {
 
     int i;
 
-    /* Update tracked keysysm state */
-    guaclog_state_add_key(state, keysym, pressed);
-    guaclog_state_trim_keys(state);
+    /* Determine nature of key */
+    guaclog_keydef* keydef = guaclog_keydef_alloc(keysym);
+    if (keydef == NULL)
+        return 0;
 
-    /* Output new log entries only when keys are pressed */
-    if (pressed) {   
+    /* Update tracked key state */
+    if (guaclog_state_add_key(state, keydef, pressed))
+        guaclog_keydef_free(keydef);
+    else
+        guaclog_state_trim_keys(state);
 
-        /* Compose log entry by inspecting the state of each tracked key */
-        for (i = 0; i < state->active_keys; i++) {
+    /* Output key states only for printable keys */
+    if (pressed && keydef->value != NULL) {
 
-            guaclog_key_state* key = &state->key_states[i];
+        if (guaclog_state_is_shortcut(state)) {
 
-            /* Translate keysym into human-readable name */
-            char key_name[GUACLOG_MAX_KEY_NAME_LENGTH];
-            int name_length = guaclog_key_name(key_name, key->keysym);
+            fprintf(state->output, "<");
 
-            /* If not the final key, omit the name (it was printed earlier) */
-            if (i < state->active_keys - 1) {
-                memset(key_name, ' ', name_length);
-                if (key->pressed)
-                    key_name[name_length / 2] = '*';
-            }
+            /* Compose log entry by inspecting the state of each tracked key */
+            for (i = 0; i < state->active_keys; i++) {
 
-            /* Separate each key by a single space */
-            if (i != 0)
-                fprintf(state->output, " ");
+                /* Translate keysym into human-readable name */
+                guaclog_key_state* key = &state->key_states[i];
+
+                /* Print name of key */
+                if (i == 0)
+                    fprintf(state->output, "%s", key->keydef->name);
+                else
+                    fprintf(state->output, "+%s", key->keydef->name);
+
+            }
 
-            /* Print name of key */
-            fprintf(state->output, "%s", key_name);
+            fprintf(state->output, ">");
 
         }
 
-        /* Terminate log entry with newline */
-        fprintf(state->output, "\n");
+        /* Print the key itself */
+        else
+            fprintf(state->output, "%s", keydef->value);
 
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5b612b85/src/guaclog/state.h
----------------------------------------------------------------------
diff --git a/src/guaclog/state.h b/src/guaclog/state.h
index 0dd2f2f..b476dde 100644
--- a/src/guaclog/state.h
+++ b/src/guaclog/state.h
@@ -21,6 +21,7 @@
 #define GUACLOG_STATE_H
 
 #include "config.h"
+#include "keydef.h"
 
 #include <stdbool.h>
 #include <stdio.h>
@@ -37,9 +38,9 @@
 typedef struct guaclog_key_state {
 
     /**
-     * The X11 keysym of the key.
+     * The definition of the key.
      */
-    int keysym;
+    guaclog_keydef* keydef;
 
     /**
      * Whether the key is currently pressed (true) or released (false).