diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/carbon.c | 20 | ||||
-rw-r--r-- | src/carbon.h | 17 | ||||
-rw-r--r-- | src/hotkey.c | 29 | ||||
-rw-r--r-- | src/hotkey.h | 7 | ||||
-rw-r--r-- | src/parse.c | 56 | ||||
-rw-r--r-- | src/parse.h | 1 | ||||
-rw-r--r-- | src/skhd.c | 19 | ||||
-rw-r--r-- | src/tokenize.c | 29 | ||||
-rw-r--r-- | src/tokenize.h | 4 |
9 files changed, 146 insertions, 36 deletions
diff --git a/src/carbon.c b/src/carbon.c index 98e2793..9af606a 100644 --- a/src/carbon.c +++ b/src/carbon.c @@ -1,17 +1,10 @@ -#include <Carbon/Carbon.h> +#include "carbon.h" -struct carbon_event -{ - EventTargetRef target; - EventHandlerUPP handler; - EventTypeSpec type; - EventHandlerRef handler_ref; - char * volatile process_name; -}; +#define internal static #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated" -static OSStatus +internal OSStatus carbon_event_handler(EventHandlerCallRef ref, EventRef event, void *context) { struct carbon_event *carbon = (struct carbon_event *) context; @@ -29,9 +22,12 @@ carbon_event_handler(EventHandlerCallRef ref, EventRef event, void *context) CFStringRef process_name_ref; if (CopyProcessName(&psn, &process_name_ref) == noErr) { - if (carbon->process_name) free(carbon->process_name); + if (carbon->process_name) { + free(carbon->process_name); + carbon->process_name = NULL; + } + carbon->process_name = copy_cfstring(process_name_ref); - printf("front app changed: %s\n", carbon->process_name); CFRelease(process_name_ref); } diff --git a/src/carbon.h b/src/carbon.h new file mode 100644 index 0000000..d98792a --- /dev/null +++ b/src/carbon.h @@ -0,0 +1,17 @@ +#ifndef SKHD_CARBON_H +#define SKHD_CARBON_H + +#include <Carbon/Carbon.h> + +struct carbon_event +{ + EventTargetRef target; + EventHandlerUPP handler; + EventTypeSpec type; + EventHandlerRef handler_ref; + char * volatile process_name; +}; + +bool carbon_event_init(struct carbon_event *carbon); + +#endif diff --git a/src/hotkey.c b/src/hotkey.c index 6448328..1cb4669 100644 --- a/src/hotkey.c +++ b/src/hotkey.c @@ -96,6 +96,13 @@ unsigned long hash_mode(char *key) return hash; } +internal inline bool +same_string(char *a, char *b) +{ + if (!a || !b) return false; + return same_mode(a, b); +} + internal inline void fork_and_exec(char *command) { @@ -142,14 +149,29 @@ should_capture_hotkey(uint32_t capture) return (capture & MODE_CAPTURE(1)); } -bool find_and_exec_hotkey(struct hotkey *k, struct table *t, struct mode **m) +internal inline char * +find_process_command_mapping(struct hotkey *hotkey, uint32_t *capture, struct carbon_event *carbon) +{ + for (int i = 0; i < buf_len(hotkey->process_name); ++i) { + if (same_string(carbon->process_name, hotkey->process_name[i])) { + return hotkey->command[i]; + } + } + + *capture &= ~FOUND_HOTKEY; + return NULL; +} + +bool find_and_exec_hotkey(struct hotkey *k, struct table *t, struct mode **m, struct carbon_event *carbon) { uint32_t c = MODE_CAPTURE((int)(*m)->capture); for (struct hotkey *h = find_hotkey(*m, k, &c); h; passthrough(h, &c), h = 0) { - char *cmd = h->command; + char *cmd = h->command[0]; if (has_flags(h, Hotkey_Flag_Activate)) { *m = table_find(t, cmd); cmd = (*m)->command; + } else if (buf_len(h->process_name) > 0) { + cmd = find_process_command_mapping(h, &c, carbon); } if (cmd) fork_and_exec(cmd); } @@ -178,7 +200,8 @@ void free_mode_map(struct table *mode_map) buf_push(freed_pointers, hotkey); buf_free(hotkey->mode_list); - free(hotkey->command); + buf_free(hotkey->process_name); + buf_free(hotkey->command); free(hotkey); next:; } diff --git a/src/hotkey.h b/src/hotkey.h index f06ce90..f96fcea 100644 --- a/src/hotkey.h +++ b/src/hotkey.h @@ -57,6 +57,8 @@ enum hotkey_flag #include "hashtable.h" +struct carbon_event; + struct mode { int line; @@ -71,7 +73,8 @@ struct hotkey { uint32_t flags; uint32_t key; - char *command; + char **process_name; + char **command; struct mode **mode_list; }; @@ -103,7 +106,7 @@ unsigned long hash_hotkey(struct hotkey *a); struct hotkey create_eventkey(CGEventRef event); bool intercept_systemkey(CGEventRef event, struct hotkey *eventkey); -bool find_and_exec_hotkey(struct hotkey *eventkey, struct table *mode_map, struct mode **current_mode); +bool find_and_exec_hotkey(struct hotkey *k, struct table *t, struct mode **m, struct carbon_event *carbon); void free_mode_map(struct table *mode_map); void init_shell(); diff --git a/src/parse.c b/src/parse.c index 8dc90dd..46378b2 100644 --- a/src/parse.c +++ b/src/parse.c @@ -74,13 +74,46 @@ keycode_from_hex(char *hex) return result; } -internal char * -parse_command(struct parser *parser) +internal void +parse_command(struct parser *parser, struct hotkey *hotkey) { struct token command = parser_previous(parser); char *result = copy_string_count(command.text, command.length); debug("\tcmd: '%s'\n", result); - return result; + buf_push(hotkey->command, result); +} + +internal void +parse_process_command_list(struct parser *parser, struct hotkey *hotkey) +{ + if (parser_match(parser, Token_String)) { + struct token name_token = parser_previous(parser); + char *name = copy_string_count(name_token.text, name_token.length); + buf_push(hotkey->process_name, name); + if (parser_match(parser, Token_Command)) { + parse_command(parser, hotkey); + parse_process_command_list(parser, hotkey); + } else { + parser_report_error(parser, Error_Unexpected_Token, "expected ':' followed by command"); + } + } else if (parser_match(parser, Token_EndList)) { + if (!buf_len(hotkey->process_name)) { + parser_report_error(parser, Error_Missing_Value, "list must contain at least one value"); + } + } else { + parser_report_error(parser, Error_Unexpected_Token, "expected process command mapping or ']'"); + } +} + +internal void +parse_activate(struct parser *parser, struct hotkey *hotkey) +{ + parse_command(parser, hotkey); + hotkey->flags |= Hotkey_Flag_Activate; + + if (!table_find(parser->mode_map, hotkey->command[0])) { + parser_report_error(parser, Error_Undeclared_Ident, "undeclared identifier"); + } } internal uint32_t @@ -269,12 +302,15 @@ parse_hotkey(struct parser *parser) } if (parser_match(parser, Token_Command)) { - hotkey->command = parse_command(parser); + parse_command(parser, hotkey); + } else if (parser_match(parser, Token_BeginList)) { + parse_process_command_list(parser); + if (parser->error) { + goto err; + } } else if (parser_match(parser, Token_Activate)) { - hotkey->flags |= Hotkey_Flag_Activate; - hotkey->command = parse_command(parser); - if (!table_find(parser->mode_map, hotkey->command)) { - parser_report_error(parser, Error_Undeclared_Ident, "undeclared identifier"); + parse_activate(parser, hotkey); + if (parser->error) { goto err; } } else { @@ -468,6 +504,10 @@ void parser_report_error(struct parser *parser, enum parse_error_type error_type fprintf(stderr, "#%d:%d ", parser->previous_token.line, parser->previous_token.cursor); vfprintf(stderr, format, args); fprintf(stderr, " '%.*s'\n", parser->previous_token.length, parser->previous_token.text); + } else if (error_type == Error_Missing_Value) { + fprintf(stderr, "#%d:%d ", parser->previous_token.line, parser->previous_token.cursor); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); } else if (error_type == Error_Duplicate_Ident) { vfprintf(stderr, format, args); } diff --git a/src/parse.h b/src/parse.h index 93fcfc6..9bd11e5 100644 --- a/src/parse.h +++ b/src/parse.h @@ -19,6 +19,7 @@ enum parse_error_type Error_Unexpected_Token, Error_Undeclared_Ident, Error_Duplicate_Ident, + Error_Missing_Value, }; @@ -15,6 +15,7 @@ #include "hotload.h" #include "event_tap.h" #include "locale.h" +#include "carbon.h" #include "tokenize.h" #include "parse.h" #include "hotkey.h" @@ -23,11 +24,11 @@ #include "hotload.c" #include "event_tap.c" #include "locale.c" +#include "carbon.c" #include "tokenize.c" #include "parse.c" #include "hotkey.c" #include "synthesize.c" -// #include "carbon.c" #define internal static extern bool CGSIsSecureEventInputSet(); @@ -63,7 +64,7 @@ internal unsigned major_version = 0; internal unsigned minor_version = 2; internal unsigned patch_version = 5; -// internal struct carbon_event carbon; +internal struct carbon_event carbon; internal struct event_tap event_tap; internal struct hotloader hotloader; internal struct mode *current_mode; @@ -105,7 +106,7 @@ internal EVENT_TAP_CALLBACK(key_handler) BEGIN_TIMED_BLOCK("handle_keypress"); struct hotkey eventkey = create_eventkey(event); - bool result = find_and_exec_hotkey(&eventkey, &mode_map, ¤t_mode); + bool result = find_and_exec_hotkey(&eventkey, &mode_map, ¤t_mode, &carbon); END_TIMED_BLOCK(); if (result) return NULL; @@ -115,7 +116,7 @@ internal EVENT_TAP_CALLBACK(key_handler) struct hotkey eventkey; if (intercept_systemkey(event, &eventkey)) { - bool result = find_and_exec_hotkey(&eventkey, &mode_map, ¤t_mode); + bool result = find_and_exec_hotkey(&eventkey, &mode_map, ¤t_mode, &carbon); if (result) return NULL; } } break; @@ -223,13 +224,9 @@ int main(int argc, char **argv) error("skhd: could not initialize keycode map! abort..\n"); } - /* - * NOTE(koekeishiya: hooks up event for tracking name of focused process/application - * - * if (!carbon_event_init(&carbon)) { - * error("skhd: could not initialize carbon events! abort..\n"); - * } - */ + if (!carbon_event_init(&carbon)) { + error("skhd: could not initialize carbon events! abort..\n"); + } if (!config_file) { use_default_config_path(); diff --git a/src/tokenize.c b/src/tokenize.c index 5040a7c..8445a71 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -63,6 +63,22 @@ eat_hex(struct tokenizer *tokenizer) } } +internal void +eat_string(struct tokenizer *tokenizer) +{ + /* + * NOTE(koekeishiya): This is NOT proper string parsing code, as we do + * not check for escaped '"' here. At the time of writing, this is only + * supposed to be used for parsing names of processes, and such names + * should not contain escaped quotes at all. We are lazy and simply do + * the most basic implementation that fulfills our current requirement. + */ + + while (*tokenizer->at && *tokenizer->at != '"') { + advance(tokenizer); + } +} + internal inline bool isidentifier(char c) { @@ -130,6 +146,19 @@ get_token(struct tokenizer *tokenizer) case ',': { token.type = Token_Comma; } break; case '<': { token.type = Token_Insert; } break; case '@': { token.type = Token_Capture; } break; + case '[': { token.type = Token_BeginList; } break; + case ']': { token.type = Token_EndList; } break; + case '"': { + token.text = tokenizer->at; + token.line = tokenizer->line; + token.cursor = tokenizer->cursor; + + eat_string(tokenizer); + token.length = tokenizer->at - token.text; + token.type = Token_String; + + advance(tokenizer); + } break; case '#': { eat_comment(tokenizer); token = get_token(tokenizer); diff --git a/src/tokenize.h b/src/tokenize.h index 3c1bd31..73cdb30 100644 --- a/src/tokenize.h +++ b/src/tokenize.h @@ -49,6 +49,10 @@ enum token_type Token_Dash, Token_Arrow, Token_Capture, + Token_String, + + Token_BeginList, + Token_EndList, Token_Unknown, Token_EndOfStream, |