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)
157 static unsigned int sync_frame_delay = 0;
158 unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
162 if (PendingEvent()) /* got event */
166 while (NextValidEvent(&event))
170 case EVENT_BUTTONPRESS:
171 case EVENT_BUTTONRELEASE:
172 HandleButtonEvent((ButtonEvent *) &event);
175 case EVENT_MOTIONNOTIFY:
176 HandleMotionEvent((MotionEvent *) &event);
179 #if defined(TARGET_SDL2)
180 case SDL_WINDOWEVENT:
181 HandleWindowEvent((WindowEvent *) &event);
184 case EVENT_FINGERPRESS:
185 case EVENT_FINGERRELEASE:
186 case EVENT_FINGERMOTION:
187 HandleFingerEvent((FingerEvent *) &event);
190 case EVENT_TEXTINPUT:
191 HandleTextEvent((TextEvent *) &event);
194 case SDL_APP_WILLENTERBACKGROUND:
195 case SDL_APP_DIDENTERBACKGROUND:
196 case SDL_APP_WILLENTERFOREGROUND:
197 case SDL_APP_DIDENTERFOREGROUND:
198 HandlePauseResumeEvent((PauseResumeEvent *) &event);
203 case EVENT_KEYRELEASE:
204 HandleKeyEvent((KeyEvent *) &event);
208 HandleOtherEvents(&event);
215 if (game_status == GAME_MODE_TITLE)
217 /* when showing title screens, hide mouse pointer (if not moved) */
219 if (gfx.cursor_mode != CURSOR_NONE &&
220 DelayReached(&special_cursor_delay, special_cursor_delay_value))
222 SetMouseCursor(CURSOR_NONE);
225 else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
228 /* when playing, display a special mouse pointer inside the playfield */
230 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
231 cursor_inside_playfield &&
232 DelayReached(&special_cursor_delay, special_cursor_delay_value))
234 SetMouseCursor(CURSOR_PLAYFIELD);
237 else if (gfx.cursor_mode != CURSOR_DEFAULT)
239 SetMouseCursor(CURSOR_DEFAULT);
242 /* this is set after all pending events have been processed */
243 cursor_mode_last = gfx.cursor_mode;
246 /* also execute after pending events have been processed before */
249 /* don't use all CPU time when idle; the main loop while playing
250 has its own synchronization and is CPU friendly, too */
252 if (game_status == GAME_MODE_PLAYING)
255 /* refresh window contents from drawing buffer, if needed */
258 if (game_status != GAME_MODE_PLAYING)
259 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
261 if (game_status == GAME_MODE_QUIT)
266 void HandleOtherEvents(Event *event)
271 HandleExposeEvent((ExposeEvent *) event);
274 case EVENT_UNMAPNOTIFY:
276 /* This causes the game to stop not only when iconified, but also
277 when on another virtual desktop, which might be not desired. */
278 SleepWhileUnmapped();
284 HandleFocusEvent((FocusChangeEvent *) event);
287 case EVENT_CLIENTMESSAGE:
288 HandleClientMessageEvent((ClientMessageEvent *) event);
291 #if defined(TARGET_SDL)
292 case SDL_JOYAXISMOTION:
293 case SDL_JOYBUTTONDOWN:
294 case SDL_JOYBUTTONUP:
295 HandleJoystickEvent(event);
299 HandleWindowManagerEvent(event);
308 void ClearEventQueue()
310 while (PendingEvent())
318 case EVENT_BUTTONRELEASE:
319 button_status = MB_RELEASED;
322 case EVENT_KEYRELEASE:
327 HandleOtherEvents(&event);
333 void ClearPlayerAction()
337 /* simulate key release events for still pressed keys */
338 key_joystick_mapping = 0;
339 for (i = 0; i < MAX_PLAYERS; i++)
340 stored_player[i].action = 0;
343 void SleepWhileUnmapped()
345 boolean window_unmapped = TRUE;
347 KeyboardAutoRepeatOn();
349 while (window_unmapped)
357 case EVENT_BUTTONRELEASE:
358 button_status = MB_RELEASED;
361 case EVENT_KEYRELEASE:
362 key_joystick_mapping = 0;
365 case EVENT_MAPNOTIFY:
366 window_unmapped = FALSE;
369 case EVENT_UNMAPNOTIFY:
370 /* this is only to surely prevent the 'should not happen' case
371 * of recursively looping between 'SleepWhileUnmapped()' and
372 * 'HandleOtherEvents()' which usually calls this funtion.
377 HandleOtherEvents(&event);
382 if (game_status == GAME_MODE_PLAYING)
383 KeyboardAutoRepeatOffUnlessAutoplay();
386 void HandleExposeEvent(ExposeEvent *event)
390 void HandleButtonEvent(ButtonEvent *event)
392 #if DEBUG_EVENTS_BUTTON
393 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
395 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
399 motion_status = FALSE;
401 if (event->type == EVENT_BUTTONPRESS)
402 button_status = event->button;
404 button_status = MB_RELEASED;
406 HandleButton(event->x, event->y, button_status, event->button);
409 void HandleMotionEvent(MotionEvent *event)
411 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
414 motion_status = TRUE;
416 #if DEBUG_EVENTS_MOTION
417 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
418 button_status, event->x, event->y);
421 HandleButton(event->x, event->y, button_status, button_status);
424 #if defined(TARGET_SDL2)
426 void HandleWindowEvent(WindowEvent *event)
428 #if DEBUG_EVENTS_WINDOW
429 int subtype = event->event;
432 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
433 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
434 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
435 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
436 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
437 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
438 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
439 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
440 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
441 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
442 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
443 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
444 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
445 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
448 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
449 event_name, event->data1, event->data2);
452 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
453 event->event == SDL_WINDOWEVENT_RESIZED ||
454 event->event == SDL_WINDOWEVENT_EXPOSED)
457 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
459 int new_window_width = event->data1;
460 int new_window_height = event->data2;
462 // if window size has changed after resizing, calculate new scaling factor
463 if (new_window_width != video.window_width ||
464 new_window_height != video.window_height)
466 int new_xpercent = (100 * new_window_width / video.width);
467 int new_ypercent = (100 * new_window_height / video.height);
469 setup.window_scaling_percent = video.window_scaling_percent =
470 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
471 MAX_WINDOW_SCALING_PERCENT);
473 video.window_width = new_window_width;
474 video.window_height = new_window_height;
476 if (game_status == GAME_MODE_SETUP)
477 RedrawSetupScreenAfterFullscreenToggle();
484 #define NUM_TOUCH_FINGERS 3
489 SDL_FingerID finger_id;
492 } touch_info[NUM_TOUCH_FINGERS];
494 void HandleFingerEvent(FingerEvent *event)
496 static Key motion_key_x = KSYM_UNDEFINED;
497 static Key motion_key_y = KSYM_UNDEFINED;
498 static Key button_key = KSYM_UNDEFINED;
499 static float motion_x1, motion_y1;
500 static float button_x1, button_y1;
501 static SDL_FingerID motion_id = -1;
502 static SDL_FingerID button_id = -1;
503 int move_trigger_distance_percent = 2; // percent of touchpad width/height
504 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
505 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
506 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
507 float event_x = event->x;
508 float event_y = event->y;
510 #if DEBUG_EVENTS_FINGER
511 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
512 event->type == EVENT_FINGERPRESS ? "pressed" :
513 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
517 event->dx, event->dy,
521 if (game_status != GAME_MODE_PLAYING)
524 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
526 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
528 Key key = (event->x < 1.0 / 3.0 ?
529 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
530 setup.input[0].key.drop) :
531 event->x > 2.0 / 3.0 ?
532 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
533 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
534 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
535 setup.input[0].key.right) :
537 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
541 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
542 getKeyNameFromKey(key), key_status_name, event->fingerId);
544 // check if we already know this touch event's finger id
545 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
547 if (touch_info[i].touched &&
548 touch_info[i].finger_id == event->fingerId)
550 // Error(ERR_DEBUG, "MARK 1: %d", i);
556 if (i >= NUM_TOUCH_FINGERS)
558 if (key_status == KEY_PRESSED)
560 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
562 // unknown finger id -- get new, empty slot, if available
563 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
565 if (touch_info[i].counter < oldest_counter)
568 oldest_counter = touch_info[i].counter;
570 // Error(ERR_DEBUG, "MARK 2: %d", i);
573 if (!touch_info[i].touched)
575 // Error(ERR_DEBUG, "MARK 3: %d", i);
581 if (i >= NUM_TOUCH_FINGERS)
583 // all slots allocated -- use oldest slot
586 // Error(ERR_DEBUG, "MARK 4: %d", i);
591 // release of previously unknown key (should not happen)
593 if (key != KSYM_UNDEFINED)
595 HandleKey(key, KEY_RELEASED);
597 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
598 getKeyNameFromKey(key), "KEY_RELEASED", i);
603 if (i < NUM_TOUCH_FINGERS)
605 if (key_status == KEY_PRESSED)
607 if (touch_info[i].key != key)
609 if (touch_info[i].key != KSYM_UNDEFINED)
611 HandleKey(touch_info[i].key, KEY_RELEASED);
613 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
614 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
617 if (key != KSYM_UNDEFINED)
619 HandleKey(key, KEY_PRESSED);
621 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
622 getKeyNameFromKey(key), "KEY_PRESSED", i);
626 touch_info[i].touched = TRUE;
627 touch_info[i].finger_id = event->fingerId;
628 touch_info[i].counter = Counter();
629 touch_info[i].key = key;
633 if (touch_info[i].key != KSYM_UNDEFINED)
635 HandleKey(touch_info[i].key, KEY_RELEASED);
637 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
638 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
641 touch_info[i].touched = FALSE;
642 touch_info[i].finger_id = 0;
643 touch_info[i].counter = 0;
644 touch_info[i].key = 0;
651 // use touch direction control
653 if (event->type == EVENT_FINGERPRESS)
655 if (event_x > 1.0 / 3.0)
659 motion_id = event->fingerId;
664 motion_key_x = KSYM_UNDEFINED;
665 motion_key_y = KSYM_UNDEFINED;
667 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
673 button_id = event->fingerId;
678 button_key = setup.input[0].key.snap;
680 HandleKey(button_key, KEY_PRESSED);
682 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
685 else if (event->type == EVENT_FINGERRELEASE)
687 if (event->fingerId == motion_id)
691 if (motion_key_x != KSYM_UNDEFINED)
692 HandleKey(motion_key_x, KEY_RELEASED);
693 if (motion_key_y != KSYM_UNDEFINED)
694 HandleKey(motion_key_y, KEY_RELEASED);
696 motion_key_x = KSYM_UNDEFINED;
697 motion_key_y = KSYM_UNDEFINED;
699 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
701 else if (event->fingerId == button_id)
705 if (button_key != KSYM_UNDEFINED)
706 HandleKey(button_key, KEY_RELEASED);
708 button_key = KSYM_UNDEFINED;
710 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
713 else if (event->type == EVENT_FINGERMOTION)
715 if (event->fingerId == motion_id)
717 float distance_x = ABS(event_x - motion_x1);
718 float distance_y = ABS(event_y - motion_y1);
719 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
720 event_x > motion_x1 ? setup.input[0].key.right :
722 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
723 event_y > motion_y1 ? setup.input[0].key.down :
726 if (distance_x < move_trigger_distance / 2 ||
727 distance_x < distance_y)
728 new_motion_key_x = KSYM_UNDEFINED;
730 if (distance_y < move_trigger_distance / 2 ||
731 distance_y < distance_x)
732 new_motion_key_y = KSYM_UNDEFINED;
734 if (distance_x > move_trigger_distance ||
735 distance_y > move_trigger_distance)
737 if (new_motion_key_x != motion_key_x)
739 if (motion_key_x != KSYM_UNDEFINED)
740 HandleKey(motion_key_x, KEY_RELEASED);
741 if (new_motion_key_x != KSYM_UNDEFINED)
742 HandleKey(new_motion_key_x, KEY_PRESSED);
745 if (new_motion_key_y != motion_key_y)
747 if (motion_key_y != KSYM_UNDEFINED)
748 HandleKey(motion_key_y, KEY_RELEASED);
749 if (new_motion_key_y != KSYM_UNDEFINED)
750 HandleKey(new_motion_key_y, KEY_PRESSED);
756 motion_key_x = new_motion_key_x;
757 motion_key_y = new_motion_key_y;
759 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
762 else if (event->fingerId == button_id)
764 float distance_x = ABS(event_x - button_x1);
765 float distance_y = ABS(event_y - button_y1);
767 if (distance_x < drop_trigger_distance / 2 &&
768 distance_y > drop_trigger_distance)
770 if (button_key == setup.input[0].key.snap)
771 HandleKey(button_key, KEY_RELEASED);
776 button_key = setup.input[0].key.drop;
778 HandleKey(button_key, KEY_PRESSED);
780 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
786 static boolean checkTextInputKeyModState()
788 // when playing, only handle raw key events and ignore text input
789 if (game_status == GAME_MODE_PLAYING)
792 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
795 void HandleTextEvent(TextEvent *event)
797 char *text = event->text;
798 Key key = getKeyFromKeyName(text);
800 #if DEBUG_EVENTS_TEXT
801 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
804 text[0], (int)(text[0]),
806 getKeyNameFromKey(key),
810 #if defined(PLATFORM_ANDROID)
811 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
813 HandleTypeName(0, key);
819 // only handle key input with text modifier keys pressed
820 if (checkTextInputKeyModState())
822 HandleKey(key, KEY_PRESSED);
823 HandleKey(key, KEY_RELEASED);
827 void HandlePauseResumeEvent(PauseResumeEvent *event)
829 if (event->type == SDL_APP_WILLENTERBACKGROUND)
833 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
841 void HandleKeyEvent(KeyEvent *event)
843 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
844 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
845 Key key = GetEventKey(event, with_modifiers);
846 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
849 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
850 event->type == EVENT_KEYPRESS ? "pressed" : "released",
851 event->keysym.scancode,
856 getKeyNameFromKey(key));
859 #if defined(PLATFORM_ANDROID)
860 // always map the "back" button to the "escape" key on Android devices
861 if (key == KSYM_Back)
865 HandleKeyModState(keymod, key_status);
867 #if defined(TARGET_SDL2)
868 // only handle raw key input without text modifier keys pressed
869 if (!checkTextInputKeyModState())
870 HandleKey(key, key_status);
872 HandleKey(key, key_status);
876 void HandleFocusEvent(FocusChangeEvent *event)
878 static int old_joystick_status = -1;
880 if (event->type == EVENT_FOCUSOUT)
882 KeyboardAutoRepeatOn();
883 old_joystick_status = joystick.status;
884 joystick.status = JOYSTICK_NOT_AVAILABLE;
888 else if (event->type == EVENT_FOCUSIN)
890 /* When there are two Rocks'n'Diamonds windows which overlap and
891 the player moves the pointer from one game window to the other,
892 a 'FocusOut' event is generated for the window the pointer is
893 leaving and a 'FocusIn' event is generated for the window the
894 pointer is entering. In some cases, it can happen that the
895 'FocusIn' event is handled by the one game process before the
896 'FocusOut' event by the other game process. In this case the
897 X11 environment would end up with activated keyboard auto repeat,
898 because unfortunately this is a global setting and not (which
899 would be far better) set for each X11 window individually.
900 The effect would be keyboard auto repeat while playing the game
901 (game_status == GAME_MODE_PLAYING), which is not desired.
902 To avoid this special case, we just wait 1/10 second before
903 processing the 'FocusIn' event.
906 if (game_status == GAME_MODE_PLAYING)
909 KeyboardAutoRepeatOffUnlessAutoplay();
912 if (old_joystick_status != -1)
913 joystick.status = old_joystick_status;
917 void HandleClientMessageEvent(ClientMessageEvent *event)
919 if (CheckCloseWindowEvent(event))
923 void HandleWindowManagerEvent(Event *event)
925 #if defined(TARGET_SDL)
926 SDLHandleWindowManagerEvent(event);
930 void HandleButton(int mx, int my, int button, int button_nr)
932 static int old_mx = 0, old_my = 0;
933 boolean button_hold = FALSE;
948 #if defined(PLATFORM_ANDROID)
949 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
950 if (game_status != GAME_MODE_PLAYING &&
951 HandleGadgets(mx, my, button))
953 /* do not handle this button event anymore */
954 mx = my = -32; /* force mouse event to be outside screen tiles */
957 if (HandleGadgets(mx, my, button))
959 /* do not handle this button event anymore */
960 mx = my = -32; /* force mouse event to be outside screen tiles */
964 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
967 /* do not use scroll wheel button events for anything other than gadgets */
968 if (IS_WHEEL_BUTTON(button_nr))
973 case GAME_MODE_TITLE:
974 HandleTitleScreen(mx, my, 0, 0, button);
978 HandleMainMenu(mx, my, 0, 0, button);
981 case GAME_MODE_PSEUDO_TYPENAME:
982 HandleTypeName(0, KSYM_Return);
985 case GAME_MODE_LEVELS:
986 HandleChooseLevelSet(mx, my, 0, 0, button);
989 case GAME_MODE_LEVELNR:
990 HandleChooseLevelNr(mx, my, 0, 0, button);
993 case GAME_MODE_SCORES:
994 HandleHallOfFame(0, 0, 0, 0, button);
997 case GAME_MODE_EDITOR:
998 HandleLevelEditorIdle();
1001 case GAME_MODE_INFO:
1002 HandleInfoScreen(mx, my, 0, 0, button);
1005 case GAME_MODE_SETUP:
1006 HandleSetupScreen(mx, my, 0, 0, button);
1009 case GAME_MODE_PLAYING:
1011 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1012 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1013 LEVELY((my - SY) / TILESIZE_VAR));
1014 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1023 static boolean is_string_suffix(char *string, char *suffix)
1025 int string_len = strlen(string);
1026 int suffix_len = strlen(suffix);
1028 if (suffix_len > string_len)
1031 return (strEqual(&string[string_len - suffix_len], suffix));
1034 #define MAX_CHEAT_INPUT_LEN 32
1036 static void HandleKeysSpecial(Key key)
1038 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1039 char letter = getCharFromKey(key);
1040 int cheat_input_len = strlen(cheat_input);
1046 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1048 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1049 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1051 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1054 cheat_input[cheat_input_len++] = letter;
1055 cheat_input[cheat_input_len] = '\0';
1057 #if DEBUG_EVENTS_KEY
1058 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1061 if (game_status == GAME_MODE_MAIN)
1063 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1064 is_string_suffix(cheat_input, ":ist"))
1066 InsertSolutionTape();
1068 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1069 is_string_suffix(cheat_input, ":rg"))
1071 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1074 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1075 is_string_suffix(cheat_input, ":rs"))
1077 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1080 else if (is_string_suffix(cheat_input, ":reload-music") ||
1081 is_string_suffix(cheat_input, ":rm"))
1083 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1086 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1087 is_string_suffix(cheat_input, ":ra"))
1089 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1090 1 << ARTWORK_TYPE_SOUNDS |
1091 1 << ARTWORK_TYPE_MUSIC);
1094 else if (is_string_suffix(cheat_input, ":dump-level") ||
1095 is_string_suffix(cheat_input, ":dl"))
1099 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1100 is_string_suffix(cheat_input, ":dt"))
1104 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1105 is_string_suffix(cheat_input, ":ft"))
1107 /* fix single-player tapes that contain player input for more than one
1108 player (due to a bug in 3.3.1.2 and earlier versions), which results
1109 in playing levels with more than one player in multi-player mode,
1110 even though the tape was originally recorded in single-player mode */
1112 /* remove player input actions for all players but the first one */
1113 for (i = 1; i < MAX_PLAYERS; i++)
1114 tape.player_participates[i] = FALSE;
1116 tape.changed = TRUE;
1118 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1119 is_string_suffix(cheat_input, ":snl"))
1121 SaveNativeLevel(&level);
1124 else if (game_status == GAME_MODE_PLAYING)
1127 if (is_string_suffix(cheat_input, ".q"))
1128 DEBUG_SetMaximumDynamite();
1131 else if (game_status == GAME_MODE_EDITOR)
1133 if (is_string_suffix(cheat_input, ":dump-brush") ||
1134 is_string_suffix(cheat_input, ":DB"))
1138 else if (is_string_suffix(cheat_input, ":DDB"))
1145 void HandleKey(Key key, int key_status)
1147 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1148 static struct SetupKeyboardInfo ski;
1149 static struct SetupShortcutInfo ssi;
1158 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1159 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1160 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1161 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1162 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1163 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1168 if (game_status == GAME_MODE_PLAYING)
1170 /* only needed for single-step tape recording mode */
1171 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1172 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1173 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1174 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1177 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1179 byte key_action = 0;
1181 if (setup.input[pnr].use_joystick)
1184 ski = setup.input[pnr].key;
1186 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1187 if (key == *key_info[i].key_custom)
1188 key_action |= key_info[i].action;
1190 /* use combined snap+direction keys for the first player only */
1193 ssi = setup.shortcut;
1195 for (i = 0; i < NUM_DIRECTIONS; i++)
1196 if (key == *key_info[i].key_snap)
1197 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1200 /* clear delayed snap and drop actions in single step mode (see below) */
1201 if (tape.single_step)
1203 if (clear_snap_button[pnr])
1205 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1206 clear_snap_button[pnr] = FALSE;
1209 if (clear_drop_button[pnr])
1211 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1212 clear_drop_button[pnr] = FALSE;
1216 if (key_status == KEY_PRESSED)
1217 stored_player[pnr].action |= key_action;
1219 stored_player[pnr].action &= ~key_action;
1221 if (tape.single_step && tape.recording && tape.pausing)
1223 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1225 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1227 /* if snap key already pressed, don't snap when releasing (below) */
1228 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1229 element_snapped[pnr] = TRUE;
1231 /* if drop key already pressed, don't drop when releasing (below) */
1232 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1233 element_dropped[pnr] = TRUE;
1235 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1237 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1238 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1241 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1242 getRedDiskReleaseFlag_SP() == 0)
1243 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1245 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1248 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1250 if (key_action & KEY_BUTTON_SNAP)
1252 /* if snap key was released without moving (see above), snap now */
1253 if (!element_snapped[pnr])
1255 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1257 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1259 /* clear delayed snap button on next event */
1260 clear_snap_button[pnr] = TRUE;
1263 element_snapped[pnr] = FALSE;
1266 if (key_action & KEY_BUTTON_DROP &&
1267 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1269 /* if drop key was released without moving (see above), drop now */
1270 if (!element_dropped[pnr])
1272 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1274 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1275 getRedDiskReleaseFlag_SP() != 0)
1276 stored_player[pnr].action |= KEY_BUTTON_DROP;
1278 /* clear delayed drop button on next event */
1279 clear_drop_button[pnr] = TRUE;
1282 element_dropped[pnr] = FALSE;
1286 else if (tape.recording && tape.pausing)
1288 /* prevent key release events from un-pausing a paused game */
1289 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1290 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1296 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1297 if (key == key_info[i].key_default)
1298 joy |= key_info[i].action;
1303 if (key_status == KEY_PRESSED)
1304 key_joystick_mapping |= joy;
1306 key_joystick_mapping &= ~joy;
1311 if (game_status != GAME_MODE_PLAYING)
1312 key_joystick_mapping = 0;
1314 if (key_status == KEY_RELEASED)
1317 if ((key == KSYM_F11 ||
1318 ((key == KSYM_Return ||
1319 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1320 video.fullscreen_available)
1322 setup.fullscreen = !setup.fullscreen;
1324 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1326 if (game_status == GAME_MODE_SETUP)
1327 RedrawSetupScreenAfterFullscreenToggle();
1332 if ((key == KSYM_minus ||
1335 ((GetKeyModState() & KMOD_Control) ||
1336 (GetKeyModState() & KMOD_Alt)) &&
1337 video.window_scaling_available &&
1338 !video.fullscreen_enabled)
1341 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1343 setup.window_scaling_percent +=
1344 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1346 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1347 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1348 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1349 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1351 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1353 if (game_status == GAME_MODE_SETUP)
1354 RedrawSetupScreenAfterFullscreenToggle();
1359 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1360 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1367 if (game_status == GAME_MODE_MAIN &&
1368 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1370 StartGameActions(options.network, setup.autorecord, level.random_seed);
1375 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1377 if (key == setup.shortcut.save_game)
1379 else if (key == setup.shortcut.load_game)
1381 else if (key == setup.shortcut.toggle_pause)
1382 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1384 HandleTapeButtonKeys(key);
1385 HandleSoundButtonKeys(key);
1388 if (game_status == GAME_MODE_PLAYING && !network_playing)
1390 int centered_player_nr_next = -999;
1392 if (key == setup.shortcut.focus_player_all)
1393 centered_player_nr_next = -1;
1395 for (i = 0; i < MAX_PLAYERS; i++)
1396 if (key == setup.shortcut.focus_player[i])
1397 centered_player_nr_next = i;
1399 if (centered_player_nr_next != -999)
1401 game.centered_player_nr_next = centered_player_nr_next;
1402 game.set_centered_player = TRUE;
1406 tape.centered_player_nr_next = game.centered_player_nr_next;
1407 tape.set_centered_player = TRUE;
1412 HandleKeysSpecial(key);
1414 if (HandleGadgetsKeyInput(key))
1416 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1417 key = KSYM_UNDEFINED;
1420 switch (game_status)
1422 case GAME_MODE_PSEUDO_TYPENAME:
1423 HandleTypeName(0, key);
1426 case GAME_MODE_TITLE:
1427 case GAME_MODE_MAIN:
1428 case GAME_MODE_LEVELS:
1429 case GAME_MODE_LEVELNR:
1430 case GAME_MODE_SETUP:
1431 case GAME_MODE_INFO:
1432 case GAME_MODE_SCORES:
1437 if (game_status == GAME_MODE_TITLE)
1438 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1439 else if (game_status == GAME_MODE_MAIN)
1440 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1441 else if (game_status == GAME_MODE_LEVELS)
1442 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1443 else if (game_status == GAME_MODE_LEVELNR)
1444 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1445 else if (game_status == GAME_MODE_SETUP)
1446 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1447 else if (game_status == GAME_MODE_INFO)
1448 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1449 else if (game_status == GAME_MODE_SCORES)
1450 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1454 if (game_status != GAME_MODE_MAIN)
1455 FadeSkipNextFadeIn();
1457 if (game_status == GAME_MODE_TITLE)
1458 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1459 else if (game_status == GAME_MODE_LEVELS)
1460 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1461 else if (game_status == GAME_MODE_LEVELNR)
1462 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1463 else if (game_status == GAME_MODE_SETUP)
1464 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1465 else if (game_status == GAME_MODE_INFO)
1466 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1467 else if (game_status == GAME_MODE_SCORES)
1468 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1472 if (game_status == GAME_MODE_LEVELS)
1473 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1474 else if (game_status == GAME_MODE_LEVELNR)
1475 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1476 else if (game_status == GAME_MODE_SETUP)
1477 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1478 else if (game_status == GAME_MODE_INFO)
1479 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1480 else if (game_status == GAME_MODE_SCORES)
1481 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1484 case KSYM_Page_Down:
1485 if (game_status == GAME_MODE_LEVELS)
1486 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1487 else if (game_status == GAME_MODE_LEVELNR)
1488 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1489 else if (game_status == GAME_MODE_SETUP)
1490 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1491 else if (game_status == GAME_MODE_INFO)
1492 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1493 else if (game_status == GAME_MODE_SCORES)
1494 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1499 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1503 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1504 printf("Supaplex border elements %s\n",
1505 setup.sp_show_border_elements ? "enabled" : "disabled");
1514 case GAME_MODE_EDITOR:
1515 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1516 HandleLevelEditorKeyInput(key);
1519 case GAME_MODE_PLAYING:
1524 RequestQuitGame(setup.ask_on_escape);
1531 if (GameFrameDelay == 500)
1532 GameFrameDelay = GAME_FRAME_DELAY;
1534 GameFrameDelay = 500;
1537 GameFrameDelay = (key - KSYM_0) * 10;
1538 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1539 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1545 options.debug = FALSE;
1546 printf("debug mode disabled\n");
1550 options.debug = TRUE;
1551 printf("debug mode enabled\n");
1556 printf("::: currently using game engine version %d\n",
1557 game.engine_version);
1568 if (key == KSYM_Escape)
1570 game_status = GAME_MODE_MAIN;
1578 void HandleNoEvent()
1580 // if (button_status && game_status != GAME_MODE_PLAYING)
1581 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1583 HandleButton(0, 0, -button_status, button_status);
1590 #if defined(NETWORK_AVALIABLE)
1591 if (options.network)
1595 switch (game_status)
1597 case GAME_MODE_MAIN:
1598 DrawPreviewLevelAnimation();
1602 case GAME_MODE_LEVELS:
1603 case GAME_MODE_LEVELNR:
1604 case GAME_MODE_SETUP:
1605 case GAME_MODE_INFO:
1606 case GAME_MODE_SCORES:
1610 case GAME_MODE_EDITOR:
1611 HandleLevelEditorIdle();
1619 static int HandleJoystickForAllPlayers()
1624 for (i = 0; i < MAX_PLAYERS; i++)
1626 byte joy_action = 0;
1629 if (!setup.input[i].use_joystick)
1633 joy_action = Joystick(i);
1634 result |= joy_action;
1636 if (!setup.input[i].use_joystick)
1639 stored_player[i].action = joy_action;
1645 void HandleJoystick()
1647 int joystick = HandleJoystickForAllPlayers();
1648 int keyboard = key_joystick_mapping;
1649 int joy = (joystick | keyboard);
1650 int left = joy & JOY_LEFT;
1651 int right = joy & JOY_RIGHT;
1652 int up = joy & JOY_UP;
1653 int down = joy & JOY_DOWN;
1654 int button = joy & JOY_BUTTON;
1655 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1656 int dx = (left ? -1 : right ? 1 : 0);
1657 int dy = (up ? -1 : down ? 1 : 0);
1659 switch (game_status)
1661 case GAME_MODE_TITLE:
1662 case GAME_MODE_MAIN:
1663 case GAME_MODE_LEVELS:
1664 case GAME_MODE_LEVELNR:
1665 case GAME_MODE_SETUP:
1666 case GAME_MODE_INFO:
1668 static unsigned int joystickmove_delay = 0;
1670 if (joystick && !button &&
1671 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1672 newbutton = dx = dy = 0;
1674 if (game_status == GAME_MODE_TITLE)
1675 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1676 else if (game_status == GAME_MODE_MAIN)
1677 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1678 else if (game_status == GAME_MODE_LEVELS)
1679 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1680 else if (game_status == GAME_MODE_LEVELNR)
1681 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1682 else if (game_status == GAME_MODE_SETUP)
1683 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1684 else if (game_status == GAME_MODE_INFO)
1685 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1689 case GAME_MODE_SCORES:
1690 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1693 case GAME_MODE_PLAYING:
1694 if (tape.playing || keyboard)
1695 newbutton = ((joy & JOY_BUTTON) != 0);
1697 if (newbutton && AllPlayersGone)