aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/hashtable.h139
-rw-r--r--src/hotkey.c83
-rw-r--r--src/hotkey.h17
-rw-r--r--src/parse.c20
-rw-r--r--src/parse.h3
-rw-r--r--src/skhd.c27
6 files changed, 213 insertions, 76 deletions
diff --git a/src/hashtable.h b/src/hashtable.h
new file mode 100644
index 0000000..9dfae70
--- /dev/null
+++ b/src/hashtable.h
@@ -0,0 +1,139 @@
+#ifndef HASHTABLE_H
+#define HASHTABLE_H
+
+typedef unsigned long (*table_hash_func)(void *key);
+typedef int (*table_compare_func)(void *key_a, void *key_b);
+
+struct bucket
+{
+ void *key;
+ void *value;
+ struct bucket *next;
+};
+struct table
+{
+ int count;
+ int capacity;
+ int key_capacity;
+ table_hash_func hash;
+ table_compare_func compare;
+ void **keys;
+ struct bucket **buckets;
+};
+
+void table_init(struct table *table, int capacity, table_hash_func hash, table_compare_func compare);
+void table_free(struct table *table);
+
+void *table_find(struct table *table, void *key);
+void table_add(struct table *table, void *key, void *value);
+void *table_remove(struct table *table, void *key);
+void *table_reset(struct table *table, int *count);
+
+#endif
+
+#ifdef HASHTABLE_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h>
+
+static struct bucket *
+table_new_bucket(void *key, void *value)
+{
+ struct bucket *bucket = malloc(sizeof(struct bucket));
+ bucket->key = key;
+ bucket->value = value;
+ bucket->next = NULL;
+ return bucket;
+}
+
+static struct bucket **
+table_get_bucket(struct table *table, void *key)
+{
+ struct bucket **bucket = table->buckets + (table->hash(key) % table->capacity);
+ while(*bucket) {
+ if(table->compare((*bucket)->key, key)) {
+ break;
+ }
+ bucket = &(*bucket)->next;
+ }
+ return bucket;
+}
+
+void table_init(struct table *table, int capacity, table_hash_func hash, table_compare_func compare)
+{
+ table->count = 0;
+ table->capacity = capacity;
+ table->hash = hash;
+ table->compare = compare;
+ table->key_capacity = capacity * 2;
+ table->keys = malloc(sizeof(void *) * table->key_capacity);
+ table->buckets = malloc(sizeof(struct bucket *) * capacity);
+ memset(table->buckets, 0, sizeof(struct bucket *) * capacity);
+}
+
+void table_free(struct table *table)
+{
+ for(int i = 0; i < table->capacity; ++i) {
+ struct bucket *next, *bucket = table->buckets[i];
+ while(bucket) {
+ next = bucket->next;
+ free(bucket);
+ bucket = next;
+ }
+ }
+ free(table->buckets);
+}
+
+void *table_find(struct table *table, void *key)
+{
+ struct bucket *bucket = *table_get_bucket(table, key);
+ return bucket ? bucket->value : NULL;
+}
+
+void table_add(struct table *table, void *key, void *value)
+{
+ struct bucket **bucket = table_get_bucket(table, key);
+ if(*bucket) {
+ (*bucket)->value = value;
+ } else {
+ *bucket = table_new_bucket(key, value);
+ if(table->count == table->key_capacity) {
+ table->key_capacity *= 2;
+ table->keys = realloc(table->keys, sizeof(void *) * table->key_capacity);
+ }
+ table->keys[table->count++] = key;
+ }
+}
+
+void *table_remove(struct table *table, void *key)
+{
+ void *result = NULL;
+ struct bucket *next, **bucket = table_get_bucket(table, key);
+ if(*bucket) {
+ result = (*bucket)->value;
+ next = (*bucket)->next;
+ free(*bucket);
+ *bucket = next;
+ --table->count;
+ }
+ return result;
+}
+
+void *table_reset(struct table *table, int *count)
+{
+ void **values;
+ int index;
+ int item;
+
+ *count = table->count;
+ values = malloc(sizeof(void *) * table->count);
+ item = 0;
+
+ for(index = 0; index < *count; ++index) {
+ values[item++] = table_remove(table, table->keys[index]);
+ }
+
+ return values;
+}
+
+#undef HASHTABLE_IMPLEMENTATION
+#endif
diff --git a/src/hotkey.c b/src/hotkey.c
index d34d9a0..1267ea3 100644
--- a/src/hotkey.c
+++ b/src/hotkey.c
@@ -9,7 +9,7 @@
#define local_persist static
internal bool
-execute_hotkey(struct hotkey *hotkey)
+fork_and_exec(char *command)
{
local_persist char arg[] = "-c";
local_persist char *shell = NULL;
@@ -22,7 +22,7 @@ execute_hotkey(struct hotkey *hotkey)
int cpid = fork();
if(cpid == 0)
{
- char *exec[] = { shell, arg, hotkey->command, NULL};
+ char *exec[] = { shell, arg, command, NULL};
int status_code = execvp(exec[0], exec);
exit(status_code);
}
@@ -100,87 +100,74 @@ same_hotkey(struct hotkey *a, struct hotkey *b)
return false;
}
-internal bool
-find_hotkey(struct hotkey *seek, struct hotkey **result, struct hotkey *hotkeys)
+unsigned long
+hash_hotkey(struct hotkey *a)
{
- struct hotkey *hotkey = hotkeys;
- while(hotkey) {
- if(same_hotkey(hotkey, seek)) {
- *result = hotkey;
- return true;
- }
+ return a->key;
+}
- hotkey = hotkey->next;
+bool find_and_exec_hotkey(struct hotkey *eventkey, struct table *hotkey_map)
+{
+ bool result = false;
+ struct hotkey *hotkey;
+ if((hotkey = table_find(hotkey_map, eventkey))) {
+ if(fork_and_exec(hotkey->command)) {
+ result = has_flags(hotkey, Hotkey_Flag_Passthrough) ? false : true;
+ }
}
-
- return false;
+ return result;
}
-void free_hotkeys(struct hotkey *hotkeys)
+void free_hotkeys(struct table *hotkey_map)
{
- struct hotkey *next, *hotkey = hotkeys;
- while(hotkey) {
- next = hotkey->next;
+ int count;
+ void **hotkeys = table_reset(hotkey_map, &count);
+ for(int index = 0; index < count; ++index) {
+ struct hotkey *hotkey = (struct hotkey *) hotkeys[index];
free(hotkey->command);
free(hotkey);
- hotkey = next;
}
-}
-bool find_and_exec_hotkey(struct hotkey *eventkey, struct hotkey *hotkeys)
-{
- bool result = false;
- struct hotkey *hotkey = NULL;
- if(find_hotkey(eventkey, &hotkey, hotkeys)) {
- if(execute_hotkey(hotkey)) {
- result = has_flags(hotkey, Hotkey_Flag_Passthrough) ? false : true;
- }
+ if(count) {
+ free(hotkeys);
}
-
- return result;
}
-struct hotkey
-cgevent_to_hotkey(CGEventFlags flags, uint32_t key)
+void cgeventflags_to_hotkeyflags(CGEventFlags flags, struct hotkey *eventkey)
{
- struct hotkey eventkey = {};
- eventkey.key = key;
-
if((flags & Event_Mask_Cmd) == Event_Mask_Cmd) {
bool left = (flags & Event_Mask_LCmd) == Event_Mask_LCmd;
bool right = (flags & Event_Mask_RCmd) == Event_Mask_RCmd;
- if(left) add_flags(&eventkey, Hotkey_Flag_LCmd);
- if(right) add_flags(&eventkey, Hotkey_Flag_RCmd);
- if(!left && !right) add_flags(&eventkey, Hotkey_Flag_Cmd);
+ if(left) add_flags(eventkey, Hotkey_Flag_LCmd);
+ if(right) add_flags(eventkey, Hotkey_Flag_RCmd);
+ if(!left && !right) add_flags(eventkey, Hotkey_Flag_Cmd);
}
if((flags & Event_Mask_Shift) == Event_Mask_Shift) {
bool left = (flags & Event_Mask_LShift) == Event_Mask_LShift;
bool right = (flags & Event_Mask_RShift) == Event_Mask_RShift;
- if(left) add_flags(&eventkey, Hotkey_Flag_LShift);
- if(right) add_flags(&eventkey, Hotkey_Flag_RShift);
- if(!left && !right) add_flags(&eventkey, Hotkey_Flag_Shift);
+ if(left) add_flags(eventkey, Hotkey_Flag_LShift);
+ if(right) add_flags(eventkey, Hotkey_Flag_RShift);
+ if(!left && !right) add_flags(eventkey, Hotkey_Flag_Shift);
}
if((flags & Event_Mask_Alt) == Event_Mask_Alt) {
bool left = (flags & Event_Mask_LAlt) == Event_Mask_LAlt;
bool right = (flags & Event_Mask_RAlt) == Event_Mask_RAlt;
- if(left) add_flags(&eventkey, Hotkey_Flag_LAlt);
- if(right) add_flags(&eventkey, Hotkey_Flag_RAlt);
- if(!left && !right) add_flags(&eventkey, Hotkey_Flag_Alt);
+ if(left) add_flags(eventkey, Hotkey_Flag_LAlt);
+ if(right) add_flags(eventkey, Hotkey_Flag_RAlt);
+ if(!left && !right) add_flags(eventkey, Hotkey_Flag_Alt);
}
if((flags & Event_Mask_Control) == Event_Mask_Control) {
bool left = (flags & Event_Mask_LControl) == Event_Mask_LControl;
bool right = (flags & Event_Mask_RControl) == Event_Mask_RControl;
- if(left) add_flags(&eventkey, Hotkey_Flag_LControl);
- if(right) add_flags(&eventkey, Hotkey_Flag_RControl);
- if(!left && !right) add_flags(&eventkey, Hotkey_Flag_Control);
+ if(left) add_flags(eventkey, Hotkey_Flag_LControl);
+ if(right) add_flags(eventkey, Hotkey_Flag_RControl);
+ if(!left && !right) add_flags(eventkey, Hotkey_Flag_Control);
}
-
- return eventkey;
}
diff --git a/src/hotkey.h b/src/hotkey.h
index 293f04f..614665d 100644
--- a/src/hotkey.h
+++ b/src/hotkey.h
@@ -5,8 +5,6 @@
#include <stdint.h>
#include <stdbool.h>
-#define internal static
-
enum osx_event_mask
{
Event_Mask_Alt = 0x00080000,
@@ -52,30 +50,31 @@ struct hotkey
uint32_t flags;
uint32_t key;
char *command;
- struct hotkey *next;
};
-internal inline void
+static inline void
add_flags(struct hotkey *hotkey, uint32_t flag)
{
hotkey->flags |= flag;
}
-internal inline bool
+static inline bool
has_flags(struct hotkey *hotkey, uint32_t flag)
{
bool result = hotkey->flags & flag;
return result;
}
-internal inline void
+static inline void
clear_flags(struct hotkey *hotkey, uint32_t flag)
{
hotkey->flags &= ~flag;
}
-bool find_and_exec_hotkey(struct hotkey *eventkey, struct hotkey *hotkeys);
-struct hotkey cgevent_to_hotkey(CGEventFlags flags, uint32_t key);
-void free_hotkeys(struct hotkey *hotkeys);
+bool find_and_exec_hotkey(struct hotkey *eventkey, struct table *hotkey_map);
+void cgeventflags_to_hotkeyflags(CGEventFlags flags, struct hotkey *eventkey);
+
+struct table;
+void free_hotkeys(struct table *hotkey_map);
#endif
diff --git a/src/parse.c b/src/parse.c
index 559d23d..b59e4cd 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -2,6 +2,7 @@
#include "tokenize.h"
#include "locale.h"
#include "hotkey.h"
+#include "hashtable.h"
#include <stdlib.h>
#include <stdio.h>
@@ -180,35 +181,30 @@ parse_hotkey(struct parser *parser)
printf("}\n");
- hotkey->next = NULL;
return hotkey;
}
-struct hotkey *
-parse_config(struct parser *parser)
+void parse_config(struct parser *parser, struct table *hotkey_map)
{
- struct hotkey hotkeys;
- struct hotkey *current_hotkey = &hotkeys;
-
+ struct hotkey *hotkey;
while(!parser_eof(parser)) {
if((parser_check(parser, Token_Modifier)) ||
(parser_check(parser, Token_Key_Hex)) ||
(parser_check(parser, Token_Key))) {
- current_hotkey->next = parse_hotkey(parser);
- current_hotkey = current_hotkey->next;
+ hotkey = parse_hotkey(parser);
+ table_add(hotkey_map, hotkey, hotkey);
if(parser->error) {
- return NULL;
+ free_hotkeys(hotkey_map);
+ return;
}
} else {
fprintf(stderr, "(#%d:%d) expected token 'Token_Modifier', 'Token_Key_Hex' or 'Token_Key', but got '%.*s'\n",
parser->current_token.line, parser->current_token.cursor,
parser->current_token.length, parser->current_token.text);
parser->error = true;
- return NULL;
+ return;
}
}
-
- return hotkeys.next;
}
struct token
diff --git a/src/parse.h b/src/parse.h
index f0ea0f7..52d3aa9 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -12,7 +12,8 @@ struct parser
bool error;
};
-struct hotkey *parse_config(struct parser *parser);
+struct table;
+void parse_config(struct parser *parser, struct table *hotkey_map);
struct token parser_peek(struct parser *parser);
struct token parser_previous(struct parser *parser);
diff --git a/src/skhd.c b/src/skhd.c
index 73b627c..c05605e 100644
--- a/src/skhd.c
+++ b/src/skhd.c
@@ -8,6 +8,9 @@
#include <Carbon/Carbon.h>
+#define HASHTABLE_IMPLEMENTATION
+#include "hashtable.h"
+
#include "hotload.h"
#include "event_tap.h"
#include "locale.h"
@@ -29,7 +32,7 @@ extern bool CGSIsSecureEventInputSet();
internal unsigned major_version = 0;
internal unsigned minor_version = 0;
internal unsigned patch_version = 4;
-internal struct hotkey *hotkeys;
+internal struct table hotkey_map;
internal char *config_file;
internal void
@@ -77,8 +80,11 @@ internal HOTLOADER_CALLBACK(hotloader_handler)
* Filter the duplicated event or something ?? */
struct parser parser;
if(parser_init(&parser, absolutepath)) {
- free_hotkeys(hotkeys);
- hotkeys = parse_config(&parser);
+ free_hotkeys(&hotkey_map);
+ parse_config(&parser, &hotkey_map);
+ if(parser.error) {
+ free_hotkeys(&hotkey_map);
+ }
parser_destroy(&parser);
}
}
@@ -100,8 +106,9 @@ internal EVENT_TAP_CALLBACK(key_handler)
{
uint32_t flags = CGEventGetFlags(event);
uint32_t key = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
- struct hotkey eventkey = cgevent_to_hotkey(flags, key);
- if(find_and_exec_hotkey(&eventkey, hotkeys)) {
+ struct hotkey eventkey = { .flags = 0, .key = key };
+ cgeventflags_to_hotkeyflags(flags, &eventkey);
+ if(find_and_exec_hotkey(&eventkey, &hotkey_map)) {
return NULL;
}
} break;
@@ -194,9 +201,17 @@ int main(int argc, char **argv)
set_config_path();
printf("skhd: using config '%s'\n", config_file);
+ table_init(&hotkey_map,
+ 128,
+ (table_hash_func) hash_hotkey,
+ (table_compare_func) same_hotkey);
+
struct parser parser;
if(parser_init(&parser, config_file)) {
- hotkeys = parse_config(&parser);
+ parse_config(&parser, &hotkey_map);
+ if(parser.error) {
+ free_hotkeys(&hotkey_map);
+ }
parser_destroy(&parser);
} else {
error("skhd: could not open file '%s'\n", config_file);