diff options
Diffstat (limited to '')
-rw-r--r-- | src/hashtable.h | 139 | ||||
-rw-r--r-- | src/hotkey.c | 83 | ||||
-rw-r--r-- | src/hotkey.h | 17 | ||||
-rw-r--r-- | src/parse.c | 20 | ||||
-rw-r--r-- | src/parse.h | 3 | ||||
-rw-r--r-- | src/skhd.c | 27 |
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); @@ -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); |