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 \
|
||||
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
|
||||
|
||||
|
@ -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 "key-name.h"
|
||||
#include "keydef.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdbool.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;
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* All known keys.
|
||||
*/
|
||||
const guaclog_known_key known_keys[] = {
|
||||
{ 0x0020, "Space" },
|
||||
const guaclog_keydef known_keys[] = {
|
||||
{ 0xFE03, "AltGr" },
|
||||
{ 0xFF08, "Backspace" },
|
||||
{ 0xFF09, "Tab" },
|
||||
{ 0xFF09, "Tab", "<Tab>" },
|
||||
{ 0xFF0B, "Clear" },
|
||||
{ 0xFF0D, "Return" },
|
||||
{ 0xFF0D, "Return", "\n" },
|
||||
{ 0xFF13, "Pause" },
|
||||
{ 0xFF1B, "Escape" },
|
||||
{ 0xFF51, "Left" },
|
||||
@ -62,9 +46,8 @@ const guaclog_known_key known_keys[] = {
|
||||
{ 0xFF63, "Insert" },
|
||||
{ 0xFF65, "Undo" },
|
||||
{ 0xFF6A, "Help" },
|
||||
{ 0xFF80, "Space" },
|
||||
{ 0xFF8D, "Enter" },
|
||||
{ 0xFFBD, "Equals" },
|
||||
{ 0xFF80, "Space", " " },
|
||||
{ 0xFF8D, "Enter", "\n" },
|
||||
{ 0xFFBE, "F1" },
|
||||
{ 0xFFBF, "F2" },
|
||||
{ 0xFFC0, "F3" },
|
||||
@ -89,8 +72,8 @@ const guaclog_known_key known_keys[] = {
|
||||
{ 0xFFD3, "F22" },
|
||||
{ 0xFFD4, "F23" },
|
||||
{ 0xFFD5, "F24" },
|
||||
{ 0xFFE1, "Shift" },
|
||||
{ 0xFFE2, "Shift" },
|
||||
{ 0xFFE1, "Shift", "" },
|
||||
{ 0xFFE2, "Shift", "" },
|
||||
{ 0xFFE3, "Ctrl" },
|
||||
{ 0xFFE4, "Ctrl" },
|
||||
{ 0xFFE5, "Caps" },
|
||||
@ -108,7 +91,7 @@ const guaclog_known_key known_keys[] = {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* given member.
|
||||
*/
|
||||
static int guaclog_known_key_bsearch_compare(const void* key,
|
||||
static int guaclog_keydef_bsearch_compare(const void* key,
|
||||
const void* member) {
|
||||
|
||||
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 */
|
||||
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
|
||||
* 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.
|
||||
* 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 whose name should be stored in
|
||||
* key_name.
|
||||
* The X11 keysym of the key.
|
||||
*
|
||||
* @return
|
||||
* The length of the name, in bytes, excluding null terminator, or zero if
|
||||
* the key could not be found.
|
||||
* A pointer to the static guaclog_keydef associated with the given keysym,
|
||||
* 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 */
|
||||
guaclog_known_key* found = bsearch((void*) ((intptr_t) keysym),
|
||||
return 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;
|
||||
sizeof(known_keys[0]), guaclog_keydef_bsearch_compare);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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 whose name should be stored in
|
||||
* key_name.
|
||||
* The X11 keysym of the key.
|
||||
*
|
||||
* @return
|
||||
* The length of the name, in bytes, excluding null terminator, or zero if
|
||||
* a readable name cannot be directly produced via Unicode alone.
|
||||
* 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 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 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;
|
||||
return NULL;
|
||||
|
||||
int codepoint = keysym & 0xFFFF;
|
||||
|
||||
@ -221,13 +187,11 @@ static int guaclog_unicode_key_name(char* key_name, int keysym) {
|
||||
}
|
||||
|
||||
/* Otherwise, invalid codepoint */
|
||||
else {
|
||||
*(key_name++) = '?';
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
/* Offset buffer by size */
|
||||
key_name += bytes;
|
||||
char* key_name = unicode_keydef_name + bytes;
|
||||
|
||||
/* Add null terminator */
|
||||
*(key_name--) = '\0';
|
||||
@ -241,36 +205,72 @@ static int guaclog_unicode_key_name(char* key_name, int keysym) {
|
||||
/* Set initial byte */
|
||||
*key_name = mask | codepoint;
|
||||
|
||||
/* Done */
|
||||
return bytes;
|
||||
/* Return static key definition */
|
||||
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 */
|
||||
name_length = guaclog_unicode_key_name(key_name, keysym);
|
||||
/* Always copy keysym and name */
|
||||
copy->keysym = keydef->keysym;
|
||||
copy->name = strdup(keydef->name);
|
||||
|
||||
/* If not Unicode, search for name within list of known keys */
|
||||
if (name_length == 0)
|
||||
name_length = guaclog_locate_key_name(key_name, keysym);
|
||||
/* Copy value only if defined */
|
||||
if (keydef->value != NULL)
|
||||
copy->value = strdup(keydef->value);
|
||||
else
|
||||
copy->value = NULL;
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
}
|
||||
|
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 "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, "<");
|
||||
|
||||
/* 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 */
|
||||
if (i != 0)
|
||||
fprintf(state->output, " ");
|
||||
|
||||
/* 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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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).
|
||||
|
Loading…
Reference in New Issue
Block a user