shithub: puzzles

Download patch

ref: 4a37f7cf782592b670d0180a38eb1fd680288421
parent: 4fdcc5497503658324fda2e0073d830276b24b60
author: Ben Harris <bjh21@bjh21.me.uk>
date: Sat Nov 5 12:05:39 EDT 2022

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.

--- a/devel.but
+++ b/devel.but
@@ -3131,7 +3131,7 @@
 
 \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 parameters \c{x} and \c{y} are identical to the ones passed to the
@@ -3172,6 +3172,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}
 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
 passed to this function by the front end, but are never passed on to
--- a/emcc.c
+++ b/emcc.c
@@ -250,7 +250,7 @@
 {
     button = (button == 0 ? LEFT_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();
 }
 
@@ -258,7 +258,7 @@
 {
     button = (button == 0 ? LEFT_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();
 }
 
@@ -266,7 +266,7 @@
 {
     int button = (buttons & 2 ? MIDDLE_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();
 }
 
@@ -379,7 +379,7 @@
             location == DOM_KEY_LOCATION_NUMPAD)
             keyevent |= MOD_NUM_KEYPAD;
 
-        midend_process_key(me, 0, 0, keyevent);
+        midend_process_key(me, 0, 0, keyevent, NULL);
         update_undo_redo();
         return true; /* We've probably handled the event. */
     }
@@ -792,7 +792,7 @@
         update_undo_redo();
         break;
       case 5:                          /* New Game */
-        midend_process_key(me, 0, 0, UI_NEWGAME);
+        midend_process_key(me, 0, 0, UI_NEWGAME, NULL);
         update_undo_redo();
         js_focus_canvas();
         break;
@@ -802,12 +802,12 @@
         js_focus_canvas();
         break;
       case 7:                          /* Undo */
-        midend_process_key(me, 0, 0, UI_UNDO);
+        midend_process_key(me, 0, 0, UI_UNDO, NULL);
         update_undo_redo();
         js_focus_canvas();
         break;
       case 8:                          /* Redo */
-        midend_process_key(me, 0, 0, UI_REDO);
+        midend_process_key(me, 0, 0, UI_REDO, NULL);
         update_undo_redo();
         js_focus_canvas();
         break;
--- a/gtk.c
+++ b/gtk.c
@@ -1533,7 +1533,7 @@
         keyval = -1;
 
     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);
 
     return true;
@@ -1568,7 +1568,7 @@
         button += LEFT_RELEASE - LEFT_BUTTON;
 
     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);
 
     return true;
@@ -1593,7 +1593,7 @@
 	return false;		       /* don't even know what button! */
 
     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);
 #if GTK_CHECK_VERSION(2,12,0)
     gdk_event_request_motions(event);
@@ -2188,7 +2188,7 @@
     frontend *fe = (frontend *)data;
     int key = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
                                                 "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);
 }
 
@@ -4130,7 +4130,7 @@
 
 	if (redo_proportion) {
 	    /* 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. */
 	    midend_freeze_timer(fe->me, redo_proportion);
 	}
--- a/midend.c
+++ b/midend.c
@@ -935,7 +935,8 @@
     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 =
         me->ourgame->dup_game(me->states[me->statepos - 1].state);
@@ -956,6 +957,7 @@
             button == UI_NEWGAME) {
 	    midend_new_game(me);
 	    midend_redraw(me);
+            *handled = true;
 	    goto done;		       /* never animate */
 	} else if (button == 'u' || button == 'U' ||
 		   button == '\x1A' || button == '\x1F' ||
@@ -965,6 +967,7 @@
 	    gottype = true;
 	    if (!midend_undo(me))
 		goto done;
+            *handled = true;
 	} else if (button == 'r' || button == 'R' ||
 		   button == '\x12' || button == '\x19' ||
                    button == UI_REDO) {
@@ -971,17 +974,21 @@
 	    midend_stop_anim(me);
 	    if (!midend_redo(me))
 		goto done;
+            *handled = true;
 	} else if ((button == '\x13' || button == UI_SOLVE) &&
                    me->ourgame->can_solve) {
+            *handled = true;
 	    if (midend_solve(me))
 		goto done;
 	} else if (button == 'q' || button == 'Q' || button == '\x11' ||
                    button == UI_QUIT) {
 	    ret = false;
+            *handled = true;
 	    goto done;
 	} else
 	    goto done;
     } else {
+        *handled = true;
 	if (movestr == UI_UPDATE)
 	    s = me->states[me->statepos-1].state;
 	else {
@@ -1052,10 +1059,12 @@
     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.
      * 
@@ -1155,7 +1164,7 @@
          */
         ret = ret && midend_really_process_key
             (me, x, y, (me->pressed_mouse_button +
-                        (LEFT_RELEASE - LEFT_BUTTON)));
+                        (LEFT_RELEASE - LEFT_BUTTON)), handled);
     }
 
     /*
@@ -1178,7 +1187,7 @@
     /*
      * 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.
--- a/nestedvm.c
+++ b/nestedvm.c
@@ -206,7 +206,7 @@
     if (fe->ox == -1)
         return 1;
     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 1;
 }
@@ -323,7 +323,7 @@
 int jcallback_newgame_event(void)
 {
     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 0;
 }
@@ -331,7 +331,7 @@
 int jcallback_undo_event(void)
 {
     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 0;
 }
@@ -339,7 +339,7 @@
 int jcallback_redo_event(void)
 {
     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 0;
 }
@@ -347,7 +347,7 @@
 int jcallback_quit_event(void)
 {
     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 0;
 }
--- a/osx.m
+++ b/osx.m
@@ -632,13 +632,13 @@
 
 - (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];
 }
 
 - (void)processKey:(int)b
 {
-    if (!midend_process_key(me, -1, -1, b))
+    if (!midend_process_key(me, -1, -1, b, NULL))
 	[self close];
 }
 
--- a/puzzles.h
+++ b/puzzles.h
@@ -305,7 +305,7 @@
 void midend_new_game(midend *me);
 void midend_restart_game(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);
 void midend_force_redraw(midend *me);
 void midend_redraw(midend *me);
--- a/windows.c
+++ b/windows.c
@@ -2530,7 +2530,7 @@
 	cmd = wParam & ~0xF;	       /* low 4 bits reserved to Windows */
 	switch (cmd) {
 	  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);
 	    break;
 	  case IDM_RESTART:
@@ -2537,11 +2537,11 @@
 	    midend_restart_game(fe->me);
 	    break;
 	  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);
 	    break;
 	  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);
 	    break;
 	  case IDM_COPY:
@@ -2563,7 +2563,7 @@
 	    }
 	    break;
 	  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);
 	    break;
 	  case IDM_CONFIG:
@@ -2833,7 +2833,7 @@
 	    }
 
 	    if (key != -1) {
-		if (!midend_process_key(fe->me, 0, 0, key))
+                if (!midend_process_key(fe->me, 0, 0, key, NULL))
 		    PostQuitMessage(0);
 	    } else {
 		MSG m;
@@ -2866,7 +2866,7 @@
 	    if (!midend_process_key(fe->me,
 				    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
 				    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
-				    button))
+				    button, NULL))
 		PostQuitMessage(0);
 
 	    SetCapture(hwnd);
@@ -2893,7 +2893,7 @@
 	    if (!midend_process_key(fe->me,
 				    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
 				    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
-				    button))
+				    button, NULL))
 		PostQuitMessage(0);
 
 	    ReleaseCapture();
@@ -2913,7 +2913,7 @@
 	    if (!midend_process_key(fe->me,
 				    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
 				    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
-				    button))
+				    button, NULL))
 		PostQuitMessage(0);
 	}
 	break;
@@ -2927,7 +2927,7 @@
                     (keystate[VK_CONTROL] & 0x80))
                     key = UI_REDO;
             }
-            if (!midend_process_key(fe->me, 0, 0, key))
+            if (!midend_process_key(fe->me, 0, 0, key, NULL))
                 PostQuitMessage(0);
         }
 	return 0;