diff --git a/src/guaclog/state.c b/src/guaclog/state.c index 6167bd30..cc6f7637 100644 --- a/src/guaclog/state.c +++ b/src/guaclog/state.c @@ -57,6 +57,9 @@ guaclog_state* guaclog_state_alloc(const char* path) { /* Associate state with output file */ state->output = output; + /* No keys are initially tracked */ + state->active_keys = 0; + return state; /* Free all allocated data in case of failure */ @@ -85,11 +88,108 @@ int guaclog_state_free(guaclog_state* state) { } +/** + * Adds the given key state to the array of tracked keys. If the key is already + * being tracked, its corresponding entry within the array of tracked keys is + * updated, and the number of tracked keys remains the same. If the key is not + * already being tracked, it is added to the end of the array of tracked keys + * providing there is space available, and the number of tracked keys is + * updated. Failures to add keys will be automatically logged. + * + * @param state + * The Guacamole input log interpreter state being updated. + * + * @param keysym + * The X11 keysym of the key being pressed or released. + * + * @param pressed + * true if the key is being pressed, false if the key is being released. + * + * @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) { + + 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) { + key->pressed = pressed; + return 0; + } + } + + /* 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); + return 1; + } + + /* Add key to state */ + guaclog_key_state* key = &state->key_states[state->active_keys++]; + key->keysym = keysym; + key->pressed = pressed; + return 0; + +} + +/** + * Removes released keys from the end of the array of tracked keys, such that + * the last key in the array is a pressed key. This function should be invoked + * after changes have been made to the interpreter state, to ensure that the + * array of tracked keys does not grow longer than necessary. + * + * @param state + * The Guacamole input log interpreter state to trim. + */ +static void guaclog_state_trim_keys(guaclog_state* state) { + + int i; + + /* 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; + } + } + + /* No keys are active */ + state->active_keys = 0; + +} + int guaclog_state_update_key(guaclog_state* state, int keysym, bool pressed) { - /* STUB */ - fprintf(state->output, "STUB: keysym=0x%X, pressed=%s\n", - keysym, pressed ? "true" : "false"); + int i; + + /* Update tracked keysysm state */ + guaclog_state_add_key(state, keysym, pressed); + guaclog_state_trim_keys(state); + + /* Output new log entries only when keys are pressed */ + if (pressed) { + + /* STUB: Output raw hex log entry */ + for (i = 0; i < state->active_keys; i++) { + + if (i != 0) + fprintf(state->output, " "); + + guaclog_key_state* key = &state->key_states[i]; + fprintf(state->output, "0x%X:%s", key->keysym, + key->pressed ? "*" : " "); + + } + + /* Terminate log entry with newline */ + fprintf(state->output, "\n"); + + } return 0; diff --git a/src/guaclog/state.h b/src/guaclog/state.h index 5891cb56..0dd2f2f9 100644 --- a/src/guaclog/state.h +++ b/src/guaclog/state.h @@ -25,6 +25,29 @@ #include #include +/** + * The maximum number of keys which may be tracked at any one time before + * newly-pressed keys are ignored. + */ +#define GUACLOG_MAX_KEYS 256 + +/** + * The current state of a single key. + */ +typedef struct guaclog_key_state { + + /** + * The X11 keysym of the key. + */ + int keysym; + + /** + * Whether the key is currently pressed (true) or released (false). + */ + bool pressed; + +} guaclog_key_state; + /** * The current state of the Guacamole input log interpreter. */ @@ -35,6 +58,18 @@ typedef struct guaclog_state { */ FILE* output; + /** + * The number of keys currently being tracked within the key_states array. + */ + int active_keys; + + /** + * Array of all keys currently being tracked. A key is added to the array + * when it is pressed for the first time. Released keys at the end of the + * array are automatically removed from tracking. + */ + guaclog_key_state key_states[GUACLOG_MAX_KEYS]; + } guaclog_state; /**