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_WHEEL (DEBUG_EVENTS * 1)
31 #define DEBUG_EVENTS_WINDOW (DEBUG_EVENTS * 0)
32 #define DEBUG_EVENTS_FINGER (DEBUG_EVENTS * 0)
33 #define DEBUG_EVENTS_TEXT (DEBUG_EVENTS * 1)
34 #define DEBUG_EVENTS_KEY (DEBUG_EVENTS * 1)
37 static boolean cursor_inside_playfield = FALSE;
38 static int cursor_mode_last = CURSOR_DEFAULT;
39 static unsigned int special_cursor_delay = 0;
40 static unsigned int special_cursor_delay_value = 1000;
42 /* event filter especially needed for SDL event filtering due to
43 delay problems with lots of mouse motion events when mouse button
44 not pressed (X11 can handle this with 'PointerMotionHintMask') */
46 /* event filter addition for SDL2: as SDL2 does not have a function to enable
47 or disable keyboard auto-repeat, filter repeated keyboard events instead */
49 static int FilterEventsExt(const Event *event)
53 #if defined(TARGET_SDL2)
54 /* skip repeated key press events if keyboard auto-repeat is disabled */
55 if (event->type == EVENT_KEYPRESS &&
61 /* non-motion events are directly passed to event handler functions */
62 if (event->type != EVENT_MOTIONNOTIFY)
65 motion = (MotionEvent *)event;
66 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
67 motion->y >= SY && motion->y < SY + SYSIZE);
69 /* do no reset mouse cursor before all pending events have been processed */
70 if (gfx.cursor_mode == cursor_mode_last &&
71 ((game_status == GAME_MODE_TITLE &&
72 gfx.cursor_mode == CURSOR_NONE) ||
73 (game_status == GAME_MODE_PLAYING &&
74 gfx.cursor_mode == CURSOR_PLAYFIELD)))
76 SetMouseCursor(CURSOR_DEFAULT);
78 DelayReached(&special_cursor_delay, 0);
80 cursor_mode_last = CURSOR_DEFAULT;
83 /* skip mouse motion events without pressed button outside level editor */
84 if (button_status == MB_RELEASED &&
85 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
91 #if defined(TARGET_SDL2)
92 int FilterEvents(void *userdata, Event *event)
94 return FilterEventsExt(event);
97 int FilterEvents(const Event *event)
99 return FilterEventsExt(event);
103 /* to prevent delay problems, skip mouse motion events if the very next
104 event is also a mouse motion event (and therefore effectively only
105 handling the last of a row of mouse motion events in the event queue) */
107 boolean SkipPressedMouseMotionEvent(const Event *event)
109 /* nothing to do if the current event is not a mouse motion event */
110 if (event->type != EVENT_MOTIONNOTIFY)
113 /* only skip motion events with pressed button outside the game */
114 if (button_status == MB_RELEASED || game_status == GAME_MODE_PLAYING)
121 PeekEvent(&next_event);
123 /* if next event is also a mouse motion event, skip the current one */
124 if (next_event.type == EVENT_MOTIONNOTIFY)
131 /* this is only really needed for non-SDL targets to filter unwanted events;
132 when using SDL with properly installed event filter, this function can be
133 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
135 boolean NextValidEvent(Event *event)
137 while (PendingEvent())
139 boolean handle_this_event = FALSE;
143 if (FilterEventsExt(event))
144 handle_this_event = TRUE;
146 if (SkipPressedMouseMotionEvent(event))
147 handle_this_event = FALSE;
149 if (handle_this_event)
159 unsigned int event_frame_delay = 0;
160 unsigned int event_frame_delay_value = GAME_FRAME_DELAY;
162 ResetDelayCounter(&event_frame_delay);
164 while (NextValidEvent(&event))
168 case EVENT_BUTTONPRESS:
169 case EVENT_BUTTONRELEASE:
170 HandleButtonEvent((ButtonEvent *) &event);
173 case EVENT_MOTIONNOTIFY:
174 HandleMotionEvent((MotionEvent *) &event);
177 #if defined(TARGET_SDL2)
178 case EVENT_WHEELMOTION:
179 HandleWheelEvent((WheelEvent *) &event);
182 case SDL_WINDOWEVENT:
183 HandleWindowEvent((WindowEvent *) &event);
186 case EVENT_FINGERPRESS:
187 case EVENT_FINGERRELEASE:
188 case EVENT_FINGERMOTION:
189 HandleFingerEvent((FingerEvent *) &event);
192 case EVENT_TEXTINPUT:
193 HandleTextEvent((TextEvent *) &event);
196 case SDL_APP_WILLENTERBACKGROUND:
197 case SDL_APP_DIDENTERBACKGROUND:
198 case SDL_APP_WILLENTERFOREGROUND:
199 case SDL_APP_DIDENTERFOREGROUND:
200 HandlePauseResumeEvent((PauseResumeEvent *) &event);
205 case EVENT_KEYRELEASE:
206 HandleKeyEvent((KeyEvent *) &event);
210 HandleOtherEvents(&event);
214 // do not handle events for longer than standard frame delay period
215 if (DelayReached(&event_frame_delay, event_frame_delay_value))
220 void HandleOtherEvents(Event *event)
225 HandleExposeEvent((ExposeEvent *) event);
228 case EVENT_UNMAPNOTIFY:
230 /* This causes the game to stop not only when iconified, but also
231 when on another virtual desktop, which might be not desired. */
232 SleepWhileUnmapped();
238 HandleFocusEvent((FocusChangeEvent *) event);
241 case EVENT_CLIENTMESSAGE:
242 HandleClientMessageEvent((ClientMessageEvent *) event);
245 #if defined(TARGET_SDL)
246 case SDL_JOYAXISMOTION:
247 case SDL_JOYBUTTONDOWN:
248 case SDL_JOYBUTTONUP:
249 HandleJoystickEvent(event);
253 HandleWindowManagerEvent(event);
262 void HandleMouseCursor()
264 if (game_status == GAME_MODE_TITLE)
266 /* when showing title screens, hide mouse pointer (if not moved) */
268 if (gfx.cursor_mode != CURSOR_NONE &&
269 DelayReached(&special_cursor_delay, special_cursor_delay_value))
271 SetMouseCursor(CURSOR_NONE);
274 else if (game_status == GAME_MODE_PLAYING && (!tape.pausing ||
277 /* when playing, display a special mouse pointer inside the playfield */
279 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
280 cursor_inside_playfield &&
281 DelayReached(&special_cursor_delay, special_cursor_delay_value))
283 SetMouseCursor(CURSOR_PLAYFIELD);
286 else if (gfx.cursor_mode != CURSOR_DEFAULT)
288 SetMouseCursor(CURSOR_DEFAULT);
291 /* this is set after all pending events have been processed */
292 cursor_mode_last = gfx.cursor_mode;
304 /* also execute after pending events have been processed before */
307 /* don't use all CPU time when idle; the main loop while playing
308 has its own synchronization and is CPU friendly, too */
310 if (game_status == GAME_MODE_PLAYING)
313 /* always copy backbuffer to visible screen for every video frame */
316 /* reset video frame delay to default (may change again while playing) */
317 SetVideoFrameDelay(MenuFrameDelay);
319 if (game_status == GAME_MODE_QUIT)
324 void ClearEventQueue()
326 while (PendingEvent())
334 case EVENT_BUTTONRELEASE:
335 button_status = MB_RELEASED;
338 case EVENT_KEYRELEASE:
343 HandleOtherEvents(&event);
349 void ClearPlayerAction()
353 /* simulate key release events for still pressed keys */
354 key_joystick_mapping = 0;
355 for (i = 0; i < MAX_PLAYERS; i++)
356 stored_player[i].action = 0;
359 void SleepWhileUnmapped()
361 boolean window_unmapped = TRUE;
363 KeyboardAutoRepeatOn();
365 while (window_unmapped)
373 case EVENT_BUTTONRELEASE:
374 button_status = MB_RELEASED;
377 case EVENT_KEYRELEASE:
378 key_joystick_mapping = 0;
381 case EVENT_MAPNOTIFY:
382 window_unmapped = FALSE;
385 case EVENT_UNMAPNOTIFY:
386 /* this is only to surely prevent the 'should not happen' case
387 * of recursively looping between 'SleepWhileUnmapped()' and
388 * 'HandleOtherEvents()' which usually calls this funtion.
393 HandleOtherEvents(&event);
398 if (game_status == GAME_MODE_PLAYING)
399 KeyboardAutoRepeatOffUnlessAutoplay();
402 void HandleExposeEvent(ExposeEvent *event)
406 void HandleButtonEvent(ButtonEvent *event)
408 #if DEBUG_EVENTS_BUTTON
409 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
411 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
415 motion_status = FALSE;
417 if (event->type == EVENT_BUTTONPRESS)
418 button_status = event->button;
420 button_status = MB_RELEASED;
422 HandleButton(event->x, event->y, button_status, event->button);
425 void HandleMotionEvent(MotionEvent *event)
427 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
430 motion_status = TRUE;
432 #if DEBUG_EVENTS_MOTION
433 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
434 button_status, event->x, event->y);
437 HandleButton(event->x, event->y, button_status, button_status);
440 #if defined(TARGET_SDL2)
442 void HandleWheelEvent(WheelEvent *event)
446 #if DEBUG_EVENTS_WHEEL
448 Error(ERR_DEBUG, "WHEEL EVENT: mouse == %d, x/y == %d/%d\n",
449 event->which, event->x, event->y);
451 // (SDL_MOUSEWHEEL_NORMAL/SDL_MOUSEWHEEL_FLIPPED needs SDL 2.0.4 or newer)
452 Error(ERR_DEBUG, "WHEEL EVENT: mouse == %d, x/y == %d/%d, direction == %s\n",
453 event->which, event->x, event->y,
454 (event->direction == SDL_MOUSEWHEEL_NORMAL ? "SDL_MOUSEWHEEL_NORMAL" :
455 "SDL_MOUSEWHEEL_FLIPPED"));
459 button_nr = (event->x < 0 ? MB_WHEEL_LEFT :
460 event->x > 0 ? MB_WHEEL_RIGHT :
461 event->y < 0 ? MB_WHEEL_DOWN :
462 event->y > 0 ? MB_WHEEL_UP : 0);
464 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX)
465 // accelerated mouse wheel available on Mac and Windows
466 wheel_steps = (event->x ? ABS(event->x) : ABS(event->y));
468 // no accelerated mouse wheel available on Unix/Linux
469 wheel_steps = DEFAULT_WHEEL_STEPS;
472 motion_status = FALSE;
474 button_status = button_nr;
475 HandleButton(0, 0, button_status, -button_nr);
477 button_status = MB_RELEASED;
478 HandleButton(0, 0, button_status, -button_nr);
481 void HandleWindowEvent(WindowEvent *event)
483 #if DEBUG_EVENTS_WINDOW
484 int subtype = event->event;
487 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
488 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
489 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
490 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
491 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
492 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
493 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
494 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
495 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
496 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
497 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
498 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
499 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
500 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
503 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
504 event_name, event->data1, event->data2);
508 // (not needed, as the screen gets redrawn every 20 ms anyway)
509 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
510 event->event == SDL_WINDOWEVENT_RESIZED ||
511 event->event == SDL_WINDOWEVENT_EXPOSED)
515 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
517 int new_window_width = event->data1;
518 int new_window_height = event->data2;
520 // if window size has changed after resizing, calculate new scaling factor
521 if (new_window_width != video.window_width ||
522 new_window_height != video.window_height)
524 int new_xpercent = (100 * new_window_width / video.width);
525 int new_ypercent = (100 * new_window_height / video.height);
527 // (extreme window scaling allowed, but cannot be saved permanently)
528 video.window_scaling_percent = MIN(new_xpercent, new_ypercent);
529 setup.window_scaling_percent =
530 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, video.window_scaling_percent),
531 MAX_WINDOW_SCALING_PERCENT);
533 video.window_width = new_window_width;
534 video.window_height = new_window_height;
536 if (game_status == GAME_MODE_SETUP)
537 RedrawSetupScreenAfterFullscreenToggle();
544 #define NUM_TOUCH_FINGERS 3
549 SDL_FingerID finger_id;
552 } touch_info[NUM_TOUCH_FINGERS];
554 void HandleFingerEvent(FingerEvent *event)
556 static Key motion_key_x = KSYM_UNDEFINED;
557 static Key motion_key_y = KSYM_UNDEFINED;
558 static Key button_key = KSYM_UNDEFINED;
559 static float motion_x1, motion_y1;
560 static float button_x1, button_y1;
561 static SDL_FingerID motion_id = -1;
562 static SDL_FingerID button_id = -1;
563 int move_trigger_distance_percent = 2; // percent of touchpad width/height
564 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
565 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
566 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
567 float event_x = event->x;
568 float event_y = event->y;
570 #if DEBUG_EVENTS_FINGER
571 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
572 event->type == EVENT_FINGERPRESS ? "pressed" :
573 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
577 event->dx, event->dy,
581 if (game_status != GAME_MODE_PLAYING)
584 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
586 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
588 Key key = (event->x < 1.0 / 3.0 ?
589 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
590 setup.input[0].key.drop) :
591 event->x > 2.0 / 3.0 ?
592 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
593 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
594 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
595 setup.input[0].key.right) :
597 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
601 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
602 getKeyNameFromKey(key), key_status_name, event->fingerId);
604 // check if we already know this touch event's finger id
605 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
607 if (touch_info[i].touched &&
608 touch_info[i].finger_id == event->fingerId)
610 // Error(ERR_DEBUG, "MARK 1: %d", i);
616 if (i >= NUM_TOUCH_FINGERS)
618 if (key_status == KEY_PRESSED)
620 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
622 // unknown finger id -- get new, empty slot, if available
623 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
625 if (touch_info[i].counter < oldest_counter)
628 oldest_counter = touch_info[i].counter;
630 // Error(ERR_DEBUG, "MARK 2: %d", i);
633 if (!touch_info[i].touched)
635 // Error(ERR_DEBUG, "MARK 3: %d", i);
641 if (i >= NUM_TOUCH_FINGERS)
643 // all slots allocated -- use oldest slot
646 // Error(ERR_DEBUG, "MARK 4: %d", i);
651 // release of previously unknown key (should not happen)
653 if (key != KSYM_UNDEFINED)
655 HandleKey(key, KEY_RELEASED);
657 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
658 getKeyNameFromKey(key), "KEY_RELEASED", i);
663 if (i < NUM_TOUCH_FINGERS)
665 if (key_status == KEY_PRESSED)
667 if (touch_info[i].key != key)
669 if (touch_info[i].key != KSYM_UNDEFINED)
671 HandleKey(touch_info[i].key, KEY_RELEASED);
673 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
674 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
677 if (key != KSYM_UNDEFINED)
679 HandleKey(key, KEY_PRESSED);
681 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
682 getKeyNameFromKey(key), "KEY_PRESSED", i);
686 touch_info[i].touched = TRUE;
687 touch_info[i].finger_id = event->fingerId;
688 touch_info[i].counter = Counter();
689 touch_info[i].key = key;
693 if (touch_info[i].key != KSYM_UNDEFINED)
695 HandleKey(touch_info[i].key, KEY_RELEASED);
697 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
698 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
701 touch_info[i].touched = FALSE;
702 touch_info[i].finger_id = 0;
703 touch_info[i].counter = 0;
704 touch_info[i].key = 0;
711 // use touch direction control
713 if (event->type == EVENT_FINGERPRESS)
715 if (event_x > 1.0 / 3.0)
719 motion_id = event->fingerId;
724 motion_key_x = KSYM_UNDEFINED;
725 motion_key_y = KSYM_UNDEFINED;
727 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
733 button_id = event->fingerId;
738 button_key = setup.input[0].key.snap;
740 HandleKey(button_key, KEY_PRESSED);
742 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
745 else if (event->type == EVENT_FINGERRELEASE)
747 if (event->fingerId == motion_id)
751 if (motion_key_x != KSYM_UNDEFINED)
752 HandleKey(motion_key_x, KEY_RELEASED);
753 if (motion_key_y != KSYM_UNDEFINED)
754 HandleKey(motion_key_y, KEY_RELEASED);
756 motion_key_x = KSYM_UNDEFINED;
757 motion_key_y = KSYM_UNDEFINED;
759 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
761 else if (event->fingerId == button_id)
765 if (button_key != KSYM_UNDEFINED)
766 HandleKey(button_key, KEY_RELEASED);
768 button_key = KSYM_UNDEFINED;
770 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
773 else if (event->type == EVENT_FINGERMOTION)
775 if (event->fingerId == motion_id)
777 float distance_x = ABS(event_x - motion_x1);
778 float distance_y = ABS(event_y - motion_y1);
779 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
780 event_x > motion_x1 ? setup.input[0].key.right :
782 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
783 event_y > motion_y1 ? setup.input[0].key.down :
786 if (distance_x < move_trigger_distance / 2 ||
787 distance_x < distance_y)
788 new_motion_key_x = KSYM_UNDEFINED;
790 if (distance_y < move_trigger_distance / 2 ||
791 distance_y < distance_x)
792 new_motion_key_y = KSYM_UNDEFINED;
794 if (distance_x > move_trigger_distance ||
795 distance_y > move_trigger_distance)
797 if (new_motion_key_x != motion_key_x)
799 if (motion_key_x != KSYM_UNDEFINED)
800 HandleKey(motion_key_x, KEY_RELEASED);
801 if (new_motion_key_x != KSYM_UNDEFINED)
802 HandleKey(new_motion_key_x, KEY_PRESSED);
805 if (new_motion_key_y != motion_key_y)
807 if (motion_key_y != KSYM_UNDEFINED)
808 HandleKey(motion_key_y, KEY_RELEASED);
809 if (new_motion_key_y != KSYM_UNDEFINED)
810 HandleKey(new_motion_key_y, KEY_PRESSED);
816 motion_key_x = new_motion_key_x;
817 motion_key_y = new_motion_key_y;
819 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
822 else if (event->fingerId == button_id)
824 float distance_x = ABS(event_x - button_x1);
825 float distance_y = ABS(event_y - button_y1);
827 if (distance_x < drop_trigger_distance / 2 &&
828 distance_y > drop_trigger_distance)
830 if (button_key == setup.input[0].key.snap)
831 HandleKey(button_key, KEY_RELEASED);
836 button_key = setup.input[0].key.drop;
838 HandleKey(button_key, KEY_PRESSED);
840 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
846 static boolean checkTextInputKeyModState()
848 // when playing, only handle raw key events and ignore text input
849 if (game_status == GAME_MODE_PLAYING)
852 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
855 void HandleTextEvent(TextEvent *event)
857 char *text = event->text;
858 Key key = getKeyFromKeyName(text);
860 #if DEBUG_EVENTS_TEXT
861 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
864 text[0], (int)(text[0]),
866 getKeyNameFromKey(key),
870 #if !defined(HAS_SCREEN_KEYBOARD)
871 // non-mobile devices: only handle key input with modifier keys pressed here
872 // (every other key input is handled directly as physical key input event)
873 if (!checkTextInputKeyModState())
877 // process text input as "classic" (with uppercase etc.) key input event
878 HandleKey(key, KEY_PRESSED);
879 HandleKey(key, KEY_RELEASED);
882 void HandlePauseResumeEvent(PauseResumeEvent *event)
884 if (event->type == SDL_APP_WILLENTERBACKGROUND)
888 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
896 void HandleKeyEvent(KeyEvent *event)
898 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
899 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
900 Key key = GetEventKey(event, with_modifiers);
901 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
904 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
905 event->type == EVENT_KEYPRESS ? "pressed" : "released",
906 event->keysym.scancode,
911 getKeyNameFromKey(key));
914 #if defined(PLATFORM_ANDROID)
915 // always map the "back" button to the "escape" key on Android devices
916 if (key == KSYM_Back)
920 HandleKeyModState(keymod, key_status);
922 #if defined(TARGET_SDL2)
923 // only handle raw key input without text modifier keys pressed
924 if (!checkTextInputKeyModState())
925 HandleKey(key, key_status);
927 HandleKey(key, key_status);
931 void HandleFocusEvent(FocusChangeEvent *event)
933 static int old_joystick_status = -1;
935 if (event->type == EVENT_FOCUSOUT)
937 KeyboardAutoRepeatOn();
938 old_joystick_status = joystick.status;
939 joystick.status = JOYSTICK_NOT_AVAILABLE;
943 else if (event->type == EVENT_FOCUSIN)
945 /* When there are two Rocks'n'Diamonds windows which overlap and
946 the player moves the pointer from one game window to the other,
947 a 'FocusOut' event is generated for the window the pointer is
948 leaving and a 'FocusIn' event is generated for the window the
949 pointer is entering. In some cases, it can happen that the
950 'FocusIn' event is handled by the one game process before the
951 'FocusOut' event by the other game process. In this case the
952 X11 environment would end up with activated keyboard auto repeat,
953 because unfortunately this is a global setting and not (which
954 would be far better) set for each X11 window individually.
955 The effect would be keyboard auto repeat while playing the game
956 (game_status == GAME_MODE_PLAYING), which is not desired.
957 To avoid this special case, we just wait 1/10 second before
958 processing the 'FocusIn' event.
961 if (game_status == GAME_MODE_PLAYING)
964 KeyboardAutoRepeatOffUnlessAutoplay();
967 if (old_joystick_status != -1)
968 joystick.status = old_joystick_status;
972 void HandleClientMessageEvent(ClientMessageEvent *event)
974 if (CheckCloseWindowEvent(event))
978 void HandleWindowManagerEvent(Event *event)
980 #if defined(TARGET_SDL)
981 SDLHandleWindowManagerEvent(event);
985 void HandleButton(int mx, int my, int button, int button_nr)
987 static int old_mx = 0, old_my = 0;
988 boolean button_hold = FALSE;
994 button_nr = -button_nr;
1003 #if defined(PLATFORM_ANDROID)
1004 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
1005 if (game_status != GAME_MODE_PLAYING &&
1006 HandleGadgets(mx, my, button))
1008 /* do not handle this button event anymore */
1009 mx = my = -32; /* force mouse event to be outside screen tiles */
1012 if (HandleGadgets(mx, my, button))
1014 /* do not handle this button event anymore */
1015 mx = my = -32; /* force mouse event to be outside screen tiles */
1019 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
1022 /* do not use scroll wheel button events for anything other than gadgets */
1023 if (IS_WHEEL_BUTTON(button_nr))
1026 switch (game_status)
1028 case GAME_MODE_TITLE:
1029 HandleTitleScreen(mx, my, 0, 0, button);
1032 case GAME_MODE_MAIN:
1033 HandleMainMenu(mx, my, 0, 0, button);
1036 case GAME_MODE_PSEUDO_TYPENAME:
1037 HandleTypeName(0, KSYM_Return);
1040 case GAME_MODE_LEVELS:
1041 HandleChooseLevelSet(mx, my, 0, 0, button);
1044 case GAME_MODE_LEVELNR:
1045 HandleChooseLevelNr(mx, my, 0, 0, button);
1048 case GAME_MODE_SCORES:
1049 HandleHallOfFame(0, 0, 0, 0, button);
1052 case GAME_MODE_EDITOR:
1053 HandleLevelEditorIdle();
1056 case GAME_MODE_INFO:
1057 HandleInfoScreen(mx, my, 0, 0, button);
1060 case GAME_MODE_SETUP:
1061 HandleSetupScreen(mx, my, 0, 0, button);
1064 case GAME_MODE_PLAYING:
1066 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1067 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1068 LEVELY((my - SY) / TILESIZE_VAR));
1069 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1078 static boolean is_string_suffix(char *string, char *suffix)
1080 int string_len = strlen(string);
1081 int suffix_len = strlen(suffix);
1083 if (suffix_len > string_len)
1086 return (strEqual(&string[string_len - suffix_len], suffix));
1089 #define MAX_CHEAT_INPUT_LEN 32
1091 static void HandleKeysSpecial(Key key)
1093 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1094 char letter = getCharFromKey(key);
1095 int cheat_input_len = strlen(cheat_input);
1101 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1103 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1104 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1106 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1109 cheat_input[cheat_input_len++] = letter;
1110 cheat_input[cheat_input_len] = '\0';
1112 #if DEBUG_EVENTS_KEY
1113 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1116 if (game_status == GAME_MODE_MAIN)
1118 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1119 is_string_suffix(cheat_input, ":ist"))
1121 InsertSolutionTape();
1123 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1124 is_string_suffix(cheat_input, ":rg"))
1126 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1129 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1130 is_string_suffix(cheat_input, ":rs"))
1132 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1135 else if (is_string_suffix(cheat_input, ":reload-music") ||
1136 is_string_suffix(cheat_input, ":rm"))
1138 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1141 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1142 is_string_suffix(cheat_input, ":ra"))
1144 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1145 1 << ARTWORK_TYPE_SOUNDS |
1146 1 << ARTWORK_TYPE_MUSIC);
1149 else if (is_string_suffix(cheat_input, ":dump-level") ||
1150 is_string_suffix(cheat_input, ":dl"))
1154 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1155 is_string_suffix(cheat_input, ":dt"))
1159 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1160 is_string_suffix(cheat_input, ":ft"))
1162 /* fix single-player tapes that contain player input for more than one
1163 player (due to a bug in 3.3.1.2 and earlier versions), which results
1164 in playing levels with more than one player in multi-player mode,
1165 even though the tape was originally recorded in single-player mode */
1167 /* remove player input actions for all players but the first one */
1168 for (i = 1; i < MAX_PLAYERS; i++)
1169 tape.player_participates[i] = FALSE;
1171 tape.changed = TRUE;
1173 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1174 is_string_suffix(cheat_input, ":snl"))
1176 SaveNativeLevel(&level);
1179 else if (game_status == GAME_MODE_PLAYING)
1182 if (is_string_suffix(cheat_input, ".q"))
1183 DEBUG_SetMaximumDynamite();
1186 else if (game_status == GAME_MODE_EDITOR)
1188 if (is_string_suffix(cheat_input, ":dump-brush") ||
1189 is_string_suffix(cheat_input, ":DB"))
1193 else if (is_string_suffix(cheat_input, ":DDB"))
1200 void HandleKeysDebug(Key key)
1205 if (game_status == GAME_MODE_PLAYING || !setup.debug.frame_delay_game_only)
1207 boolean mod_key_pressed = (GetKeyModState() != KMOD_None);
1209 for (i = 0; i < NUM_DEBUG_FRAME_DELAY_KEYS; i++)
1211 if (key == setup.debug.frame_delay_key[i] &&
1212 (mod_key_pressed == setup.debug.frame_delay_use_mod_key))
1214 GameFrameDelay = (GameFrameDelay != setup.debug.frame_delay[i] ?
1215 setup.debug.frame_delay[i] : GAME_FRAME_DELAY);
1217 if (!setup.debug.frame_delay_game_only)
1218 MenuFrameDelay = GameFrameDelay;
1220 SetVideoFrameDelay(GameFrameDelay);
1222 if (GameFrameDelay > ONE_SECOND_DELAY)
1223 Error(ERR_DEBUG, "frame delay == %d ms", GameFrameDelay);
1224 else if (GameFrameDelay != 0)
1225 Error(ERR_DEBUG, "frame delay == %d ms (max. %d fps / %d %%)",
1226 GameFrameDelay, ONE_SECOND_DELAY / GameFrameDelay,
1227 GAME_FRAME_DELAY * 100 / GameFrameDelay);
1229 Error(ERR_DEBUG, "frame delay == 0 ms (maximum speed)");
1236 if (game_status == GAME_MODE_PLAYING)
1240 options.debug = !options.debug;
1242 Error(ERR_DEBUG, "debug mode %s",
1243 (options.debug ? "enabled" : "disabled"));
1245 else if (key == KSYM_v)
1247 Error(ERR_DEBUG, "currently using game engine version %d",
1248 game.engine_version);
1254 void HandleKey(Key key, int key_status)
1256 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1257 static boolean ignore_repeated_key = FALSE;
1258 static struct SetupKeyboardInfo ski;
1259 static struct SetupShortcutInfo ssi;
1268 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1269 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1270 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1271 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1272 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1273 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1278 if (game_status == GAME_MODE_PLAYING)
1280 /* only needed for single-step tape recording mode */
1281 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1282 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1283 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1284 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1287 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1289 byte key_action = 0;
1291 if (setup.input[pnr].use_joystick)
1294 ski = setup.input[pnr].key;
1296 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1297 if (key == *key_info[i].key_custom)
1298 key_action |= key_info[i].action;
1300 /* use combined snap+direction keys for the first player only */
1303 ssi = setup.shortcut;
1305 for (i = 0; i < NUM_DIRECTIONS; i++)
1306 if (key == *key_info[i].key_snap)
1307 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1310 /* clear delayed snap and drop actions in single step mode (see below) */
1311 if (tape.single_step)
1313 if (clear_snap_button[pnr])
1315 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1316 clear_snap_button[pnr] = FALSE;
1319 if (clear_drop_button[pnr])
1321 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1322 clear_drop_button[pnr] = FALSE;
1326 if (key_status == KEY_PRESSED)
1327 stored_player[pnr].action |= key_action;
1329 stored_player[pnr].action &= ~key_action;
1331 if (tape.single_step && tape.recording && tape.pausing)
1333 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1335 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1337 /* if snap key already pressed, don't snap when releasing (below) */
1338 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1339 element_snapped[pnr] = TRUE;
1341 /* if drop key already pressed, don't drop when releasing (below) */
1342 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1343 element_dropped[pnr] = TRUE;
1345 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1347 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1348 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1351 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1352 getRedDiskReleaseFlag_SP() == 0)
1353 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1355 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1358 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1360 if (key_action & KEY_BUTTON_SNAP)
1362 /* if snap key was released without moving (see above), snap now */
1363 if (!element_snapped[pnr])
1365 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1367 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1369 /* clear delayed snap button on next event */
1370 clear_snap_button[pnr] = TRUE;
1373 element_snapped[pnr] = FALSE;
1376 if (key_action & KEY_BUTTON_DROP &&
1377 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1379 /* if drop key was released without moving (see above), drop now */
1380 if (!element_dropped[pnr])
1382 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1384 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1385 getRedDiskReleaseFlag_SP() != 0)
1386 stored_player[pnr].action |= KEY_BUTTON_DROP;
1388 /* clear delayed drop button on next event */
1389 clear_drop_button[pnr] = TRUE;
1392 element_dropped[pnr] = FALSE;
1396 else if (tape.recording && tape.pausing)
1398 /* prevent key release events from un-pausing a paused game */
1399 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1400 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1406 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1407 if (key == key_info[i].key_default)
1408 joy |= key_info[i].action;
1413 if (key_status == KEY_PRESSED)
1414 key_joystick_mapping |= joy;
1416 key_joystick_mapping &= ~joy;
1421 if (game_status != GAME_MODE_PLAYING)
1422 key_joystick_mapping = 0;
1424 if (key_status == KEY_RELEASED)
1426 // reset flag to ignore repeated "key pressed" events after key release
1427 ignore_repeated_key = FALSE;
1432 if ((key == KSYM_F11 ||
1433 ((key == KSYM_Return ||
1434 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1435 video.fullscreen_available &&
1436 !ignore_repeated_key)
1438 setup.fullscreen = !setup.fullscreen;
1440 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1442 if (game_status == GAME_MODE_SETUP)
1443 RedrawSetupScreenAfterFullscreenToggle();
1445 // set flag to ignore repeated "key pressed" events
1446 ignore_repeated_key = TRUE;
1451 if ((key == KSYM_0 || key == KSYM_KP_0 ||
1452 key == KSYM_minus || key == KSYM_KP_Subtract ||
1453 key == KSYM_plus || key == KSYM_KP_Add ||
1454 key == KSYM_equal) && // ("Shift-=" is "+" on US keyboards)
1455 (GetKeyModState() & (KMOD_Control | KMOD_Meta)) &&
1456 video.window_scaling_available &&
1457 !video.fullscreen_enabled)
1459 if (key == KSYM_0 || key == KSYM_KP_0)
1460 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1461 else if (key == KSYM_minus || key == KSYM_KP_Subtract)
1462 setup.window_scaling_percent -= STEP_WINDOW_SCALING_PERCENT;
1464 setup.window_scaling_percent += STEP_WINDOW_SCALING_PERCENT;
1466 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1467 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1468 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1469 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1471 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1473 if (game_status == GAME_MODE_SETUP)
1474 RedrawSetupScreenAfterFullscreenToggle();
1479 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1480 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1487 if (game_status == GAME_MODE_MAIN &&
1488 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1490 StartGameActions(options.network, setup.autorecord, level.random_seed);
1495 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1497 if (key == setup.shortcut.save_game)
1499 else if (key == setup.shortcut.load_game)
1501 else if (key == setup.shortcut.toggle_pause)
1502 TapeTogglePause(TAPE_TOGGLE_MANUAL | TAPE_TOGGLE_PLAY_PAUSE);
1504 HandleTapeButtonKeys(key);
1505 HandleSoundButtonKeys(key);
1508 if (game_status == GAME_MODE_PLAYING && !network_playing)
1510 int centered_player_nr_next = -999;
1512 if (key == setup.shortcut.focus_player_all)
1513 centered_player_nr_next = -1;
1515 for (i = 0; i < MAX_PLAYERS; i++)
1516 if (key == setup.shortcut.focus_player[i])
1517 centered_player_nr_next = i;
1519 if (centered_player_nr_next != -999)
1521 game.centered_player_nr_next = centered_player_nr_next;
1522 game.set_centered_player = TRUE;
1526 tape.centered_player_nr_next = game.centered_player_nr_next;
1527 tape.set_centered_player = TRUE;
1532 HandleKeysSpecial(key);
1534 if (HandleGadgetsKeyInput(key))
1536 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1537 key = KSYM_UNDEFINED;
1540 switch (game_status)
1542 case GAME_MODE_PSEUDO_TYPENAME:
1543 HandleTypeName(0, key);
1546 case GAME_MODE_TITLE:
1547 case GAME_MODE_MAIN:
1548 case GAME_MODE_LEVELS:
1549 case GAME_MODE_LEVELNR:
1550 case GAME_MODE_SETUP:
1551 case GAME_MODE_INFO:
1552 case GAME_MODE_SCORES:
1557 if (game_status == GAME_MODE_TITLE)
1558 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1559 else if (game_status == GAME_MODE_MAIN)
1560 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1561 else if (game_status == GAME_MODE_LEVELS)
1562 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1563 else if (game_status == GAME_MODE_LEVELNR)
1564 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1565 else if (game_status == GAME_MODE_SETUP)
1566 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1567 else if (game_status == GAME_MODE_INFO)
1568 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1569 else if (game_status == GAME_MODE_SCORES)
1570 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1574 if (game_status != GAME_MODE_MAIN)
1575 FadeSkipNextFadeIn();
1577 if (game_status == GAME_MODE_TITLE)
1578 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1579 else if (game_status == GAME_MODE_LEVELS)
1580 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1581 else if (game_status == GAME_MODE_LEVELNR)
1582 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1583 else if (game_status == GAME_MODE_SETUP)
1584 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1585 else if (game_status == GAME_MODE_INFO)
1586 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1587 else if (game_status == GAME_MODE_SCORES)
1588 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1592 if (game_status == GAME_MODE_LEVELS)
1593 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1594 else if (game_status == GAME_MODE_LEVELNR)
1595 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1596 else if (game_status == GAME_MODE_SETUP)
1597 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1598 else if (game_status == GAME_MODE_INFO)
1599 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1600 else if (game_status == GAME_MODE_SCORES)
1601 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1604 case KSYM_Page_Down:
1605 if (game_status == GAME_MODE_LEVELS)
1606 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1607 else if (game_status == GAME_MODE_LEVELNR)
1608 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1609 else if (game_status == GAME_MODE_SETUP)
1610 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1611 else if (game_status == GAME_MODE_INFO)
1612 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1613 else if (game_status == GAME_MODE_SCORES)
1614 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1622 case GAME_MODE_EDITOR:
1623 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1624 HandleLevelEditorKeyInput(key);
1627 case GAME_MODE_PLAYING:
1632 RequestQuitGame(setup.ask_on_escape);
1642 if (key == KSYM_Escape)
1644 SetGameStatus(GAME_MODE_MAIN);
1652 HandleKeysDebug(key);
1655 void HandleNoEvent()
1657 // if (button_status && game_status != GAME_MODE_PLAYING)
1658 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1660 HandleButton(0, 0, button_status, -button_status);
1667 #if defined(NETWORK_AVALIABLE)
1668 if (options.network)
1672 switch (game_status)
1674 case GAME_MODE_MAIN:
1675 DrawPreviewLevelAnimation();
1678 case GAME_MODE_EDITOR:
1679 HandleLevelEditorIdle();
1687 static int HandleJoystickForAllPlayers()
1692 for (i = 0; i < MAX_PLAYERS; i++)
1694 byte joy_action = 0;
1697 if (!setup.input[i].use_joystick)
1701 joy_action = Joystick(i);
1702 result |= joy_action;
1704 if (!setup.input[i].use_joystick)
1707 stored_player[i].action = joy_action;
1713 void HandleJoystick()
1715 int joystick = HandleJoystickForAllPlayers();
1716 int keyboard = key_joystick_mapping;
1717 int joy = (joystick | keyboard);
1718 int left = joy & JOY_LEFT;
1719 int right = joy & JOY_RIGHT;
1720 int up = joy & JOY_UP;
1721 int down = joy & JOY_DOWN;
1722 int button = joy & JOY_BUTTON;
1723 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1724 int dx = (left ? -1 : right ? 1 : 0);
1725 int dy = (up ? -1 : down ? 1 : 0);
1727 switch (game_status)
1729 case GAME_MODE_TITLE:
1730 case GAME_MODE_MAIN:
1731 case GAME_MODE_LEVELS:
1732 case GAME_MODE_LEVELNR:
1733 case GAME_MODE_SETUP:
1734 case GAME_MODE_INFO:
1736 static unsigned int joystickmove_delay = 0;
1738 if (joystick && !button &&
1739 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1740 newbutton = dx = dy = 0;
1742 if (game_status == GAME_MODE_TITLE)
1743 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1744 else if (game_status == GAME_MODE_MAIN)
1745 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1746 else if (game_status == GAME_MODE_LEVELS)
1747 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1748 else if (game_status == GAME_MODE_LEVELNR)
1749 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1750 else if (game_status == GAME_MODE_SETUP)
1751 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1752 else if (game_status == GAME_MODE_INFO)
1753 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1757 case GAME_MODE_SCORES:
1758 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1761 case GAME_MODE_PLAYING:
1762 if (tape.playing || keyboard)
1763 newbutton = ((joy & JOY_BUTTON) != 0);
1765 if (newbutton && AllPlayersGone)