Add a way for midend_process_key() to report whether it handled a keypress

This adds a new bool * argument, which can be NULL if front ends don't
care whether the keypress was handled.  Currently they all do that.

Currently, "undo" and "redo" keys are treated as not handled if there's
no move to undo or redo.  This may be a little too strict.
This commit is contained in:
Ben Harris
2022-11-05 16:05:39 +00:00
parent 4fdcc54975
commit 4a37f7cf78
8 changed files with 50 additions and 35 deletions

View File

@ -3131,7 +3131,7 @@ call to this function. Some back ends require that \cw{midend_size()}
\H{midend-process-key} \cw{midend_process_key()} \H{midend-process-key} \cw{midend_process_key()}
\c bool midend_process_key(midend *me, int x, int y, int button); \c bool midend_process_key(midend *me, int x, int y, int button, bool *handled);
The front end calls this function to report a mouse or keyboard event. The front end calls this function to report a mouse or keyboard event.
The parameters \c{x} and \c{y} are identical to the ones passed to the The parameters \c{x} and \c{y} are identical to the ones passed to the
@ -3173,6 +3173,12 @@ the effect of the keypress was to request termination of the program.
A front end should shut down the puzzle in response to a \cw{false} A front end should shut down the puzzle in response to a \cw{false}
return. return.
If the front end passes in a non-NULL pointer in \c{handled}, the
mid-end will set \cw{*handled} to \cw{true} if it or the backend does
something in response to the keypress. A front end can use this to
decide whether to pass the keypress on to anything else that might
want to do something in response to it.
The following additional values of \c{button} are permitted to be The following additional values of \c{button} are permitted to be
passed to this function by the front end, but are never passed on to passed to this function by the front end, but are never passed on to
the back end. They indicate front-end specific UI operations, such as the back end. They indicate front-end specific UI operations, such as

14
emcc.c
View File

@ -250,7 +250,7 @@ void mousedown(int x, int y, int button)
{ {
button = (button == 0 ? LEFT_BUTTON : button = (button == 0 ? LEFT_BUTTON :
button == 1 ? MIDDLE_BUTTON : RIGHT_BUTTON); button == 1 ? MIDDLE_BUTTON : RIGHT_BUTTON);
midend_process_key(me, x, y, button); midend_process_key(me, x, y, button, NULL);
update_undo_redo(); update_undo_redo();
} }
@ -258,7 +258,7 @@ void mouseup(int x, int y, int button)
{ {
button = (button == 0 ? LEFT_RELEASE : button = (button == 0 ? LEFT_RELEASE :
button == 1 ? MIDDLE_RELEASE : RIGHT_RELEASE); button == 1 ? MIDDLE_RELEASE : RIGHT_RELEASE);
midend_process_key(me, x, y, button); midend_process_key(me, x, y, button, NULL);
update_undo_redo(); update_undo_redo();
} }
@ -266,7 +266,7 @@ void mousemove(int x, int y, int buttons)
{ {
int button = (buttons & 2 ? MIDDLE_DRAG : int button = (buttons & 2 ? MIDDLE_DRAG :
buttons & 4 ? RIGHT_DRAG : LEFT_DRAG); buttons & 4 ? RIGHT_DRAG : LEFT_DRAG);
midend_process_key(me, x, y, button); midend_process_key(me, x, y, button, NULL);
update_undo_redo(); update_undo_redo();
} }
@ -379,7 +379,7 @@ bool key(int keycode, const char *key, const char *chr, int location,
location == DOM_KEY_LOCATION_NUMPAD) location == DOM_KEY_LOCATION_NUMPAD)
keyevent |= MOD_NUM_KEYPAD; keyevent |= MOD_NUM_KEYPAD;
midend_process_key(me, 0, 0, keyevent); midend_process_key(me, 0, 0, keyevent, NULL);
update_undo_redo(); update_undo_redo();
return true; /* We've probably handled the event. */ return true; /* We've probably handled the event. */
} }
@ -792,7 +792,7 @@ void command(int n)
update_undo_redo(); update_undo_redo();
break; break;
case 5: /* New Game */ case 5: /* New Game */
midend_process_key(me, 0, 0, UI_NEWGAME); midend_process_key(me, 0, 0, UI_NEWGAME, NULL);
update_undo_redo(); update_undo_redo();
js_focus_canvas(); js_focus_canvas();
break; break;
@ -802,12 +802,12 @@ void command(int n)
js_focus_canvas(); js_focus_canvas();
break; break;
case 7: /* Undo */ case 7: /* Undo */
midend_process_key(me, 0, 0, UI_UNDO); midend_process_key(me, 0, 0, UI_UNDO, NULL);
update_undo_redo(); update_undo_redo();
js_focus_canvas(); js_focus_canvas();
break; break;
case 8: /* Redo */ case 8: /* Redo */
midend_process_key(me, 0, 0, UI_REDO); midend_process_key(me, 0, 0, UI_REDO, NULL);
update_undo_redo(); update_undo_redo();
js_focus_canvas(); js_focus_canvas();
break; break;

10
gtk.c
View File

@ -1533,7 +1533,7 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
keyval = -1; keyval = -1;
if (keyval >= 0 && if (keyval >= 0 &&
!midend_process_key(fe->me, 0, 0, keyval)) !midend_process_key(fe->me, 0, 0, keyval, NULL))
gtk_widget_destroy(fe->window); gtk_widget_destroy(fe->window);
return true; return true;
@ -1568,7 +1568,7 @@ static gint button_event(GtkWidget *widget, GdkEventButton *event,
button += LEFT_RELEASE - LEFT_BUTTON; button += LEFT_RELEASE - LEFT_BUTTON;
if (!midend_process_key(fe->me, event->x - fe->ox, if (!midend_process_key(fe->me, event->x - fe->ox,
event->y - fe->oy, button)) event->y - fe->oy, button, NULL))
gtk_widget_destroy(fe->window); gtk_widget_destroy(fe->window);
return true; return true;
@ -1593,7 +1593,7 @@ static gint motion_event(GtkWidget *widget, GdkEventMotion *event,
return false; /* don't even know what button! */ return false; /* don't even know what button! */
if (!midend_process_key(fe->me, event->x - fe->ox, if (!midend_process_key(fe->me, event->x - fe->ox,
event->y - fe->oy, button)) event->y - fe->oy, button, NULL))
gtk_widget_destroy(fe->window); gtk_widget_destroy(fe->window);
#if GTK_CHECK_VERSION(2,12,0) #if GTK_CHECK_VERSION(2,12,0)
gdk_event_request_motions(event); gdk_event_request_motions(event);
@ -2188,7 +2188,7 @@ static void menu_key_event(GtkMenuItem *menuitem, gpointer data)
frontend *fe = (frontend *)data; frontend *fe = (frontend *)data;
int key = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), int key = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
"user-data")); "user-data"));
if (!midend_process_key(fe->me, 0, 0, key)) if (!midend_process_key(fe->me, 0, 0, key, NULL))
gtk_widget_destroy(fe->window); gtk_widget_destroy(fe->window);
} }
@ -4130,7 +4130,7 @@ int main(int argc, char **argv)
if (redo_proportion) { if (redo_proportion) {
/* Start a redo. */ /* Start a redo. */
midend_process_key(fe->me, 0, 0, 'r'); midend_process_key(fe->me, 0, 0, 'r', NULL);
/* And freeze the timer at the specified position. */ /* And freeze the timer at the specified position. */
midend_freeze_timer(fe->me, redo_proportion); midend_freeze_timer(fe->me, redo_proportion);
} }

View File

@ -935,7 +935,8 @@ void midend_restart_game(midend *me)
midend_set_timer(me); midend_set_timer(me);
} }
static bool midend_really_process_key(midend *me, int x, int y, int button) static bool midend_really_process_key(midend *me, int x, int y, int button,
bool *handled)
{ {
game_state *oldstate = game_state *oldstate =
me->ourgame->dup_game(me->states[me->statepos - 1].state); me->ourgame->dup_game(me->states[me->statepos - 1].state);
@ -956,6 +957,7 @@ static bool midend_really_process_key(midend *me, int x, int y, int button)
button == UI_NEWGAME) { button == UI_NEWGAME) {
midend_new_game(me); midend_new_game(me);
midend_redraw(me); midend_redraw(me);
*handled = true;
goto done; /* never animate */ goto done; /* never animate */
} else if (button == 'u' || button == 'U' || } else if (button == 'u' || button == 'U' ||
button == '\x1A' || button == '\x1F' || button == '\x1A' || button == '\x1F' ||
@ -965,23 +967,28 @@ static bool midend_really_process_key(midend *me, int x, int y, int button)
gottype = true; gottype = true;
if (!midend_undo(me)) if (!midend_undo(me))
goto done; goto done;
*handled = true;
} else if (button == 'r' || button == 'R' || } else if (button == 'r' || button == 'R' ||
button == '\x12' || button == '\x19' || button == '\x12' || button == '\x19' ||
button == UI_REDO) { button == UI_REDO) {
midend_stop_anim(me); midend_stop_anim(me);
if (!midend_redo(me)) if (!midend_redo(me))
goto done; goto done;
*handled = true;
} else if ((button == '\x13' || button == UI_SOLVE) && } else if ((button == '\x13' || button == UI_SOLVE) &&
me->ourgame->can_solve) { me->ourgame->can_solve) {
*handled = true;
if (midend_solve(me)) if (midend_solve(me))
goto done; goto done;
} else if (button == 'q' || button == 'Q' || button == '\x11' || } else if (button == 'q' || button == 'Q' || button == '\x11' ||
button == UI_QUIT) { button == UI_QUIT) {
ret = false; ret = false;
*handled = true;
goto done; goto done;
} else } else
goto done; goto done;
} else { } else {
*handled = true;
if (movestr == UI_UPDATE) if (movestr == UI_UPDATE)
s = me->states[me->statepos-1].state; s = me->states[me->statepos-1].state;
else { else {
@ -1052,10 +1059,12 @@ static bool midend_really_process_key(midend *me, int x, int y, int button)
return ret; return ret;
} }
bool midend_process_key(midend *me, int x, int y, int button) bool midend_process_key(midend *me, int x, int y, int button, bool *handled)
{ {
bool ret = true; bool ret = true, dummy_handled;
if (handled == NULL) handled = &dummy_handled;
*handled = false;
/* /*
* Harmonise mouse drag and release messages. * Harmonise mouse drag and release messages.
* *
@ -1155,7 +1164,7 @@ bool midend_process_key(midend *me, int x, int y, int button)
*/ */
ret = ret && midend_really_process_key ret = ret && midend_really_process_key
(me, x, y, (me->pressed_mouse_button + (me, x, y, (me->pressed_mouse_button +
(LEFT_RELEASE - LEFT_BUTTON))); (LEFT_RELEASE - LEFT_BUTTON)), handled);
} }
/* /*
@ -1178,7 +1187,7 @@ bool midend_process_key(midend *me, int x, int y, int button)
/* /*
* Now send on the event we originally received. * Now send on the event we originally received.
*/ */
ret = ret && midend_really_process_key(me, x, y, button); ret = ret && midend_really_process_key(me, x, y, button, handled);
/* /*
* And update the currently pressed button. * And update the currently pressed button.

View File

@ -206,7 +206,7 @@ int jcallback_key_event(int x, int y, int keyval)
if (fe->ox == -1) if (fe->ox == -1)
return 1; return 1;
if (keyval >= 0 && if (keyval >= 0 &&
!midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval)) !midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval, NULL))
return 42; return 42;
return 1; return 1;
} }
@ -323,7 +323,7 @@ static bool get_config(frontend *fe, int which)
int jcallback_newgame_event(void) int jcallback_newgame_event(void)
{ {
frontend *fe = (frontend *)_fe; frontend *fe = (frontend *)_fe;
if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME)) if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME, NULL))
return 42; return 42;
return 0; return 0;
} }
@ -331,7 +331,7 @@ int jcallback_newgame_event(void)
int jcallback_undo_event(void) int jcallback_undo_event(void)
{ {
frontend *fe = (frontend *)_fe; frontend *fe = (frontend *)_fe;
if (!midend_process_key(fe->me, 0, 0, UI_UNDO)) if (!midend_process_key(fe->me, 0, 0, UI_UNDO, NULL))
return 42; return 42;
return 0; return 0;
} }
@ -339,7 +339,7 @@ int jcallback_undo_event(void)
int jcallback_redo_event(void) int jcallback_redo_event(void)
{ {
frontend *fe = (frontend *)_fe; frontend *fe = (frontend *)_fe;
if (!midend_process_key(fe->me, 0, 0, UI_REDO)) if (!midend_process_key(fe->me, 0, 0, UI_REDO, NULL))
return 42; return 42;
return 0; return 0;
} }
@ -347,7 +347,7 @@ int jcallback_redo_event(void)
int jcallback_quit_event(void) int jcallback_quit_event(void)
{ {
frontend *fe = (frontend *)_fe; frontend *fe = (frontend *)_fe;
if (!midend_process_key(fe->me, 0, 0, UI_QUIT)) if (!midend_process_key(fe->me, 0, 0, UI_QUIT, NULL))
return 42; return 42;
return 0; return 0;
} }

4
osx.m
View File

@ -632,13 +632,13 @@ struct frontend {
- (void)processButton:(int)b x:(int)x y:(int)y - (void)processButton:(int)b x:(int)x y:(int)y
{ {
if (!midend_process_key(me, x, fe.h - 1 - y, b)) if (!midend_process_key(me, x, fe.h - 1 - y, b, NULL))
[self close]; [self close];
} }
- (void)processKey:(int)b - (void)processKey:(int)b
{ {
if (!midend_process_key(me, -1, -1, b)) if (!midend_process_key(me, -1, -1, b, NULL))
[self close]; [self close];
} }

View File

@ -305,7 +305,7 @@ void midend_reset_tilesize(midend *me);
void midend_new_game(midend *me); void midend_new_game(midend *me);
void midend_restart_game(midend *me); void midend_restart_game(midend *me);
void midend_stop_anim(midend *me); void midend_stop_anim(midend *me);
bool midend_process_key(midend *me, int x, int y, int button); bool midend_process_key(midend *me, int x, int y, int button, bool *handled);
key_label *midend_request_keys(midend *me, int *nkeys); key_label *midend_request_keys(midend *me, int *nkeys);
void midend_force_redraw(midend *me); void midend_force_redraw(midend *me);
void midend_redraw(midend *me); void midend_redraw(midend *me);

View File

@ -2530,18 +2530,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */ cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */
switch (cmd) { switch (cmd) {
case IDM_NEW: case IDM_NEW:
if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME)) if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME, NULL))
PostQuitMessage(0); PostQuitMessage(0);
break; break;
case IDM_RESTART: case IDM_RESTART:
midend_restart_game(fe->me); midend_restart_game(fe->me);
break; break;
case IDM_UNDO: case IDM_UNDO:
if (!midend_process_key(fe->me, 0, 0, UI_UNDO)) if (!midend_process_key(fe->me, 0, 0, UI_UNDO, NULL))
PostQuitMessage(0); PostQuitMessage(0);
break; break;
case IDM_REDO: case IDM_REDO:
if (!midend_process_key(fe->me, 0, 0, UI_REDO)) if (!midend_process_key(fe->me, 0, 0, UI_REDO, NULL))
PostQuitMessage(0); PostQuitMessage(0);
break; break;
case IDM_COPY: case IDM_COPY:
@ -2563,7 +2563,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
} }
break; break;
case IDM_QUIT: case IDM_QUIT:
if (!midend_process_key(fe->me, 0, 0, UI_QUIT)) if (!midend_process_key(fe->me, 0, 0, UI_QUIT, NULL))
PostQuitMessage(0); PostQuitMessage(0);
break; break;
case IDM_CONFIG: case IDM_CONFIG:
@ -2833,7 +2833,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
} }
if (key != -1) { if (key != -1) {
if (!midend_process_key(fe->me, 0, 0, key)) if (!midend_process_key(fe->me, 0, 0, key, NULL))
PostQuitMessage(0); PostQuitMessage(0);
} else { } else {
MSG m; MSG m;
@ -2866,7 +2866,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (!midend_process_key(fe->me, if (!midend_process_key(fe->me,
(signed short)LOWORD(lParam) - fe->bitmapPosition.left, (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
(signed short)HIWORD(lParam) - fe->bitmapPosition.top, (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
button)) button, NULL))
PostQuitMessage(0); PostQuitMessage(0);
SetCapture(hwnd); SetCapture(hwnd);
@ -2893,7 +2893,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (!midend_process_key(fe->me, if (!midend_process_key(fe->me,
(signed short)LOWORD(lParam) - fe->bitmapPosition.left, (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
(signed short)HIWORD(lParam) - fe->bitmapPosition.top, (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
button)) button, NULL))
PostQuitMessage(0); PostQuitMessage(0);
ReleaseCapture(); ReleaseCapture();
@ -2913,7 +2913,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (!midend_process_key(fe->me, if (!midend_process_key(fe->me,
(signed short)LOWORD(lParam) - fe->bitmapPosition.left, (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
(signed short)HIWORD(lParam) - fe->bitmapPosition.top, (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
button)) button, NULL))
PostQuitMessage(0); PostQuitMessage(0);
} }
break; break;
@ -2927,7 +2927,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
(keystate[VK_CONTROL] & 0x80)) (keystate[VK_CONTROL] & 0x80))
key = UI_REDO; key = UI_REDO;
} }
if (!midend_process_key(fe->me, 0, 0, key)) if (!midend_process_key(fe->me, 0, 0, key, NULL))
PostQuitMessage(0); PostQuitMessage(0);
} }
return 0; return 0;