Skip to content

Commit 1a6d883

Browse files
committed
fix: recover macOS helper input after wake
Reset stale grab state before sleep or session deactivation, repair the event tap on wake, and cancel active modes through an explicit input interrupt so keyboard input is not left suppressed after unlock.
1 parent a2a5de1 commit 1a6d883

18 files changed

Lines changed: 749 additions & 33 deletions

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ dist/
1414
*.exe
1515
tests/cursor_style_test
1616
tests/cursor_style_test.dSYM/
17+
tests/input_interrupt_test
18+
tests/input_interrupt_test.dSYM/
19+
tests/mode_interrupt_test
20+
tests/mode_interrupt_test.dSYM/

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,19 @@ endif
3535

3636
.PHONY: test
3737

38-
test: tests/cursor_style_test
38+
test: tests/cursor_style_test tests/input_interrupt_test tests/mode_interrupt_test
3939
./tests/cursor_style_test
40+
./tests/input_interrupt_test
41+
./tests/mode_interrupt_test
4042

4143
tests/cursor_style_test: tests/cursor_style_test.c src/cursor.c src/config.c src/warpd.h src/platform.h
4244
$(CC) -o tests/cursor_style_test tests/cursor_style_test.c src/cursor.c src/config.c $(CFLAGS)
4345

46+
tests/input_interrupt_test: tests/input_interrupt_test.c src/input.c src/warpd.h src/platform.h
47+
$(CC) -o tests/input_interrupt_test tests/input_interrupt_test.c src/input.c $(CFLAGS)
48+
49+
tests/mode_interrupt_test: tests/mode_interrupt_test.c src/normal.c src/warpd.h src/platform.h
50+
$(CC) -o tests/mode_interrupt_test tests/mode_interrupt_test.c src/normal.c $(CFLAGS)
51+
4452
man:
4553
scdoc < warpd.1.md | gzip > files/warpd.1.gz

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ On first run, you will be prompted to grant accessibility permissions. If you ar
119119
*Note 3:* Some programs (e.g iTerm) have a 'secure input mode' that may need to be
120120
disabled in order for warpd to work properly.
121121

122+
*Note 4:* On macOS, locking or sleeping the machine while a warpd mode is active
123+
cancels that mode and restores keyboard input after unlock or wake.
124+
122125
The service can be disabled with
123126

124127
```

codesign/sign.sh

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@
33
export KEYCHAIN_NAME=warpd-temp-keychain
44
export KEYCHAIN_PASSWORD=
55

6-
# Allow passing binary or bundle path as argument
7-
TARGET_PATH="${1:-../bin/warpd-bin}"
6+
# Allow passing binary or bundle path as argument.
7+
if [ "$#" -gt 0 ]; then
8+
case "$1" in
9+
/*) TARGET_PATH="$1" ;;
10+
*) TARGET_PATH="$(pwd)/$1" ;;
11+
esac
12+
else
13+
TARGET_PATH="../bin/warpd-bin"
14+
fi
815

916
cd "$(dirname "$0")"
1017

docs/plans/2026-07-08-001-fix-macos-helper-wake-keyboard-plan.md

Lines changed: 203 additions & 0 deletions
Large diffs are not rendered by default.

src/grid.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ struct input_event *grid_mode()
129129
ev = platform->input_next_event(10);
130130
platform->mouse_get_position(NULL, &mx, &my);
131131

132+
if (input_event_is_interrupt(ev))
133+
goto exit;
134+
132135
if (mouse_process_key(ev, "grid_up", "grid_down", "grid_left", "grid_right")) {
133136
redraw(mx, my, 0);
134137
continue;

src/hint.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ static int hint_selection(screen_t scr, struct hint *_hints, size_t _nr_hints)
122122

123123
ev = platform->input_next_event(0);
124124

125+
if (input_event_is_interrupt(ev)) {
126+
rc = -1;
127+
break;
128+
}
129+
130+
if (!ev)
131+
continue;
132+
125133
if (!ev->pressed)
126134
continue;
127135

src/input.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ const char *input_event_tostr(struct input_event *ev)
8686
return s;
8787
}
8888

89+
int input_event_is_interrupt(struct input_event *ev)
90+
{
91+
return ev && ev->code == 0 && ev->mods == 0;
92+
}
93+
8994
/*
9095
* Returns:
9196
* 0 on no match

src/mode-loop.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@ int mode_loop(int initial_mode, int oneshot, int record_history)
5353
break;
5454
case MODE_GRID:
5555
ev = grid_mode();
56+
if (input_event_is_interrupt(ev))
57+
goto exit;
5658
if (config_input_match(ev, "grid_exit"))
5759
ev = NULL;
5860
mode = MODE_NORMAL;
5961
break;
6062
case MODE_SCREEN_SELECTION:
61-
screen_selection_mode();
63+
if (screen_selection_mode() < 0)
64+
goto exit;
6265
mode = MODE_NORMAL;
6366
ev = NULL;
6467
break;
@@ -86,4 +89,3 @@ int mode_loop(int initial_mode, int oneshot, int record_history)
8689
exit:
8790
return rc;
8891
}
89-

src/normal.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ struct input_event *normal_mode(struct input_event *start_ev, int oneshot)
119119

120120
platform->mouse_get_position(&scr, &mx, &my);
121121

122+
if (input_event_is_interrupt(ev)) {
123+
ev = NULL;
124+
goto exit;
125+
}
126+
122127
if (!system_cursor && on_time) {
123128
if (show_cursor && (time - last_blink_update) >= on_time) {
124129
show_cursor = 0;
@@ -251,6 +256,8 @@ struct input_event *normal_mode(struct input_event *start_ev, int oneshot)
251256
}
252257

253258
exit:
259+
if (dragging)
260+
platform->mouse_up(config_get_int("drag_button"));
254261
platform->mouse_show();
255262
platform->screen_clear(scr);
256263

0 commit comments

Comments
 (0)