aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/carbon.c20
-rw-r--r--src/carbon.h17
-rw-r--r--src/hotkey.c29
-rw-r--r--src/hotkey.h7
-rw-r--r--src/parse.c56
-rw-r--r--src/parse.h1
-rw-r--r--src/skhd.c19
-rw-r--r--src/tokenize.c29
-rw-r--r--src/tokenize.h4
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,
};
diff --git a/src/skhd.c b/src/skhd.c
index 1391125..3725641 100644
--- a/src/skhd.c
+++ b/src/skhd.c
@@ -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, &current_mode);
+ bool result = find_and_exec_hotkey(&eventkey, &mode_map, &current_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, &current_mode);
+ bool result = find_and_exec_hotkey(&eventkey, &mode_map, &current_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,