GUACAMOLE-313: Refactor guaclog to produce simpler, greppable output.
This commit is contained in:
parent
86b09c8cf7
commit
5b612b856a
@ -28,7 +28,7 @@ noinst_HEADERS = \
|
|||||||
guaclog.h \
|
guaclog.h \
|
||||||
instructions.h \
|
instructions.h \
|
||||||
interpret.h \
|
interpret.h \
|
||||||
key-name.h \
|
keydef.h \
|
||||||
log.h \
|
log.h \
|
||||||
state.h
|
state.h
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ guaclog_SOURCES = \
|
|||||||
instructions.c \
|
instructions.c \
|
||||||
instruction-key.c \
|
instruction-key.c \
|
||||||
interpret.c \
|
interpret.c \
|
||||||
key-name.c \
|
keydef.c \
|
||||||
log.c \
|
log.c \
|
||||||
state.c
|
state.c
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
|
@ -18,39 +18,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "key-name.h"
|
#include "keydef.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.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.
|
* All known keys.
|
||||||
*/
|
*/
|
||||||
const guaclog_known_key known_keys[] = {
|
const guaclog_keydef known_keys[] = {
|
||||||
{ 0x0020, "Space" },
|
|
||||||
{ 0xFE03, "AltGr" },
|
{ 0xFE03, "AltGr" },
|
||||||
{ 0xFF08, "Backspace" },
|
{ 0xFF08, "Backspace" },
|
||||||
{ 0xFF09, "Tab" },
|
{ 0xFF09, "Tab", "<Tab>" },
|
||||||
{ 0xFF0B, "Clear" },
|
{ 0xFF0B, "Clear" },
|
||||||
{ 0xFF0D, "Return" },
|
{ 0xFF0D, "Return", "\n" },
|
||||||
{ 0xFF13, "Pause" },
|
{ 0xFF13, "Pause" },
|
||||||
{ 0xFF1B, "Escape" },
|
{ 0xFF1B, "Escape" },
|
||||||
{ 0xFF51, "Left" },
|
{ 0xFF51, "Left" },
|
||||||
@ -62,9 +46,8 @@ const guaclog_known_key known_keys[] = {
|
|||||||
{ 0xFF63, "Insert" },
|
{ 0xFF63, "Insert" },
|
||||||
{ 0xFF65, "Undo" },
|
{ 0xFF65, "Undo" },
|
||||||
{ 0xFF6A, "Help" },
|
{ 0xFF6A, "Help" },
|
||||||
{ 0xFF80, "Space" },
|
{ 0xFF80, "Space", " " },
|
||||||
{ 0xFF8D, "Enter" },
|
{ 0xFF8D, "Enter", "\n" },
|
||||||
{ 0xFFBD, "Equals" },
|
|
||||||
{ 0xFFBE, "F1" },
|
{ 0xFFBE, "F1" },
|
||||||
{ 0xFFBF, "F2" },
|
{ 0xFFBF, "F2" },
|
||||||
{ 0xFFC0, "F3" },
|
{ 0xFFC0, "F3" },
|
||||||
@ -89,8 +72,8 @@ const guaclog_known_key known_keys[] = {
|
|||||||
{ 0xFFD3, "F22" },
|
{ 0xFFD3, "F22" },
|
||||||
{ 0xFFD4, "F23" },
|
{ 0xFFD4, "F23" },
|
||||||
{ 0xFFD5, "F24" },
|
{ 0xFFD5, "F24" },
|
||||||
{ 0xFFE1, "Shift" },
|
{ 0xFFE1, "Shift", "" },
|
||||||
{ 0xFFE2, "Shift" },
|
{ 0xFFE2, "Shift", "" },
|
||||||
{ 0xFFE3, "Ctrl" },
|
{ 0xFFE3, "Ctrl" },
|
||||||
{ 0xFFE4, "Ctrl" },
|
{ 0xFFE4, "Ctrl" },
|
||||||
{ 0xFFE5, "Caps" },
|
{ 0xFFE5, "Caps" },
|
||||||
@ -108,7 +91,7 @@ const guaclog_known_key known_keys[] = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparator for the standard bsearch() function which compares an integer
|
* Comparator for the standard bsearch() function which compares an integer
|
||||||
* keysym against the keysym associated with a guaclog_known_key.
|
* keysym against the keysym associated with a guaclog_keydef.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* The key value being compared against the member. This MUST be the
|
* The key value being compared against the member. This MUST be the
|
||||||
@ -125,11 +108,11 @@ const guaclog_known_key known_keys[] = {
|
|||||||
* member, or a negative value if the given keysym is less than that of the
|
* member, or a negative value if the given keysym is less than that of the
|
||||||
* given member.
|
* given member.
|
||||||
*/
|
*/
|
||||||
static int guaclog_known_key_bsearch_compare(const void* key,
|
static int guaclog_keydef_bsearch_compare(const void* key,
|
||||||
const void* member) {
|
const void* member) {
|
||||||
|
|
||||||
int keysym = (int) ((intptr_t) key);
|
int keysym = (int) ((intptr_t) key);
|
||||||
guaclog_known_key* current = (guaclog_known_key*) member;
|
guaclog_keydef* current = (guaclog_keydef*) member;
|
||||||
|
|
||||||
/* Compare given keysym to keysym of current member */
|
/* Compare given keysym to keysym of current member */
|
||||||
return keysym - current->keysym;
|
return keysym - current->keysym;
|
||||||
@ -138,67 +121,50 @@ static int guaclog_known_key_bsearch_compare(const void* key,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches through the known_keys array of known keys for the name of the key
|
* 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
|
* having the given keysym, returning a pointer to the static guaclog_keydef
|
||||||
* given buffer, which must be at least GUACLOG_MAX_KEY_NAME_LENGTH bytes long.
|
* within the array if found.
|
||||||
*
|
|
||||||
* @param key_name
|
|
||||||
* The buffer to copy the key name into, which must be at least
|
|
||||||
* GUACLOG_MAX_KEY_NAME_LENGTH.
|
|
||||||
*
|
*
|
||||||
* @param keysym
|
* @param keysym
|
||||||
* The X11 keysym of the key whose name should be stored in
|
* The X11 keysym of the key.
|
||||||
* key_name.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The length of the name, in bytes, excluding null terminator, or zero if
|
* A pointer to the static guaclog_keydef associated with the given keysym,
|
||||||
* the key could not be found.
|
* or NULL if the key could not be found.
|
||||||
*/
|
*/
|
||||||
static int guaclog_locate_key_name(char* key_name, int keysym) {
|
static guaclog_keydef* guaclog_get_known_key(int keysym) {
|
||||||
|
|
||||||
/* Search through known keys for given keysym */
|
/* Search through known keys for given keysym */
|
||||||
guaclog_known_key* found = bsearch((void*) ((intptr_t) keysym),
|
return bsearch((void*) ((intptr_t) keysym),
|
||||||
known_keys, sizeof(known_keys) / sizeof(known_keys[0]),
|
known_keys, sizeof(known_keys) / sizeof(known_keys[0]),
|
||||||
sizeof(known_keys[0]), guaclog_known_key_bsearch_compare);
|
sizeof(known_keys[0]), guaclog_keydef_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
|
* Returns a statically-allocated guaclog_keydef representing the key
|
||||||
* Unicode character. If possible, the name of the keysym is copied into the
|
* associated with the given keysym, deriving the name and value of the key
|
||||||
* given buffer, which must be at least GUAC_MAX_KEY_NAME_LENGTH bytes long.
|
* using its corresponding Unicode character.
|
||||||
*
|
|
||||||
* @param key_name
|
|
||||||
* The buffer to copy the key name into, which must be at least
|
|
||||||
* GUACLOG_MAX_KEY_NAME_LENGTH.
|
|
||||||
*
|
*
|
||||||
* @param keysym
|
* @param keysym
|
||||||
* The X11 keysym of the key whose name should be stored in
|
* The X11 keysym of the key.
|
||||||
* key_name.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The length of the name, in bytes, excluding null terminator, or zero if
|
* A statically-allocated guaclog_keydef representing the key associated
|
||||||
* a readable name cannot be directly produced via Unicode alone.
|
* with the given keysym, or NULL if the given keysym has no corresponding
|
||||||
|
* Unicode character.
|
||||||
*/
|
*/
|
||||||
static int guaclog_unicode_key_name(char* key_name, int keysym) {
|
static guaclog_keydef* guaclog_get_unicode_key(int keysym) {
|
||||||
|
|
||||||
|
static char unicode_keydef_name[8];
|
||||||
|
|
||||||
|
static guaclog_keydef unicode_keydef;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int mask, bytes;
|
int mask, bytes;
|
||||||
|
|
||||||
/* Translate only if keysym maps to Unicode */
|
/* Translate only if keysym maps to Unicode */
|
||||||
if (keysym < 0x00 || (keysym > 0xFF && (keysym & 0xFFFF0000) != 0x01000000))
|
if (keysym < 0x00 || (keysym > 0xFF && (keysym & 0xFFFF0000) != 0x01000000))
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
/* Do not translate whitespace - it will be unreadable */
|
|
||||||
if (keysym == 0x20)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int codepoint = keysym & 0xFFFF;
|
int codepoint = keysym & 0xFFFF;
|
||||||
|
|
||||||
@ -221,13 +187,11 @@ static int guaclog_unicode_key_name(char* key_name, int keysym) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, invalid codepoint */
|
/* Otherwise, invalid codepoint */
|
||||||
else {
|
else
|
||||||
*(key_name++) = '?';
|
return NULL;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Offset buffer by size */
|
/* Offset buffer by size */
|
||||||
key_name += bytes;
|
char* key_name = unicode_keydef_name + bytes;
|
||||||
|
|
||||||
/* Add null terminator */
|
/* Add null terminator */
|
||||||
*(key_name--) = '\0';
|
*(key_name--) = '\0';
|
||||||
@ -241,36 +205,72 @@ static int guaclog_unicode_key_name(char* key_name, int keysym) {
|
|||||||
/* Set initial byte */
|
/* Set initial byte */
|
||||||
*key_name = mask | codepoint;
|
*key_name = mask | codepoint;
|
||||||
|
|
||||||
/* Done */
|
/* Return static key definition */
|
||||||
return bytes;
|
unicode_keydef.keysym = keysym;
|
||||||
|
unicode_keydef.name = unicode_keydef.value = unicode_keydef_name;
|
||||||
|
return &unicode_keydef;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int guaclog_key_name(char* key_name, int keysym) {
|
/**
|
||||||
|
* 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) {
|
||||||
|
|
||||||
int name_length;
|
guaclog_keydef* copy = malloc(sizeof(guaclog_keydef));
|
||||||
|
|
||||||
/* Attempt to translate straight into a Unicode character */
|
/* Always copy keysym and name */
|
||||||
name_length = guaclog_unicode_key_name(key_name, keysym);
|
copy->keysym = keydef->keysym;
|
||||||
|
copy->name = strdup(keydef->name);
|
||||||
|
|
||||||
/* If not Unicode, search for name within list of known keys */
|
/* Copy value only if defined */
|
||||||
if (name_length == 0)
|
if (keydef->value != NULL)
|
||||||
name_length = guaclog_locate_key_name(key_name, keysym);
|
copy->value = strdup(keydef->value);
|
||||||
|
else
|
||||||
|
copy->value = NULL;
|
||||||
|
|
||||||
/* Fallback to using hex keysym as name */
|
return copy;
|
||||||
if (name_length == 0)
|
|
||||||
name_length = snprintf(key_name, GUACLOG_MAX_KEY_NAME_LENGTH,
|
}
|
||||||
"0x%X", keysym);
|
|
||||||
|
guaclog_keydef* guaclog_keydef_alloc(int keysym) {
|
||||||
/* Truncate name if necessary */
|
|
||||||
if (name_length >= GUACLOG_MAX_KEY_NAME_LENGTH) {
|
guaclog_keydef* keydef;
|
||||||
name_length = GUACLOG_MAX_KEY_NAME_LENGTH - 1;
|
|
||||||
key_name[name_length] = '\0';
|
/* Check list of known keys first */
|
||||||
guaclog_log(GUAC_LOG_DEBUG, "Name for key 0x%X was "
|
keydef = guaclog_get_known_key(keysym);
|
||||||
"truncated.", keysym);
|
if (keydef != NULL)
|
||||||
}
|
return guaclog_copy_key(keydef);
|
||||||
|
|
||||||
return name_length;
|
/* 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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
73
src/guaclog/keydef.h
Normal file
73
src/guaclog/keydef.h
Normal file
@ -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
|
||||||
|
|
@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "key-name.h"
|
#include "keydef.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
@ -77,10 +77,16 @@ fail_output_fd:
|
|||||||
|
|
||||||
int guaclog_state_free(guaclog_state* state) {
|
int guaclog_state_free(guaclog_state* state) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Ignore NULL state */
|
/* Ignore NULL state */
|
||||||
if (state == NULL)
|
if (state == NULL)
|
||||||
return 0;
|
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 */
|
/* Close output file */
|
||||||
fclose(state->output);
|
fclose(state->output);
|
||||||
|
|
||||||
@ -100,8 +106,11 @@ int guaclog_state_free(guaclog_state* state) {
|
|||||||
* @param state
|
* @param state
|
||||||
* The Guacamole input log interpreter state being updated.
|
* The Guacamole input log interpreter state being updated.
|
||||||
*
|
*
|
||||||
* @param keysym
|
* @param keydef
|
||||||
* The X11 keysym of the key being pressed or released.
|
* 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
|
* @param pressed
|
||||||
* true if the key is being pressed, false if the key is being released.
|
* 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
|
* @return
|
||||||
* Zero if the key state was successfully added, non-zero otherwise.
|
* 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;
|
int i;
|
||||||
|
|
||||||
/* Update existing key, if already tracked */
|
/* Update existing key, if already tracked */
|
||||||
for (i = 0; i < state->active_keys; i++) {
|
for (i = 0; i < state->active_keys; i++) {
|
||||||
guaclog_key_state* key = &state->key_states[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;
|
key->pressed = pressed;
|
||||||
return 0;
|
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 not already tracked, we need space to add it */
|
||||||
if (state->active_keys == GUACLOG_MAX_KEYS) {
|
if (state->active_keys == GUACLOG_MAX_KEYS) {
|
||||||
guaclog_log(GUAC_LOG_WARNING, "Unable to log key 0x%X: Too many "
|
guaclog_log(GUAC_LOG_WARNING, "Unable to log key 0x%X: Too many "
|
||||||
"active keys.", keysym);
|
"active keys.", keydef->keysym);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add key to state */
|
/* Add key to state */
|
||||||
guaclog_key_state* key = &state->key_states[state->active_keys++];
|
guaclog_key_state* key = &state->key_states[state->active_keys++];
|
||||||
key->keysym = keysym;
|
key->keydef = keydef;
|
||||||
key->pressed = pressed;
|
key->pressed = pressed;
|
||||||
return 0;
|
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 */
|
/* Reset active_keys to contain only up to the last pressed key */
|
||||||
for (i = state->active_keys - 1; i >= 0; i--) {
|
for (i = state->active_keys - 1; i >= 0; i--) {
|
||||||
|
|
||||||
guaclog_key_state* key = &state->key_states[i];
|
guaclog_key_state* key = &state->key_states[i];
|
||||||
if (key->pressed) {
|
if (key->pressed) {
|
||||||
state->active_keys = i + 1;
|
state->active_keys = i + 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free all trimmed states */
|
||||||
|
guaclog_keydef_free(key->keydef);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No keys are active */
|
/* 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 guaclog_state_update_key(guaclog_state* state, int keysym, bool pressed) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Update tracked keysysm state */
|
/* Determine nature of key */
|
||||||
guaclog_state_add_key(state, keysym, pressed);
|
guaclog_keydef* keydef = guaclog_keydef_alloc(keysym);
|
||||||
guaclog_state_trim_keys(state);
|
if (keydef == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Output new log entries only when keys are pressed */
|
/* Update tracked key state */
|
||||||
if (pressed) {
|
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 */
|
/* Output key states only for printable keys */
|
||||||
for (i = 0; i < state->active_keys; i++) {
|
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 */
|
fprintf(state->output, "<");
|
||||||
char key_name[GUACLOG_MAX_KEY_NAME_LENGTH];
|
|
||||||
int name_length = guaclog_key_name(key_name, key->keysym);
|
/* Compose log entry by inspecting the state of each tracked key */
|
||||||
|
for (i = 0; i < state->active_keys; i++) {
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
/* 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] = '*';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Separate each key by a single space */
|
fprintf(state->output, ">");
|
||||||
if (i != 0)
|
|
||||||
fprintf(state->output, " ");
|
|
||||||
|
|
||||||
/* Print name of key */
|
|
||||||
fprintf(state->output, "%s", key_name);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terminate log entry with newline */
|
/* Print the key itself */
|
||||||
fprintf(state->output, "\n");
|
else
|
||||||
|
fprintf(state->output, "%s", keydef->value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define GUACLOG_STATE_H
|
#define GUACLOG_STATE_H
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "keydef.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -37,9 +38,9 @@
|
|||||||
typedef struct guaclog_key_state {
|
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).
|
* Whether the key is currently pressed (true) or released (false).
|
||||||
|
Loading…
Reference in New Issue
Block a user