float anim_time, anim_pos;
float flash_time, flash_pos;
int dir;
+
+ int pressed_mouse_button;
};
#define ensure(me) do { \
me->flash_time = me->flash_pos = 0.0F;
me->dir = 0;
me->ui = NULL;
+ me->pressed_mouse_button = 0;
sfree(randseed);
if (me->ui)
me->ourgame->free_ui(me->ui);
me->ui = me->ourgame->new_ui(me->states[0]);
+ me->pressed_mouse_button = 0;
}
void midend_restart_game(midend_data *me)
}
}
-int midend_process_key(midend_data *me, int x, int y, int button)
+static int midend_really_process_key(midend_data *me, int x, int y, int button)
{
game_state *oldstate = me->ourgame->dup_game(me->states[me->statepos - 1]);
float anim_time;
return 1;
}
+int midend_process_key(midend_data *me, int x, int y, int button)
+{
+ int ret = 1;
+
+ /*
+ * Harmonise mouse drag and release messages.
+ *
+ * Some front ends might accidentally switch from sending, say,
+ * RIGHT_DRAG messages to sending LEFT_DRAG, half way through a
+ * drag. (This can happen on the Mac, for example, since
+ * RIGHT_DRAG is usually done using Command+drag, and if the
+ * user accidentally releases Command half way through the drag
+ * then there will be trouble.)
+ *
+ * It would be an O(number of front ends) annoyance to fix this
+ * in the front ends, but an O(number of back ends) annoyance
+ * to have each game capable of dealing with it. Therefore, we
+ * fix it _here_ in the common midend code so that it only has
+ * to be done once.
+ *
+ * The possible ways in which things can go screwy in the front
+ * end are:
+ *
+ * - in a system containing multiple physical buttons button
+ * presses can inadvertently overlap. We can see ABab (caps
+ * meaning button-down and lowercase meaning button-up) when
+ * the user had semantically intended AaBb.
+ *
+ * - in a system where one button is simulated by means of a
+ * modifier key and another button, buttons can mutate
+ * between press and release (possibly during drag). So we
+ * can see Ab instead of Aa.
+ *
+ * Definite requirements are:
+ *
+ * - button _presses_ must never be invented or destroyed. If
+ * the user presses two buttons in succession, the button
+ * presses must be transferred to the backend unchanged. So
+ * if we see AaBb , that's fine; if we see ABab (the button
+ * presses inadvertently overlapped) we must somehow
+ * `correct' it to AaBb.
+ *
+ * - every mouse action must end up looking like a press, zero
+ * or more drags, then a release. This allows back ends to
+ * make the _assumption_ that incoming mouse data will be
+ * sane in this regard, and not worry about the details.
+ *
+ * So my policy will be:
+ *
+ * - treat any button-up as a button-up for the currently
+ * pressed button, or ignore it if there is no currently
+ * pressed button.
+ *
+ * - treat any drag as a drag for the currently pressed
+ * button, or ignore it if there is no currently pressed
+ * button.
+ *
+ * - if we see a button-down while another button is currently
+ * pressed, invent a button-up for the first one and then
+ * pass the button-down through as before.
+ *
+ */
+ if (IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) {
+ if (me->pressed_mouse_button) {
+ if (IS_MOUSE_DRAG(button)) {
+ button = me->pressed_mouse_button +
+ (LEFT_DRAG - LEFT_BUTTON);
+ } else {
+ button = me->pressed_mouse_button +
+ (LEFT_RELEASE - LEFT_BUTTON);
+ }
+ } else
+ return ret; /* ignore it */
+ } else if (IS_MOUSE_DOWN(button) && me->pressed_mouse_button) {
+ /*
+ * Fabricate a button-up for the previously pressed button.
+ */
+ ret = ret && midend_really_process_key
+ (me, x, y, (me->pressed_mouse_button +
+ (LEFT_RELEASE - LEFT_BUTTON)));
+ }
+
+ /*
+ * Now send on the event we originally received.
+ */
+ ret = ret && midend_really_process_key(me, x, y, button);
+
+ /*
+ * And update the currently pressed button.
+ */
+ if (IS_MOUSE_RELEASE(button))
+ me->pressed_mouse_button = 0;
+ else if (IS_MOUSE_DOWN(button))
+ me->pressed_mouse_button = button;
+
+ return ret;
+}
+
void midend_redraw(midend_data *me)
{
if (me->statepos > 0 && me->drawstate) {