1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
26 #define DEBUG_EVENTS 0
28 #define DEBUG_EVENTS_BUTTON (DEBUG_EVENTS * 0)
29 #define DEBUG_EVENTS_MOTION (DEBUG_EVENTS * 0)
30 #define DEBUG_EVENTS_WINDOW (DEBUG_EVENTS * 0)
31 #define DEBUG_EVENTS_FINGER (DEBUG_EVENTS * 0)
32 #define DEBUG_EVENTS_TEXT (DEBUG_EVENTS * 1)
33 #define DEBUG_EVENTS_KEY (DEBUG_EVENTS * 1)
36 static boolean cursor_inside_playfield = FALSE;
37 static int cursor_mode_last = CURSOR_DEFAULT;
38 static unsigned int special_cursor_delay = 0;
39 static unsigned int special_cursor_delay_value = 1000;
41 /* event filter especially needed for SDL event filtering due to
42 delay problems with lots of mouse motion events when mouse button
43 not pressed (X11 can handle this with 'PointerMotionHintMask') */
45 /* event filter addition for SDL2: as SDL2 does not have a function to enable
46 or disable keyboard auto-repeat, filter repeated keyboard events instead */
48 static int FilterEventsExt(const Event *event)
52 #if defined(TARGET_SDL2)
53 /* skip repeated key press events if keyboard auto-repeat is disabled */
54 if (event->type == EVENT_KEYPRESS &&
60 /* non-motion events are directly passed to event handler functions */
61 if (event->type != EVENT_MOTIONNOTIFY)
64 motion = (MotionEvent *)event;
65 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
66 motion->y >= SY && motion->y < SY + SYSIZE);
68 /* do no reset mouse cursor before all pending events have been processed */
69 if (gfx.cursor_mode == cursor_mode_last &&
70 ((game_status == GAME_MODE_TITLE &&
71 gfx.cursor_mode == CURSOR_NONE) ||
72 (game_status == GAME_MODE_PLAYING &&
73 gfx.cursor_mode == CURSOR_PLAYFIELD)))
75 SetMouseCursor(CURSOR_DEFAULT);
77 DelayReached(&special_cursor_delay, 0);
79 cursor_mode_last = CURSOR_DEFAULT;
82 /* skip mouse motion events without pressed button outside level editor */
83 if (button_status == MB_RELEASED &&
84 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
90 #if defined(TARGET_SDL2)
91 int FilterEvents(void *userdata, Event *event)
93 return FilterEventsExt(event);
96 int FilterEvents(const Event *event)
98 return FilterEventsExt(event);
102 /* to prevent delay problems, skip mouse motion events if the very next
103 event is also a mouse motion event (and therefore effectively only
104 handling the last of a row of mouse motion events in the event queue) */
106 boolean SkipPressedMouseMotionEvent(const Event *event)
108 /* nothing to do if the current event is not a mouse motion event */
109 if (event->type != EVENT_MOTIONNOTIFY)
112 /* only skip motion events with pressed button outside the game */
113 if (button_status == MB_RELEASED || game_status == GAME_MODE_PLAYING)
120 PeekEvent(&next_event);
122 /* if next event is also a mouse motion event, skip the current one */
123 if (next_event.type == EVENT_MOTIONNOTIFY)
130 /* this is only really needed for non-SDL targets to filter unwanted events;
131 when using SDL with properly installed event filter, this function can be
132 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
134 boolean NextValidEvent(Event *event)
136 while (PendingEvent())
138 boolean handle_this_event = FALSE;
142 if (FilterEventsExt(event))
143 handle_this_event = TRUE;
145 if (SkipPressedMouseMotionEvent(event))
146 handle_this_event = FALSE;
148 if (handle_this_event)
159 if (PendingEvent()) /* got event */
163 while (NextValidEvent(&event))
167 case EVENT_BUTTONPRESS:
168 case EVENT_BUTTONRELEASE:
169 HandleButtonEvent((ButtonEvent *) &event);
172 case EVENT_MOTIONNOTIFY:
173 HandleMotionEvent((MotionEvent *) &event);
176 #if defined(TARGET_SDL2)
177 case SDL_WINDOWEVENT:
178 HandleWindowEvent((WindowEvent *) &event);
181 case EVENT_FINGERPRESS:
182 case EVENT_FINGERRELEASE:
183 case EVENT_FINGERMOTION:
184 HandleFingerEvent((FingerEvent *) &event);
187 case EVENT_TEXTINPUT:
188 HandleTextEvent((TextEvent *) &event);
191 case SDL_APP_WILLENTERBACKGROUND:
192 case SDL_APP_DIDENTERBACKGROUND:
193 case SDL_APP_WILLENTERFOREGROUND:
194 case SDL_APP_DIDENTERFOREGROUND:
195 HandlePauseResumeEvent((PauseResumeEvent *) &event);
200 case EVENT_KEYRELEASE:
201 HandleKeyEvent((KeyEvent *) &event);
205 HandleOtherEvents(&event);
212 if (game_status == GAME_MODE_TITLE)
214 /* when showing title screens, hide mouse pointer (if not moved) */
216 if (gfx.cursor_mode != CURSOR_NONE &&
217 DelayReached(&special_cursor_delay, special_cursor_delay_value))
219 SetMouseCursor(CURSOR_NONE);
222 else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
225 /* when playing, display a special mouse pointer inside the playfield */
227 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
228 cursor_inside_playfield &&
229 DelayReached(&special_cursor_delay, special_cursor_delay_value))
231 SetMouseCursor(CURSOR_PLAYFIELD);
234 else if (gfx.cursor_mode != CURSOR_DEFAULT)
236 SetMouseCursor(CURSOR_DEFAULT);
239 /* this is set after all pending events have been processed */
240 cursor_mode_last = gfx.cursor_mode;
243 /* also execute after pending events have been processed before */
246 /* don't use all CPU time when idle; the main loop while playing
247 has its own synchronization and is CPU friendly, too */
249 if (game_status == GAME_MODE_PLAYING)
255 if (!PendingEvent()) /* delay only if no pending events */
259 /* refresh window contents from drawing buffer, if needed */
262 if (game_status == GAME_MODE_QUIT)
267 void HandleOtherEvents(Event *event)
272 HandleExposeEvent((ExposeEvent *) event);
275 case EVENT_UNMAPNOTIFY:
277 /* This causes the game to stop not only when iconified, but also
278 when on another virtual desktop, which might be not desired. */
279 SleepWhileUnmapped();
285 HandleFocusEvent((FocusChangeEvent *) event);
288 case EVENT_CLIENTMESSAGE:
289 HandleClientMessageEvent((ClientMessageEvent *) event);
292 #if defined(TARGET_SDL)
293 case SDL_JOYAXISMOTION:
294 case SDL_JOYBUTTONDOWN:
295 case SDL_JOYBUTTONUP:
296 HandleJoystickEvent(event);
300 HandleWindowManagerEvent(event);
309 void ClearEventQueue()
311 while (PendingEvent())
319 case EVENT_BUTTONRELEASE:
320 button_status = MB_RELEASED;
323 case EVENT_KEYRELEASE:
328 HandleOtherEvents(&event);
334 void ClearPlayerAction()
338 /* simulate key release events for still pressed keys */
339 key_joystick_mapping = 0;
340 for (i = 0; i < MAX_PLAYERS; i++)
341 stored_player[i].action = 0;
344 void SleepWhileUnmapped()
346 boolean window_unmapped = TRUE;
348 KeyboardAutoRepeatOn();
350 while (window_unmapped)
358 case EVENT_BUTTONRELEASE:
359 button_status = MB_RELEASED;
362 case EVENT_KEYRELEASE:
363 key_joystick_mapping = 0;
366 case EVENT_MAPNOTIFY:
367 window_unmapped = FALSE;
370 case EVENT_UNMAPNOTIFY:
371 /* this is only to surely prevent the 'should not happen' case
372 * of recursively looping between 'SleepWhileUnmapped()' and
373 * 'HandleOtherEvents()' which usually calls this funtion.
378 HandleOtherEvents(&event);
383 if (game_status == GAME_MODE_PLAYING)
384 KeyboardAutoRepeatOffUnlessAutoplay();
387 void HandleExposeEvent(ExposeEvent *event)
391 void HandleButtonEvent(ButtonEvent *event)
393 #if DEBUG_EVENTS_BUTTON
394 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
396 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
400 motion_status = FALSE;
402 if (event->type == EVENT_BUTTONPRESS)
403 button_status = event->button;
405 button_status = MB_RELEASED;
407 HandleButton(event->x, event->y, button_status, event->button);
410 void HandleMotionEvent(MotionEvent *event)
412 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
415 motion_status = TRUE;
417 #if DEBUG_EVENTS_MOTION
418 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
419 button_status, event->x, event->y);
422 HandleButton(event->x, event->y, button_status, button_status);
425 #if defined(TARGET_SDL2)
427 void HandleWindowEvent(WindowEvent *event)
429 #if DEBUG_EVENTS_WINDOW
430 int subtype = event->event;
433 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
434 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
435 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
436 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
437 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
438 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
439 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
440 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
441 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
442 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
443 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
444 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
445 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
446 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
449 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
450 event_name, event->data1, event->data2);
453 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
454 event->event == SDL_WINDOWEVENT_RESIZED ||
455 event->event == SDL_WINDOWEVENT_EXPOSED)
458 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
460 int new_window_width = event->data1;
461 int new_window_height = event->data2;
463 // if window size has changed after resizing, calculate new scaling factor
464 if (new_window_width != video.window_width ||
465 new_window_height != video.window_height)
467 int new_xpercent = (100 * new_window_width / video.width);
468 int new_ypercent = (100 * new_window_height / video.height);
470 setup.window_scaling_percent = video.window_scaling_percent =
471 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
472 MAX_WINDOW_SCALING_PERCENT);
474 video.window_width = new_window_width;
475 video.window_height = new_window_height;
477 if (game_status == GAME_MODE_SETUP)
478 RedrawSetupScreenAfterFullscreenToggle();
485 #define NUM_TOUCH_FINGERS 3
490 SDL_FingerID finger_id;
493 } touch_info[NUM_TOUCH_FINGERS];
495 void HandleFingerEvent(FingerEvent *event)
497 static Key motion_key_x = KSYM_UNDEFINED;
498 static Key motion_key_y = KSYM_UNDEFINED;
499 static Key button_key = KSYM_UNDEFINED;
500 static float motion_x1, motion_y1;
501 static float button_x1, button_y1;
502 static SDL_FingerID motion_id = -1;
503 static SDL_FingerID button_id = -1;
504 int move_trigger_distance_percent = 2; // percent of touchpad width/height
505 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
506 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
507 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
508 float event_x = event->x;
509 float event_y = event->y;
511 #if DEBUG_EVENTS_FINGER
512 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
513 event->type == EVENT_FINGERPRESS ? "pressed" :
514 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
518 event->dx, event->dy,
522 if (game_status != GAME_MODE_PLAYING)
525 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
527 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
529 Key key = (event->x < 1.0 / 3.0 ?
530 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
531 setup.input[0].key.drop) :
532 event->x > 2.0 / 3.0 ?
533 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
534 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
535 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
536 setup.input[0].key.right) :
538 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
542 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
543 getKeyNameFromKey(key), key_status_name, event->fingerId);
545 // check if we already know this touch event's finger id
546 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
548 if (touch_info[i].touched &&
549 touch_info[i].finger_id == event->fingerId)
551 // Error(ERR_DEBUG, "MARK 1: %d", i);
557 if (i >= NUM_TOUCH_FINGERS)
559 if (key_status == KEY_PRESSED)
561 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
563 // unknown finger id -- get new, empty slot, if available
564 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
566 if (touch_info[i].counter < oldest_counter)
569 oldest_counter = touch_info[i].counter;
571 // Error(ERR_DEBUG, "MARK 2: %d", i);
574 if (!touch_info[i].touched)
576 // Error(ERR_DEBUG, "MARK 3: %d", i);
582 if (i >= NUM_TOUCH_FINGERS)
584 // all slots allocated -- use oldest slot
587 // Error(ERR_DEBUG, "MARK 4: %d", i);
592 // release of previously unknown key (should not happen)
594 if (key != KSYM_UNDEFINED)
596 HandleKey(key, KEY_RELEASED);
598 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
599 getKeyNameFromKey(key), "KEY_RELEASED", i);
604 if (i < NUM_TOUCH_FINGERS)
606 if (key_status == KEY_PRESSED)
608 if (touch_info[i].key != key)
610 if (touch_info[i].key != KSYM_UNDEFINED)
612 HandleKey(touch_info[i].key, KEY_RELEASED);
614 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
615 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
618 if (key != KSYM_UNDEFINED)
620 HandleKey(key, KEY_PRESSED);
622 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
623 getKeyNameFromKey(key), "KEY_PRESSED", i);
627 touch_info[i].touched = TRUE;
628 touch_info[i].finger_id = event->fingerId;
629 touch_info[i].counter = Counter();
630 touch_info[i].key = key;
634 if (touch_info[i].key != KSYM_UNDEFINED)
636 HandleKey(touch_info[i].key, KEY_RELEASED);
638 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
639 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
642 touch_info[i].touched = FALSE;
643 touch_info[i].finger_id = 0;
644 touch_info[i].counter = 0;
645 touch_info[i].key = 0;
652 // use touch direction control
654 if (event->type == EVENT_FINGERPRESS)
656 if (event_x > 1.0 / 3.0)
660 motion_id = event->fingerId;
665 motion_key_x = KSYM_UNDEFINED;
666 motion_key_y = KSYM_UNDEFINED;
668 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
674 button_id = event->fingerId;
679 button_key = setup.input[0].key.snap;
681 HandleKey(button_key, KEY_PRESSED);
683 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
686 else if (event->type == EVENT_FINGERRELEASE)
688 if (event->fingerId == motion_id)
692 if (motion_key_x != KSYM_UNDEFINED)
693 HandleKey(motion_key_x, KEY_RELEASED);
694 if (motion_key_y != KSYM_UNDEFINED)
695 HandleKey(motion_key_y, KEY_RELEASED);
697 motion_key_x = KSYM_UNDEFINED;
698 motion_key_y = KSYM_UNDEFINED;
700 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
702 else if (event->fingerId == button_id)
706 if (button_key != KSYM_UNDEFINED)
707 HandleKey(button_key, KEY_RELEASED);
709 button_key = KSYM_UNDEFINED;
711 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
714 else if (event->type == EVENT_FINGERMOTION)
716 if (event->fingerId == motion_id)
718 float distance_x = ABS(event_x - motion_x1);
719 float distance_y = ABS(event_y - motion_y1);
720 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
721 event_x > motion_x1 ? setup.input[0].key.right :
723 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
724 event_y > motion_y1 ? setup.input[0].key.down :
727 if (distance_x < move_trigger_distance / 2 ||
728 distance_x < distance_y)
729 new_motion_key_x = KSYM_UNDEFINED;
731 if (distance_y < move_trigger_distance / 2 ||
732 distance_y < distance_x)
733 new_motion_key_y = KSYM_UNDEFINED;
735 if (distance_x > move_trigger_distance ||
736 distance_y > move_trigger_distance)
738 if (new_motion_key_x != motion_key_x)
740 if (motion_key_x != KSYM_UNDEFINED)
741 HandleKey(motion_key_x, KEY_RELEASED);
742 if (new_motion_key_x != KSYM_UNDEFINED)
743 HandleKey(new_motion_key_x, KEY_PRESSED);
746 if (new_motion_key_y != motion_key_y)
748 if (motion_key_y != KSYM_UNDEFINED)
749 HandleKey(motion_key_y, KEY_RELEASED);
750 if (new_motion_key_y != KSYM_UNDEFINED)
751 HandleKey(new_motion_key_y, KEY_PRESSED);
757 motion_key_x = new_motion_key_x;
758 motion_key_y = new_motion_key_y;
760 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
763 else if (event->fingerId == button_id)
765 float distance_x = ABS(event_x - button_x1);
766 float distance_y = ABS(event_y - button_y1);
768 if (distance_x < drop_trigger_distance / 2 &&
769 distance_y > drop_trigger_distance)
771 if (button_key == setup.input[0].key.snap)
772 HandleKey(button_key, KEY_RELEASED);
777 button_key = setup.input[0].key.drop;
779 HandleKey(button_key, KEY_PRESSED);
781 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
787 static boolean checkTextInputKeyModState()
789 // when playing, only handle raw key events and ignore text input
790 if (game_status == GAME_MODE_PLAYING)
793 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
796 void HandleTextEvent(TextEvent *event)
798 char *text = event->text;
799 Key key = getKeyFromKeyName(text);
801 #if DEBUG_EVENTS_TEXT
802 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
805 text[0], (int)(text[0]),
807 getKeyNameFromKey(key),
811 #if defined(PLATFORM_ANDROID)
812 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
814 HandleTypeName(0, key);
820 // only handle key input with text modifier keys pressed
821 if (checkTextInputKeyModState())
823 HandleKey(key, KEY_PRESSED);
824 HandleKey(key, KEY_RELEASED);
828 void HandlePauseResumeEvent(PauseResumeEvent *event)
830 if (event->type == SDL_APP_WILLENTERBACKGROUND)
834 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
842 void HandleKeyEvent(KeyEvent *event)
844 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
845 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
846 Key key = GetEventKey(event, with_modifiers);
847 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
850 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
851 event->type == EVENT_KEYPRESS ? "pressed" : "released",
852 event->keysym.scancode,
857 getKeyNameFromKey(key));
860 #if defined(PLATFORM_ANDROID)
861 // always map the "back" button to the "escape" key on Android devices
862 if (key == KSYM_Back)
866 HandleKeyModState(keymod, key_status);
868 #if defined(TARGET_SDL2)
869 // only handle raw key input without text modifier keys pressed
870 if (!checkTextInputKeyModState())
871 HandleKey(key, key_status);
873 HandleKey(key, key_status);
877 void HandleFocusEvent(FocusChangeEvent *event)
879 static int old_joystick_status = -1;
881 if (event->type == EVENT_FOCUSOUT)
883 KeyboardAutoRepeatOn();
884 old_joystick_status = joystick.status;
885 joystick.status = JOYSTICK_NOT_AVAILABLE;
889 else if (event->type == EVENT_FOCUSIN)
891 /* When there are two Rocks'n'Diamonds windows which overlap and
892 the player moves the pointer from one game window to the other,
893 a 'FocusOut' event is generated for the window the pointer is
894 leaving and a 'FocusIn' event is generated for the window the
895 pointer is entering. In some cases, it can happen that the
896 'FocusIn' event is handled by the one game process before the
897 'FocusOut' event by the other game process. In this case the
898 X11 environment would end up with activated keyboard auto repeat,
899 because unfortunately this is a global setting and not (which
900 would be far better) set for each X11 window individually.
901 The effect would be keyboard auto repeat while playing the game
902 (game_status == GAME_MODE_PLAYING), which is not desired.
903 To avoid this special case, we just wait 1/10 second before
904 processing the 'FocusIn' event.
907 if (game_status == GAME_MODE_PLAYING)
910 KeyboardAutoRepeatOffUnlessAutoplay();
913 if (old_joystick_status != -1)
914 joystick.status = old_joystick_status;
918 void HandleClientMessageEvent(ClientMessageEvent *event)
920 if (CheckCloseWindowEvent(event))
924 void HandleWindowManagerEvent(Event *event)
926 #if defined(TARGET_SDL)
927 SDLHandleWindowManagerEvent(event);
931 void HandleButton(int mx, int my, int button, int button_nr)
933 static int old_mx = 0, old_my = 0;
934 boolean button_hold = FALSE;
949 #if defined(PLATFORM_ANDROID)
950 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
951 if (game_status != GAME_MODE_PLAYING &&
952 HandleGadgets(mx, my, button))
954 /* do not handle this button event anymore */
955 mx = my = -32; /* force mouse event to be outside screen tiles */
958 if (HandleGadgets(mx, my, button))
960 /* do not handle this button event anymore */
961 mx = my = -32; /* force mouse event to be outside screen tiles */
965 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
968 /* do not use scroll wheel button events for anything other than gadgets */
969 if (IS_WHEEL_BUTTON(button_nr))
974 case GAME_MODE_TITLE:
975 HandleTitleScreen(mx, my, 0, 0, button);
979 HandleMainMenu(mx, my, 0, 0, button);
982 case GAME_MODE_PSEUDO_TYPENAME:
983 HandleTypeName(0, KSYM_Return);
986 case GAME_MODE_LEVELS:
987 HandleChooseLevelSet(mx, my, 0, 0, button);
990 case GAME_MODE_LEVELNR:
991 HandleChooseLevelNr(mx, my, 0, 0, button);
994 case GAME_MODE_SCORES:
995 HandleHallOfFame(0, 0, 0, 0, button);
998 case GAME_MODE_EDITOR:
999 HandleLevelEditorIdle();
1002 case GAME_MODE_INFO:
1003 HandleInfoScreen(mx, my, 0, 0, button);
1006 case GAME_MODE_SETUP:
1007 HandleSetupScreen(mx, my, 0, 0, button);
1010 case GAME_MODE_PLAYING:
1012 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1013 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1014 LEVELY((my - SY) / TILESIZE_VAR));
1015 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1024 static boolean is_string_suffix(char *string, char *suffix)
1026 int string_len = strlen(string);
1027 int suffix_len = strlen(suffix);
1029 if (suffix_len > string_len)
1032 return (strEqual(&string[string_len - suffix_len], suffix));
1035 #define MAX_CHEAT_INPUT_LEN 32
1037 static void HandleKeysSpecial(Key key)
1039 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1040 char letter = getCharFromKey(key);
1041 int cheat_input_len = strlen(cheat_input);
1047 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1049 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1050 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1052 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1055 cheat_input[cheat_input_len++] = letter;
1056 cheat_input[cheat_input_len] = '\0';
1058 #if DEBUG_EVENTS_KEY
1059 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1062 if (game_status == GAME_MODE_MAIN)
1064 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1065 is_string_suffix(cheat_input, ":ist"))
1067 InsertSolutionTape();
1069 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1070 is_string_suffix(cheat_input, ":rg"))
1072 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1075 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1076 is_string_suffix(cheat_input, ":rs"))
1078 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1081 else if (is_string_suffix(cheat_input, ":reload-music") ||
1082 is_string_suffix(cheat_input, ":rm"))
1084 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1087 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1088 is_string_suffix(cheat_input, ":ra"))
1090 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1091 1 << ARTWORK_TYPE_SOUNDS |
1092 1 << ARTWORK_TYPE_MUSIC);
1095 else if (is_string_suffix(cheat_input, ":dump-level") ||
1096 is_string_suffix(cheat_input, ":dl"))
1100 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1101 is_string_suffix(cheat_input, ":dt"))
1105 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1106 is_string_suffix(cheat_input, ":ft"))
1108 /* fix single-player tapes that contain player input for more than one
1109 player (due to a bug in 3.3.1.2 and earlier versions), which results
1110 in playing levels with more than one player in multi-player mode,
1111 even though the tape was originally recorded in single-player mode */
1113 /* remove player input actions for all players but the first one */
1114 for (i = 1; i < MAX_PLAYERS; i++)
1115 tape.player_participates[i] = FALSE;
1117 tape.changed = TRUE;
1119 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1120 is_string_suffix(cheat_input, ":snl"))
1122 SaveNativeLevel(&level);
1125 else if (game_status == GAME_MODE_PLAYING)
1128 if (is_string_suffix(cheat_input, ".q"))
1129 DEBUG_SetMaximumDynamite();
1132 else if (game_status == GAME_MODE_EDITOR)
1134 if (is_string_suffix(cheat_input, ":dump-brush") ||
1135 is_string_suffix(cheat_input, ":DB"))
1139 else if (is_string_suffix(cheat_input, ":DDB"))
1146 void HandleKey(Key key, int key_status)
1148 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1149 static struct SetupKeyboardInfo ski;
1150 static struct SetupShortcutInfo ssi;
1159 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1160 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1161 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1162 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1163 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1164 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1169 if (game_status == GAME_MODE_PLAYING)
1171 /* only needed for single-step tape recording mode */
1172 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1173 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1174 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1175 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1178 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1180 byte key_action = 0;
1182 if (setup.input[pnr].use_joystick)
1185 ski = setup.input[pnr].key;
1187 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1188 if (key == *key_info[i].key_custom)
1189 key_action |= key_info[i].action;
1191 /* use combined snap+direction keys for the first player only */
1194 ssi = setup.shortcut;
1196 for (i = 0; i < NUM_DIRECTIONS; i++)
1197 if (key == *key_info[i].key_snap)
1198 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1201 /* clear delayed snap and drop actions in single step mode (see below) */
1202 if (tape.single_step)
1204 if (clear_snap_button[pnr])
1206 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1207 clear_snap_button[pnr] = FALSE;
1210 if (clear_drop_button[pnr])
1212 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1213 clear_drop_button[pnr] = FALSE;
1217 if (key_status == KEY_PRESSED)
1218 stored_player[pnr].action |= key_action;
1220 stored_player[pnr].action &= ~key_action;
1222 if (tape.single_step && tape.recording && tape.pausing)
1224 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1226 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1228 /* if snap key already pressed, don't snap when releasing (below) */
1229 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1230 element_snapped[pnr] = TRUE;
1232 /* if drop key already pressed, don't drop when releasing (below) */
1233 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1234 element_dropped[pnr] = TRUE;
1236 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1238 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1239 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1242 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1243 getRedDiskReleaseFlag_SP() == 0)
1244 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1246 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1249 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1251 if (key_action & KEY_BUTTON_SNAP)
1253 /* if snap key was released without moving (see above), snap now */
1254 if (!element_snapped[pnr])
1256 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1258 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1260 /* clear delayed snap button on next event */
1261 clear_snap_button[pnr] = TRUE;
1264 element_snapped[pnr] = FALSE;
1267 if (key_action & KEY_BUTTON_DROP &&
1268 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1270 /* if drop key was released without moving (see above), drop now */
1271 if (!element_dropped[pnr])
1273 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1275 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1276 getRedDiskReleaseFlag_SP() != 0)
1277 stored_player[pnr].action |= KEY_BUTTON_DROP;
1279 /* clear delayed drop button on next event */
1280 clear_drop_button[pnr] = TRUE;
1283 element_dropped[pnr] = FALSE;
1287 else if (tape.recording && tape.pausing)
1289 /* prevent key release events from un-pausing a paused game */
1290 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1291 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1297 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1298 if (key == key_info[i].key_default)
1299 joy |= key_info[i].action;
1304 if (key_status == KEY_PRESSED)
1305 key_joystick_mapping |= joy;
1307 key_joystick_mapping &= ~joy;
1312 if (game_status != GAME_MODE_PLAYING)
1313 key_joystick_mapping = 0;
1315 if (key_status == KEY_RELEASED)
1318 if ((key == KSYM_F11 ||
1319 ((key == KSYM_Return ||
1320 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1321 video.fullscreen_available)
1323 setup.fullscreen = !setup.fullscreen;
1325 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1327 if (game_status == GAME_MODE_SETUP)
1328 RedrawSetupScreenAfterFullscreenToggle();
1333 if ((key == KSYM_minus ||
1336 ((GetKeyModState() & KMOD_Control) ||
1337 (GetKeyModState() & KMOD_Alt)) &&
1338 video.window_scaling_available &&
1339 !video.fullscreen_enabled)
1342 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1344 setup.window_scaling_percent +=
1345 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1347 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1348 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1349 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1350 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1352 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1354 if (game_status == GAME_MODE_SETUP)
1355 RedrawSetupScreenAfterFullscreenToggle();
1360 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1361 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1368 if (game_status == GAME_MODE_MAIN &&
1369 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1371 StartGameActions(options.network, setup.autorecord, level.random_seed);
1376 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1378 if (key == setup.shortcut.save_game)
1380 else if (key == setup.shortcut.load_game)
1382 else if (key == setup.shortcut.toggle_pause)
1383 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1385 HandleTapeButtonKeys(key);
1386 HandleSoundButtonKeys(key);
1389 if (game_status == GAME_MODE_PLAYING && !network_playing)
1391 int centered_player_nr_next = -999;
1393 if (key == setup.shortcut.focus_player_all)
1394 centered_player_nr_next = -1;
1396 for (i = 0; i < MAX_PLAYERS; i++)
1397 if (key == setup.shortcut.focus_player[i])
1398 centered_player_nr_next = i;
1400 if (centered_player_nr_next != -999)
1402 game.centered_player_nr_next = centered_player_nr_next;
1403 game.set_centered_player = TRUE;
1407 tape.centered_player_nr_next = game.centered_player_nr_next;
1408 tape.set_centered_player = TRUE;
1413 HandleKeysSpecial(key);
1415 if (HandleGadgetsKeyInput(key))
1417 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1418 key = KSYM_UNDEFINED;
1421 switch (game_status)
1423 case GAME_MODE_PSEUDO_TYPENAME:
1424 HandleTypeName(0, key);
1427 case GAME_MODE_TITLE:
1428 case GAME_MODE_MAIN:
1429 case GAME_MODE_LEVELS:
1430 case GAME_MODE_LEVELNR:
1431 case GAME_MODE_SETUP:
1432 case GAME_MODE_INFO:
1433 case GAME_MODE_SCORES:
1438 if (game_status == GAME_MODE_TITLE)
1439 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1440 else if (game_status == GAME_MODE_MAIN)
1441 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1442 else if (game_status == GAME_MODE_LEVELS)
1443 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1444 else if (game_status == GAME_MODE_LEVELNR)
1445 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1446 else if (game_status == GAME_MODE_SETUP)
1447 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1448 else if (game_status == GAME_MODE_INFO)
1449 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1450 else if (game_status == GAME_MODE_SCORES)
1451 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1455 if (game_status != GAME_MODE_MAIN)
1456 FadeSkipNextFadeIn();
1458 if (game_status == GAME_MODE_TITLE)
1459 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1460 else if (game_status == GAME_MODE_LEVELS)
1461 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1462 else if (game_status == GAME_MODE_LEVELNR)
1463 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1464 else if (game_status == GAME_MODE_SETUP)
1465 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1466 else if (game_status == GAME_MODE_INFO)
1467 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1468 else if (game_status == GAME_MODE_SCORES)
1469 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1473 if (game_status == GAME_MODE_LEVELS)
1474 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1475 else if (game_status == GAME_MODE_LEVELNR)
1476 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1477 else if (game_status == GAME_MODE_SETUP)
1478 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1479 else if (game_status == GAME_MODE_INFO)
1480 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1481 else if (game_status == GAME_MODE_SCORES)
1482 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1485 case KSYM_Page_Down:
1486 if (game_status == GAME_MODE_LEVELS)
1487 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1488 else if (game_status == GAME_MODE_LEVELNR)
1489 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1490 else if (game_status == GAME_MODE_SETUP)
1491 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1492 else if (game_status == GAME_MODE_INFO)
1493 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1494 else if (game_status == GAME_MODE_SCORES)
1495 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1500 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1504 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1505 printf("Supaplex border elements %s\n",
1506 setup.sp_show_border_elements ? "enabled" : "disabled");
1515 case GAME_MODE_EDITOR:
1516 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1517 HandleLevelEditorKeyInput(key);
1520 case GAME_MODE_PLAYING:
1525 RequestQuitGame(setup.ask_on_escape);
1532 if (GameFrameDelay == 500)
1533 GameFrameDelay = GAME_FRAME_DELAY;
1535 GameFrameDelay = 500;
1538 GameFrameDelay = (key - KSYM_0) * 10;
1539 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1540 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1546 options.debug = FALSE;
1547 printf("debug mode disabled\n");
1551 options.debug = TRUE;
1552 printf("debug mode enabled\n");
1557 printf("::: currently using game engine version %d\n",
1558 game.engine_version);
1569 if (key == KSYM_Escape)
1571 game_status = GAME_MODE_MAIN;
1579 void HandleNoEvent()
1581 // if (button_status && game_status != GAME_MODE_PLAYING)
1582 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1584 HandleButton(0, 0, -button_status, button_status);
1591 #if defined(NETWORK_AVALIABLE)
1592 if (options.network)
1596 switch (game_status)
1598 case GAME_MODE_MAIN:
1599 DrawPreviewLevelAnimation();
1603 case GAME_MODE_LEVELS:
1604 case GAME_MODE_LEVELNR:
1605 case GAME_MODE_SETUP:
1606 case GAME_MODE_INFO:
1607 case GAME_MODE_SCORES:
1611 case GAME_MODE_EDITOR:
1612 HandleLevelEditorIdle();
1620 static int HandleJoystickForAllPlayers()
1625 for (i = 0; i < MAX_PLAYERS; i++)
1627 byte joy_action = 0;
1630 if (!setup.input[i].use_joystick)
1634 joy_action = Joystick(i);
1635 result |= joy_action;
1637 if (!setup.input[i].use_joystick)
1640 stored_player[i].action = joy_action;
1646 void HandleJoystick()
1648 int joystick = HandleJoystickForAllPlayers();
1649 int keyboard = key_joystick_mapping;
1650 int joy = (joystick | keyboard);
1651 int left = joy & JOY_LEFT;
1652 int right = joy & JOY_RIGHT;
1653 int up = joy & JOY_UP;
1654 int down = joy & JOY_DOWN;
1655 int button = joy & JOY_BUTTON;
1656 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1657 int dx = (left ? -1 : right ? 1 : 0);
1658 int dy = (up ? -1 : down ? 1 : 0);
1660 switch (game_status)
1662 case GAME_MODE_TITLE:
1663 case GAME_MODE_MAIN:
1664 case GAME_MODE_LEVELS:
1665 case GAME_MODE_LEVELNR:
1666 case GAME_MODE_SETUP:
1667 case GAME_MODE_INFO:
1669 static unsigned int joystickmove_delay = 0;
1671 if (joystick && !button &&
1672 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1673 newbutton = dx = dy = 0;
1675 if (game_status == GAME_MODE_TITLE)
1676 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1677 else if (game_status == GAME_MODE_MAIN)
1678 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1679 else if (game_status == GAME_MODE_LEVELS)
1680 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1681 else if (game_status == GAME_MODE_LEVELNR)
1682 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1683 else if (game_status == GAME_MODE_SETUP)
1684 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1685 else if (game_status == GAME_MODE_INFO)
1686 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1690 case GAME_MODE_SCORES:
1691 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1694 case GAME_MODE_PLAYING:
1695 if (tape.playing || keyboard)
1696 newbutton = ((joy & JOY_BUTTON) != 0);
1698 if (newbutton && AllPlayersGone)