shithub: cstory

Download patch

ref: 1cf4200051217c229c3cc69cf71404f8a6886489
parent: 1d9048c8a6a6388607799384d4912eec00e88c5d
parent: bcd883e767526e7e5f4a8fae0c68853ee8ea1e00
author: Gabriel Ravier <[email protected]>
date: Sun Apr 5 15:33:13 EDT 2020

Merge branch 'portable' into improvePerformance2

--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -439,11 +439,11 @@
 		if (PKG_CONFIG_STATIC_LIBS)
 			message(STATUS "Using system GLFW3 (pkg-config, static)")
 			target_compile_options(CSE2 PRIVATE ${glfw3_STATIC_CFLAGS})
-			target_link_libraries(CSE2 PRIVATE ${glfw3_STATIC_LINK_LIBRARIES})
+			target_link_libraries(CSE2 PRIVATE ${glfw3_STATIC_LDFLAGS})
 		else()
 			message(STATUS "Using system GLFW3 (pkg-config, dynamic)")
 			target_compile_options(CSE2 PRIVATE ${glfw3_CFLAGS})
-			target_link_libraries(CSE2 PRIVATE ${glfw3_LINK_LIBRARIES})
+			target_link_libraries(CSE2 PRIVATE ${glfw3_LDFLAGS})
 		endif()
 	elseif(TARGET glfw)
 		# CMake
@@ -475,11 +475,11 @@
 		if (PKG_CONFIG_STATIC_LIBS)
 			message(STATUS "Using system SDL2 (pkg-config, static)")
 			target_compile_options(CSE2 PRIVATE ${sdl2_STATIC_CFLAGS})
-			target_link_libraries(CSE2 PRIVATE ${sdl2_STATIC_LINK_LIBRARIES})
+			target_link_libraries(CSE2 PRIVATE ${sdl2_STATIC_LDFLAGS})
 		else()
 			message(STATUS "Using system SDL2 (pkg-config, dynamic)")
 			target_compile_options(CSE2 PRIVATE ${sdl2_CFLAGS})
-			target_link_libraries(CSE2 PRIVATE ${sdl2_LINK_LIBRARIES})
+			target_link_libraries(CSE2 PRIVATE ${sdl2_LDFLAGS})
 		endif()
 	elseif(TARGET SDL2::SDL2)
 		# CMake-generated config (Arch, vcpkg, Raspbian)
@@ -519,11 +519,11 @@
 	if (PKG_CONFIG_STATIC_LIBS)
 		message(STATUS "Using system FreeType (pkg-config, static)")
 		target_compile_options(CSE2 PRIVATE ${freetype2_STATIC_CFLAGS})
-		target_link_libraries(CSE2 PRIVATE ${freetype2_STATIC_LINK_LIBRARIES})
+		target_link_libraries(CSE2 PRIVATE ${freetype2_STATIC_LDFLAGS})
 	else()
 		message(STATUS "Using system FreeType (pkg-config, dynamic)")
 		target_compile_options(CSE2 PRIVATE ${freetype2_CFLAGS})
-		target_link_libraries(CSE2 PRIVATE ${freetype2_LINK_LIBRARIES})
+		target_link_libraries(CSE2 PRIVATE ${freetype2_LDFLAGS})
 	endif()
 elseif(FREETYPE_FOUND)
 	message(STATUS "Using system FreeType (CMake)")
--- a/DoConfig/CMakeLists.txt
+++ b/DoConfig/CMakeLists.txt
@@ -95,11 +95,11 @@
 	if (PKG_CONFIG_STATIC_LIBS)
 		message(STATUS "Using system GLFW3 (pkg-config, static)")
 		target_compile_options(DoConfig PRIVATE ${glfw3_STATIC_CFLAGS})
-		target_link_libraries(DoConfig PRIVATE ${glfw3_STATIC_LINK_LIBRARIES})
+		target_link_libraries(DoConfig PRIVATE ${glfw3_STATIC_LDFLAGS})
 	else()
 		message(STATUS "Using system GLFW3 (pkg-config, dynamic)")
 		target_compile_options(DoConfig PRIVATE ${glfw3_CFLAGS})
-		target_link_libraries(DoConfig PRIVATE ${glfw3_LINK_LIBRARIES})
+		target_link_libraries(DoConfig PRIVATE ${glfw3_LDFLAGS})
 	endif()
 elseif(TARGET glfw)
 	# CMake
--- a/external/glad/CMakeLists.txt
+++ b/external/glad/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 project(glad LANGUAGES C)
 
-add_library(glad
+add_library(glad STATIC
 	"include/glad/glad.h"
 	"include/KHR/khrplatform.h"
 	"src/glad.c"
--- a/src/Backends/Audio/SoftwareMixer.cpp
+++ b/src/Backends/Audio/SoftwareMixer.cpp
@@ -154,7 +154,7 @@
 				const float sample2 = (sound->samples[(size_t)sound->position + 1] - 128.0f) / 128.0f;
 
 				// Perform linear interpolation
-				const float interpolated_sample = sample1 + ((sample2 - sample1) * fmod((float)sound->position, 1.0f));
+				const float interpolated_sample = sample1 + ((sample2 - sample1) * fmod(sound->position, 1.0));
 
 				*steam_pointer++ += interpolated_sample * sound->volume_l;
 				*steam_pointer++ += interpolated_sample * sound->volume_r;
--- a/src/Backends/GLFW3/Controller.cpp
+++ b/src/Backends/GLFW3/Controller.cpp
@@ -2,6 +2,7 @@
 
 #include <stddef.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #define GLFW_INCLUDE_NONE
 #include <GLFW/glfw3.h>
@@ -12,9 +13,9 @@
 
 static BOOL joystick_connected;
 static int connected_joystick_id;
-static int joystick_neutral_x;
-static int joystick_neutral_y;
 
+static float *axis_neutrals;
+
 static void JoystickCallback(int joystick_id, int event)
 {
 	switch (event)
@@ -24,10 +25,13 @@
 
 			if (!joystick_connected)
 			{
-				int total_axis;
-				const float *axis = glfwGetJoystickAxes(joystick_id, &total_axis);
+				int total_axes;
+				const float *axes = glfwGetJoystickAxes(joystick_id, &total_axes);
 
-				if (total_axis >= 2)
+				int total_buttons;
+				const unsigned char *buttons = glfwGetJoystickButtons(joystick_id, &total_buttons);
+
+				if (total_axes >= 2 && total_buttons >= 6)
 				{
 #if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
 					if (glfwJoystickIsGamepad(joystick_id) == GLFW_TRUE)	// Avoid selecting things like laptop touchpads
@@ -37,9 +41,11 @@
 						joystick_connected = TRUE;
 						connected_joystick_id = joystick_id;
 
-						// Reset default stick positions (this is performed in ResetJoystickStatus in vanilla Cave Story
-						joystick_neutral_x = axis[0];
-						joystick_neutral_y = axis[1];
+						// Set up neutral axes
+						axis_neutrals = (float*)malloc(sizeof(float) * total_axes);
+
+						for (int i = 0; i < total_axes; ++i)
+							axis_neutrals[i] = axes[i];
 					}
 				}
 			}
@@ -51,6 +57,8 @@
 			{
 				printf("Joystick #%d disconnected\n", connected_joystick_id);
 				joystick_connected = FALSE;
+
+				free(axis_neutrals);
 			}
 
 			break;
@@ -76,8 +84,9 @@
 
 	joystick_connected = FALSE;
 	connected_joystick_id = 0;
-	joystick_neutral_x = 0;
-	joystick_neutral_y = 0;
+
+	free(axis_neutrals);
+	axis_neutrals = NULL;
 }
 
 BOOL ControllerBackend_GetJoystickStatus(JOYSTICK_STATUS *status)
@@ -85,29 +94,79 @@
 	if (!joystick_connected)
 		return FALSE;
 
-	// Read axis
-	int total_axis;
-	const float *axis = glfwGetJoystickAxes(connected_joystick_id, &total_axis);
+	const size_t button_limit = sizeof(status->bButton) / sizeof(status->bButton[0]);
 
-	status->bLeft = axis[0] < joystick_neutral_x - DEADZONE;
-	status->bRight = axis[0] > joystick_neutral_x + DEADZONE;
-	status->bUp = axis[1] < joystick_neutral_y - DEADZONE;
-	status->bDown = axis[1] > joystick_neutral_y + DEADZONE;
-
-	// Read buttons
 	int total_buttons;
 	const unsigned char *buttons = glfwGetJoystickButtons(connected_joystick_id, &total_buttons);
 
-	// The original `Input.cpp` assumed there were 32 buttons (because of DirectInput's `DIJOYSTATE` struct)
-	if (total_buttons > 32)
-		total_buttons = 32;
+	int total_axes;
+	const float *axes = glfwGetJoystickAxes(connected_joystick_id, &total_axes);
 
-	// Read whatever buttons actually exist
+#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
+	int total_hats;
+	const unsigned char *hats = glfwGetJoystickHats(connected_joystick_id, &total_hats);
+#endif
+
+	// Handle directional inputs
+	status->bLeft = axes[0] < axis_neutrals[0] - DEADZONE;
+	status->bRight = axes[0] > axis_neutrals[0] + DEADZONE;
+	status->bUp = axes[1] < axis_neutrals[1] - DEADZONE;
+	status->bDown = axes[1] > axis_neutrals[1] + DEADZONE;
+
+	// Handle button inputs
+	unsigned int buttons_done = 0;
+
+	// Start with the joystick buttons
 	for (int i = 0; i < total_buttons; ++i)
-		status->bButton[i] = buttons[i] == GLFW_PRESS;
+	{
+		status->bButton[buttons_done] = buttons[i] == GLFW_PRESS;
 
-	// Blank the buttons that do not
-	for (int i = total_buttons; i < 32; ++i)
+		if (++buttons_done >= button_limit)
+			break;
+	}
+
+	// Then the joystick axes
+	for (int i = 0; i < total_axes; ++i)
+	{
+		status->bButton[buttons_done] = axes[i] < axis_neutrals[i] - DEADZONE;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = axes[i] > axis_neutrals[i] + DEADZONE;
+
+		if (++buttons_done >= button_limit)
+			break;
+	}
+
+#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
+	// Then the joystick hats
+	for (int i = 0; i < total_axes; ++i)
+	{
+		status->bButton[buttons_done] = hats[i] & GLFW_HAT_UP;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = hats[i] & GLFW_HAT_RIGHT;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = hats[i] & GLFW_HAT_DOWN;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = hats[i] & GLFW_HAT_LEFT;
+
+		if (++buttons_done >= button_limit)
+			break;
+	}
+#endif
+
+	// Blank any remaining buttons
+	for (size_t i = buttons_done; i < button_limit; ++i)
 		status->bButton[i] = FALSE;
 
 	return TRUE;
@@ -117,8 +176,6 @@
 {
 	if (!joystick_connected)
 		return FALSE;
-
-	// The code that would normally run here has been moved to JoystickCallback, to better-support hotplugging
 
 	return TRUE;
 }
--- a/src/Backends/GLFW3/Misc.cpp
+++ b/src/Backends/GLFW3/Misc.cpp
@@ -20,13 +20,13 @@
 
 #define DO_KEY(GLFW_KEY, BACKEND_KEY) \
 	case GLFW_KEY: \
-		backend_keyboard_state[BACKEND_KEY] = action == GLFW_PRESS; \
+		keyboard_state[BACKEND_KEY] = action == GLFW_PRESS; \
 		break;
 
 BOOL bActive = TRUE;
-BOOL backend_keyboard_state[BACKEND_KEYBOARD_TOTAL];
-BOOL backend_previous_keyboard_state[BACKEND_KEYBOARD_TOTAL];
 
+static BOOL keyboard_state[BACKEND_KEYBOARD_TOTAL];
+
 static GLFWcursor* cursor;
 
 static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
@@ -264,8 +264,6 @@
 		return FALSE;
 	}
 
-	memcpy(backend_previous_keyboard_state, backend_keyboard_state, sizeof(backend_keyboard_state));
-
 	glfwPollEvents();
 
 	while (!bActive)
@@ -272,6 +270,11 @@
 		glfwWaitEvents();
 
 	return TRUE;
+}
+
+void Backend_GetKeyboardState(BOOL *out_keyboard_state)
+{
+	memcpy(out_keyboard_state, keyboard_state, sizeof(keyboard_state));
 }
 
 void Backend_ShowMessageBox(const char *title, const char *message)
--- a/src/Backends/Misc.h
+++ b/src/Backends/Misc.h
@@ -84,8 +84,6 @@
 };
 
 extern BOOL bActive;
-extern BOOL backend_keyboard_state[BACKEND_KEYBOARD_TOTAL];
-extern BOOL backend_previous_keyboard_state[BACKEND_KEYBOARD_TOTAL];
 
 void Backend_Init(void);
 void Backend_Deinit(void);
@@ -96,6 +94,7 @@
 void Backend_SetCursor(const unsigned char *rgb_pixels, unsigned int width, unsigned int height);
 void PlaybackBackend_EnableDragAndDrop(void);
 BOOL Backend_SystemTask(void);
+void Backend_GetKeyboardState(BOOL *keyboard_state);
 void Backend_ShowMessageBox(const char *title, const char *message);
 unsigned long Backend_GetTicks(void);
 void Backend_Delay(unsigned int ticks);
--- a/src/Backends/SDL2/Controller.cpp
+++ b/src/Backends/SDL2/Controller.cpp
@@ -11,9 +11,9 @@
 #define DEADZONE 10000;
 
 static SDL_Joystick *joystick;
-static int joystick_neutral_x;
-static int joystick_neutral_y;
 
+static Sint16 *axis_neutrals;
+
 BOOL ControllerBackend_Init(void)
 {
 	SDL_InitSubSystem(SDL_INIT_JOYSTICK);
@@ -37,26 +37,77 @@
 	if (joystick == NULL)
 		return FALSE;
 
-	// Read axis
+	const size_t button_limit = sizeof(status->bButton) / sizeof(status->bButton[0]);
+
+	// Handle directional inputs
 	const Sint16 joystick_x = SDL_JoystickGetAxis(joystick, 0);
 	const Sint16 joystick_y = SDL_JoystickGetAxis(joystick, 1);
 
-	status->bLeft = joystick_x < joystick_neutral_x - DEADZONE;
-	status->bRight = joystick_x > joystick_neutral_x + DEADZONE;
-	status->bUp = joystick_y < joystick_neutral_y - DEADZONE;
-	status->bDown = joystick_y > joystick_neutral_y + DEADZONE;
+	status->bLeft = joystick_x < axis_neutrals[0] - DEADZONE;
+	status->bRight = joystick_x > axis_neutrals[0] + DEADZONE;
+	status->bUp = joystick_y < axis_neutrals[1] - DEADZONE;
+	status->bDown = joystick_y > axis_neutrals[1] + DEADZONE;
 
-	// The original `Input.cpp` assumed there were 32 buttons (because of DirectInput's `DIJOYSTATE` struct)
-	int numButtons = SDL_JoystickNumButtons(joystick);
-	if (numButtons > 32)
-		numButtons = 32;
+	// Handle button inputs
+	int total_buttons = SDL_JoystickNumButtons(joystick);
+	int total_axes = SDL_JoystickNumAxes(joystick);
+	int total_hats = SDL_JoystickNumHats(joystick);
 
-	// Read whatever buttons actually exist
-	for (int i = 0; i < numButtons; ++i)
-		status->bButton[i] = SDL_JoystickGetButton(joystick, i);
+	unsigned int buttons_done = 0;
 
-	// Blank the buttons that do not
-	for (int i = numButtons; i < 32; ++i)
+	// Start with the joystick buttons
+	for (int i = 0; i < total_buttons; ++i)
+	{
+		status->bButton[buttons_done] = SDL_JoystickGetButton(joystick, i);
+
+		if (++buttons_done >= button_limit)
+			break;
+	}
+
+	// Then the joystick axes
+	for (int i = 0; i < total_axes; ++i)
+	{
+		Sint16 axis = SDL_JoystickGetAxis(joystick, i);
+
+		status->bButton[buttons_done] = axis < axis_neutrals[i] - DEADZONE;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = axis > axis_neutrals[i] + DEADZONE;
+
+		if (++buttons_done >= button_limit)
+			break;
+	}
+
+	// Then the joystick hats
+	for (int i = 0; i < total_axes; ++i)
+	{
+		Uint8 hat = SDL_JoystickGetHat(joystick, i);
+
+		status->bButton[buttons_done] = hat == SDL_HAT_UP || hat == SDL_HAT_LEFTUP || hat == SDL_HAT_RIGHTUP;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = hat == SDL_HAT_RIGHT || hat == SDL_HAT_RIGHTUP || hat == SDL_HAT_RIGHTDOWN;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = hat == SDL_HAT_DOWN || hat == SDL_HAT_LEFTDOWN || hat == SDL_HAT_RIGHTDOWN;
+
+		if (++buttons_done >= button_limit)
+			break;
+
+		status->bButton[buttons_done] = hat == SDL_HAT_LEFT || hat == SDL_HAT_LEFTUP || hat == SDL_HAT_LEFTDOWN;
+
+		if (++buttons_done >= button_limit)
+			break;
+	}
+
+	// Blank any remaining buttons
+	for (size_t i = buttons_done; i < button_limit; ++i)
 		status->bButton[i] = FALSE;
 
 	return TRUE;
@@ -67,8 +118,6 @@
 	if (joystick == NULL)
 		return FALSE;
 
-	// The code that would normally run here has been moved to JoystickCallback, to better-support hotplugging
-
 	return TRUE;
 }
 
@@ -82,11 +131,24 @@
 
 		if (joystick != NULL)
 		{
-			printf("Joystick #%d selected\n", joystick_id);
+			int total_axes = SDL_JoystickNumAxes(joystick);
+			int total_buttons = SDL_JoystickNumButtons(joystick);
 
-			// Reset default stick positions (this is performed in ResetJoystickStatus in vanilla Cave Story
-			joystick_neutral_x = SDL_JoystickGetAxis(joystick, 0);
-			joystick_neutral_y = SDL_JoystickGetAxis(joystick, 1);
+			if (total_axes >= 2 && total_buttons >= 6)
+			{
+				printf("Joystick #%d selected\n", joystick_id);
+
+				// Set up neutral axes
+				axis_neutrals = (Sint16*)malloc(sizeof(Sint16) * total_axes);
+
+				for (int i = 0; i < total_axes; ++i)
+					axis_neutrals[i] = SDL_JoystickGetAxis(joystick, i);
+			}
+			else
+			{
+				SDL_JoystickClose(joystick);
+				joystick = NULL;
+			}
 		}
 	}
 }
@@ -96,6 +158,9 @@
 	if (joystick_id == SDL_JoystickInstanceID(joystick))
 	{
 		printf("Joystick #%d disconnected\n", joystick_id);
+		SDL_JoystickClose(joystick);
 		joystick = NULL;
+
+		free(axis_neutrals);
 	}
 }
--- a/src/Backends/SDL2/Misc.cpp
+++ b/src/Backends/SDL2/Misc.cpp
@@ -18,13 +18,13 @@
 
 #define DO_KEY(SDL_KEY, BACKEND_KEY) \
 	case SDL_KEY: \
-		backend_keyboard_state[BACKEND_KEY] = event.key.type == SDL_KEYDOWN; \
+		keyboard_state[BACKEND_KEY] = event.key.type == SDL_KEYDOWN; \
 		break;
 
 BOOL bActive = TRUE;
-BOOL backend_keyboard_state[BACKEND_KEYBOARD_TOTAL];
-BOOL backend_previous_keyboard_state[BACKEND_KEYBOARD_TOTAL];
 
+static BOOL keyboard_state[BACKEND_KEYBOARD_TOTAL];
+
 static SDL_Surface *cursor_surface;
 static SDL_Cursor *cursor;
 
@@ -97,8 +97,6 @@
 
 BOOL Backend_SystemTask(void)
 {
-	memcpy(backend_previous_keyboard_state, backend_keyboard_state, sizeof(backend_keyboard_state));
-
 	while (SDL_PollEvent(NULL) || !bActive)
 	{
 		SDL_Event event;
@@ -238,6 +236,11 @@
 	}
 
 	return TRUE;
+}
+
+void Backend_GetKeyboardState(BOOL *out_keyboard_state)
+{
+	memcpy(out_keyboard_state, keyboard_state, sizeof(keyboard_state));
 }
 
 void Backend_ShowMessageBox(const char *title, const char *message)
--- a/src/Input.h
+++ b/src/Input.h
@@ -8,7 +8,7 @@
 	BOOL bRight;
 	BOOL bUp;
 	BOOL bDown;
-	BOOL bButton[32];
+	BOOL bButton[32];	// The original `Input.cpp` assumed there were 32 buttons (because of DirectInput's `DIJOYSTATE` struct)
 };
 
 void ReleaseDirectInput(void);
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -277,13 +277,16 @@
 	size_t window_icon_resource_size;
 	const unsigned char *window_icon_resource_data = FindResource("ICON_MINI", "ICON", &window_icon_resource_size);
 
-	unsigned int window_icon_width, window_icon_height;
-	unsigned char *window_icon_rgb_pixels = DecodeBitmap(window_icon_resource_data, window_icon_resource_size, &window_icon_width, &window_icon_height);
-
-	if (window_icon_rgb_pixels != NULL)
+	if (window_icon_resource_data != NULL)
 	{
-		Backend_SetWindowIcon(window_icon_rgb_pixels, window_icon_width, window_icon_height);
-		FreeBitmap(window_icon_rgb_pixels);
+		unsigned int window_icon_width, window_icon_height;
+		unsigned char *window_icon_rgb_pixels = DecodeBitmap(window_icon_resource_data, window_icon_resource_size, &window_icon_width, &window_icon_height);
+
+		if (window_icon_rgb_pixels != NULL)
+		{
+			Backend_SetWindowIcon(window_icon_rgb_pixels, window_icon_width, window_icon_height);
+			FreeBitmap(window_icon_rgb_pixels);
+		}
 	}
 #endif
 
@@ -291,13 +294,16 @@
 	size_t cursor_resource_size;
 	const unsigned char *cursor_resource_data = FindResource("CURSOR_NORMAL", "CURSOR", &cursor_resource_size);
 
-	unsigned int cursor_width, cursor_height;
-	unsigned char *cursor_rgb_pixels = DecodeBitmap(cursor_resource_data, cursor_resource_size, &cursor_width, &cursor_height);
-
-	if (cursor_rgb_pixels != NULL)
+	if (cursor_resource_data != NULL)
 	{
-		Backend_SetCursor(cursor_rgb_pixels, cursor_width, cursor_height);
-		FreeBitmap(cursor_rgb_pixels);
+		unsigned int cursor_width, cursor_height;
+		unsigned char *cursor_rgb_pixels = DecodeBitmap(cursor_resource_data, cursor_resource_size, &cursor_width, &cursor_height);
+
+		if (cursor_rgb_pixels != NULL)
+		{
+			Backend_SetCursor(cursor_rgb_pixels, cursor_width, cursor_height);
+			FreeBitmap(cursor_rgb_pixels);
+		}
 	}
 
 	if (IsKeyFile("fps"))
@@ -379,12 +385,17 @@
 
 BOOL SystemTask(void)
 {
+	static BOOL previous_keyboard_state[BACKEND_KEYBOARD_TOTAL];
+
 	if (!Backend_SystemTask())
 		return FALSE;
 
+	BOOL keyboard_state[BACKEND_KEYBOARD_TOTAL];
+	Backend_GetKeyboardState(keyboard_state);
+
 	for (unsigned int i = 0; i < BACKEND_KEYBOARD_TOTAL; ++i)
 	{
-		if ((backend_keyboard_state[i] ^ backend_previous_keyboard_state[i]) & backend_keyboard_state[i])
+		if (keyboard_state[i] && !previous_keyboard_state[i])
 		{
 			switch (i)
 			{
@@ -470,7 +481,7 @@
 					break;
 			}
 		}
-		else if ((backend_keyboard_state[i] ^ backend_previous_keyboard_state[i]) & backend_previous_keyboard_state[i])
+		else if (!keyboard_state[i] && previous_keyboard_state[i])
 		{
 			switch (i)
 			{
@@ -554,6 +565,8 @@
 		}
 	}
 
+	memcpy(previous_keyboard_state, keyboard_state, sizeof(keyboard_state));
+
 	// Run joystick code
 	if (gbUseJoystick)
 		JoystickProc();
@@ -569,7 +582,7 @@
 	if (!GetJoystickStatus(&status))
 		return;
 
-	gKey &= (KEY_ESCAPE | KEY_F2 | KEY_F1);
+	gKey &= (KEY_ESCAPE | KEY_F1 | KEY_F2);
 
 	// Set movement buttons
 	if (status.bLeft)