diff --git a/Makefile.win b/Makefile.win index 75b5a6775e..99a61861fd 100644 --- a/Makefile.win +++ b/Makefile.win @@ -20,14 +20,14 @@ OBJ = retroarch.o \ audio/utils.o \ audio/null.o \ input/null.o \ + fifo_buffer.o \ gfx/null.o JOBJ := conf/config_file.o \ tools/retroarch-joyconfig.o \ compat/compat.o \ input/input_common.o \ - input/dinput.o \ - input/sdl_joypad.o + input/dinput.o CC = gcc CXX = g++ @@ -35,7 +35,6 @@ CXX = g++ HAVE_DINPUT = 1 HAVE_XAUDIO = 1 HAVE_DSOUND = 1 -HAVE_SDL = 1 HAVE_OPENGL = 1 HAVE_DYLIB = 1 HAVE_NETPLAY = 1 @@ -44,6 +43,7 @@ HAVE_THREADS = 1 DYNAMIC = 1 ifeq ($(SLIM),) + HAVE_SDL = 1 HAVE_SDL_IMAGE = 1 HAVE_XML = 1 HAVE_FREETYPE = 1 @@ -57,21 +57,28 @@ endif libretro ?= -lretro LIBS = -lm -DEFINES = -I. -DHAVE_CONFIGFILE -DHAVE_SDL -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.7\" +DEFINES = -I. -DHAVE_CONFIGFILE -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.7\" LDFLAGS = -L. -static-libgcc ifeq ($(TDM_GCC),) LDCXXFLAGS += -static-libstdc++ endif -ifeq ($(HAVE_SDL), 1) - OBJ += gfx/sdl_gfx.o gfx/gl.o gfx/math/matrix.o gfx/fonts/freetype.o gfx/context/sdl_ctx.o gfx/gfx_context.o input/sdl_input.o input/sdl_joypad.o audio/sdl_audio.o fifo_buffer.o - OBJ += gfx/scaler/scaler.o gfx/scaler/pixconv.o gfx/scaler/scaler_int.o gfx/scaler/filter.o - LIBS += -lSDL - DEFINES += -ISDL -DHAVE_SDL ifeq ($(SCALER_NO_SIMD), 1) DEFINES += -DSCALER_NO_SIMD endif + +ifeq ($(HAVE_SDL), 1) + OBJ += gfx/scaler/scaler.o gfx/scaler/pixconv.o gfx/scaler/scaler_int.o gfx/scaler/filter.o +else ifeq ($(HAVE_FFMPEG), 1) + OBJ += gfx/scaler/scaler.o gfx/scaler/pixconv.o gfx/scaler/scaler_int.o gfx/scaler/filter.o +endif + +ifeq ($(HAVE_SDL), 1) + OBJ += gfx/sdl_gfx.o gfx/context/sdl_ctx.o input/sdl_input.o input/sdl_joypad.o audio/sdl_audio.o + JOBJ += input/sdl_joypad.o + LIBS += -lSDL + DEFINES += -ISDL -DHAVE_SDL endif ifeq ($(HAVE_THREADS), 1) @@ -80,8 +87,9 @@ ifeq ($(HAVE_THREADS), 1) endif ifeq ($(HAVE_OPENGL), 1) + OBJ += gfx/gl.o gfx/math/matrix.o gfx/fonts/freetype.o gfx/gfx_context.o gfx/context/wgl_ctx.o DEFINES += -DHAVE_OPENGL - LIBS += -lopengl32 + LIBS += -lopengl32 -lgdi32 endif ifeq ($(HAVE_SDL_IMAGE), 1) diff --git a/config.def.h b/config.def.h index 75bfb53ca8..f936b2a5fd 100644 --- a/config.def.h +++ b/config.def.h @@ -60,6 +60,7 @@ enum INPUT_SDL, INPUT_X, + INPUT_DINPUT, INPUT_PS3, INPUT_XENON360, INPUT_WII, @@ -130,6 +131,8 @@ enum #define INPUT_DEFAULT_DRIVER INPUT_XENON360 #elif defined(_XBOX360) || defined(_XBOX) || defined(HAVE_XINPUT2) || defined(HAVE_XINPUT_XBOX1) #define INPUT_DEFAULT_DRIVER INPUT_XINPUT +#elif defined(_WIN32) +#define INPUT_DEFAULT_DRIVER INPUT_DINPUT #elif defined(HAVE_SDL) #define INPUT_DEFAULT_DRIVER INPUT_SDL #elif defined(__CELLOS_LV2__) diff --git a/driver.h b/driver.h index 8b6c2249ea..c8c7636021 100644 --- a/driver.h +++ b/driver.h @@ -278,6 +278,7 @@ extern const video_driver_t video_vg; extern const video_driver_t video_ext; extern const video_driver_t video_null; extern const input_driver_t input_sdl; +extern const input_driver_t input_dinput; extern const input_driver_t input_x; extern const input_driver_t input_ps3; extern const input_driver_t input_xenon360; diff --git a/gfx/context/glx_ctx.c b/gfx/context/glx_ctx.c index 2a26d1bea0..7aea19ba65 100644 --- a/gfx/context/glx_ctx.c +++ b/gfx/context/glx_ctx.c @@ -312,7 +312,7 @@ static bool gfx_ctx_set_video_mode( driver.display_type = RARCH_DISPLAY_X11; driver.video_display = (uintptr_t)g_dpy; - driver.video_window = (Window)g_win; + driver.video_window = (uintptr_t)g_win; return true; diff --git a/gfx/context/sdl_ctx.c b/gfx/context/sdl_ctx.c index c608add95d..2f29421835 100644 --- a/gfx/context/sdl_ctx.c +++ b/gfx/context/sdl_ctx.c @@ -24,6 +24,8 @@ #ifdef __APPLE__ #include #include +#else +#include "SDL/SDL_syswm.h" #endif #include "SDL.h" diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c new file mode 100644 index 0000000000..29d35343ce --- /dev/null +++ b/gfx/context/wgl_ctx.c @@ -0,0 +1,371 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +// Win32/WGL context. + +#include "../../driver.h" +#include "../gfx_context.h" +#include "../gl_common.h" +#include "../gfx_common.h" +#include + +static HWND g_hwnd; +static HGLRC g_hrc; +static HDC g_hdc; + +static bool g_quit; +static bool g_inited; +static unsigned g_interval; + +static unsigned g_resize_width; +static unsigned g_resize_height; +static bool g_resized; + +static bool g_restore_desktop; + +static void gfx_ctx_get_video_size(unsigned *width, unsigned *height); +static void gfx_ctx_destroy(void); + +static BOOL (APIENTRY *p_swap_interval)(int); + +static void setup_pixel_format(HDC hdc) +{ + PIXELFORMATDESCRIPTOR pfd = {0}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 0; + pfd.cStencilBits = 0; + pfd.iLayerType = PFD_MAIN_PLANE; + + SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd); +} + +static void create_gl_context(HWND hwnd) +{ + g_hdc = GetDC(hwnd); + setup_pixel_format(g_hdc); + + g_hrc = wglCreateContext(g_hdc); + if (g_hrc) + { + if (wglMakeCurrent(g_hdc, g_hrc)) + g_inited = true; + else + g_quit = true; + } + else + g_quit = true; +} + +static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, + WPARAM wparam, LPARAM lparam) +{ + switch (message) + { + case WM_SYSCOMMAND: + // Prevent screensavers, etc, while running. + switch (wparam) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + return 0; + } + break; + + case WM_CREATE: + create_gl_context(hwnd); + return 0; + + case WM_CLOSE: + case WM_DESTROY: + case WM_QUIT: + g_quit = true; + return 0; + + case WM_SIZE: + // Do not send resize message if we minimize. + if (wparam != SIZE_MAXHIDE && wparam != SIZE_MINIMIZED) + { + g_resize_width = LOWORD(lparam); + g_resize_height = HIWORD(lparam); + g_resized = true; + } + return 0; + } + + return DefWindowProc(hwnd, message, wparam, lparam); +} + +static void gfx_ctx_swap_interval(unsigned interval) +{ + g_interval = interval; + + if (g_hrc && p_swap_interval) + { + RARCH_LOG("[WGL]: wglSwapInterval(%u)\n", g_interval); + if (!p_swap_interval(g_interval)) + RARCH_WARN("[WGL]: wglSwapInterval() failed.\n"); + } +} + +static void gfx_ctx_check_window(bool *quit, + bool *resize, unsigned *width, unsigned *height, unsigned frame_count) +{ + (void)frame_count; + + MSG msg; + while (PeekMessage(&msg, g_hwnd, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + *quit = g_quit; + if (g_resized) + { + *resize = true; + *width = g_resize_width; + *height = g_resize_height; + g_resized = false; + } +} + +static void gfx_ctx_swap_buffers(void) +{ + SwapBuffers(g_hdc); +} + +static void gfx_ctx_set_resize(unsigned width, unsigned height) +{ + (void)width; + (void)height; +} + +static void gfx_ctx_update_window_title(bool reset) +{ + if (reset) + gfx_window_title_reset(); + + char buf[128]; + if (gfx_window_title(buf, sizeof(buf))) + SetWindowText(g_hwnd, buf); +} + +static void gfx_ctx_get_video_size(unsigned *width, unsigned *height) +{ + if (!g_hwnd) + { + RECT screen_rect; + GetClientRect(GetDesktopWindow(), &screen_rect); + *width = screen_rect.right - screen_rect.left; + *height = screen_rect.bottom - screen_rect.top; + } + else + { + *width = g_resize_width; + *height = g_resize_height; + } +} + +static bool gfx_ctx_init(void) +{ + if (g_inited) + return false; + + g_quit = false; + g_restore_desktop = false; + + WNDCLASSEX wndclass = {0}; + wndclass.cbSize = sizeof(wndclass); + wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wndclass.lpfnWndProc = WndProc; + wndclass.hInstance = GetModuleHandle(NULL); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.lpszClassName = "RetroArch"; + + if (!RegisterClassEx(&wndclass)) + return false; + + return true; +} + +static bool set_fullscreen(unsigned width, unsigned height) +{ + DEVMODE devmode; + memset(&devmode, 0, sizeof(devmode)); + devmode.dmSize = sizeof(DEVMODE); + devmode.dmPelsWidth = width; + devmode.dmPelsHeight = height; + devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + + return ChangeDisplaySettings(&devmode, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL; +} + +static bool gfx_ctx_set_video_mode( + unsigned width, unsigned height, + unsigned bits, bool fullscreen) +{ + (void)bits; + + DWORD style; + RECT screen_rect; + GetClientRect(GetDesktopWindow(), &screen_rect); + + g_resize_width = width; + g_resize_height = height; + + if (fullscreen) + { + style = WS_POPUP | WS_VISIBLE; + + AdjustWindowRect(&screen_rect, style, FALSE); + width = screen_rect.right - screen_rect.left; + height = screen_rect.bottom - screen_rect.top; + + if (!set_fullscreen(width, height)) + goto error; + + g_restore_desktop = true; + } + else + { + style = WS_OVERLAPPEDWINDOW; + RECT rect = {0}; + rect.right = width; + rect.bottom = height; + AdjustWindowRect(&rect, style, FALSE); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + + g_hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", style, + CW_USEDEFAULT, CW_USEDEFAULT, width, height, + NULL, NULL, NULL, NULL); + + if (!g_hwnd) + goto error; + + if (!fullscreen) + { + ShowWindow(g_hwnd, SW_RESTORE); + UpdateWindow(g_hwnd); + SetForegroundWindow(g_hwnd); + SetFocus(g_hwnd); + } + + // Wait until GL context is created (or failed to do so ...) + MSG msg; + while (!g_inited && !g_quit && GetMessage(&msg, g_hwnd, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (g_quit) + goto error; + + p_swap_interval = (BOOL (APIENTRY *)(int))wglGetProcAddress("wglSwapIntervalEXT"); + + gfx_ctx_swap_interval(g_interval); + + driver.display_type = RARCH_DISPLAY_WIN32; + driver.video_display = 0; + driver.video_window = (uintptr_t)g_hwnd; + + return true; + +error: + gfx_ctx_destroy(); + return false; +} + +static void gfx_ctx_destroy(void) +{ + if (g_hrc) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(g_hrc); + g_hrc = NULL; + } + + if (g_hwnd && g_hdc) + { + ReleaseDC(g_hwnd, g_hdc); + g_hdc = NULL; + } + + if (g_hwnd) + { + DestroyWindow(g_hwnd); + UnregisterClass("RetroArch", GetModuleHandle(NULL)); + g_hwnd = NULL; + } + + if (g_restore_desktop) + { + ChangeDisplaySettings(NULL, 0); + g_restore_desktop = false; + } + + g_inited = false; +} + +static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data) +{ + void *dinput = input_dinput.init(); + *input = dinput ? &input_dinput : NULL; + *input_data = dinput; +} + +static bool gfx_ctx_has_focus(void) +{ + if (!g_inited) + return false; + + return GetFocus() == g_hwnd; +} + +static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol) +{ + return (gfx_ctx_proc_t)wglGetProcAddress(symbol); +} + +static bool gfx_ctx_bind_api(enum gfx_ctx_api api) +{ + return api == GFX_CTX_OPENGL_API; +} + +const gfx_ctx_driver_t gfx_ctx_wgl = { + gfx_ctx_init, + gfx_ctx_destroy, + gfx_ctx_bind_api, + gfx_ctx_swap_interval, + gfx_ctx_set_video_mode, + gfx_ctx_get_video_size, + NULL, + gfx_ctx_update_window_title, + gfx_ctx_check_window, + gfx_ctx_set_resize, + gfx_ctx_has_focus, + gfx_ctx_swap_buffers, + gfx_ctx_input_driver, + gfx_ctx_get_proc_address, + "wgl", +}; + diff --git a/gfx/context/xegl_ctx.c b/gfx/context/xegl_ctx.c index 6fbf3785ee..2b24829c57 100644 --- a/gfx/context/xegl_ctx.c +++ b/gfx/context/xegl_ctx.c @@ -334,7 +334,7 @@ static bool gfx_ctx_set_video_mode( driver.display_type = RARCH_DISPLAY_X11; driver.video_display = (uintptr_t)g_dpy; - driver.video_window = (Window)g_win; + driver.video_window = (uintptr_t)g_win; return true; diff --git a/gfx/gfx_context.c b/gfx/gfx_context.c index e4c97a7978..b1bdc877f6 100644 --- a/gfx/gfx_context.c +++ b/gfx/gfx_context.c @@ -27,6 +27,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { #if defined(HAVE_VIDEOCORE) &gfx_ctx_videocore, #endif +#if defined(_WIN32) && defined(HAVE_OPENGL) + &gfx_ctx_wgl, +#endif #if defined(HAVE_X11) && defined(HAVE_OPENGL) && !defined(HAVE_OPENGLES) &gfx_ctx_glx, #endif diff --git a/gfx/gfx_context.h b/gfx/gfx_context.h index 29a1cf8922..69604f89ab 100644 --- a/gfx/gfx_context.h +++ b/gfx/gfx_context.h @@ -23,10 +23,6 @@ #include "../config.h" #endif -#if defined(HAVE_SDL) && !defined(__APPLE__) -#include "SDL_syswm.h" -#endif - enum gfx_ctx_api { GFX_CTX_OPENGL_API, @@ -102,6 +98,7 @@ extern const gfx_ctx_driver_t gfx_ctx_x_egl; extern const gfx_ctx_driver_t gfx_ctx_glx; extern const gfx_ctx_driver_t gfx_ctx_drm_egl; extern const gfx_ctx_driver_t gfx_ctx_ps3; +extern const gfx_ctx_driver_t gfx_ctx_wgl; extern const gfx_ctx_driver_t gfx_ctx_videocore; const gfx_ctx_driver_t *gfx_ctx_find_driver(const char *ident); // Finds driver with ident. Does not initialize. diff --git a/gfx/sdl_gfx.c b/gfx/sdl_gfx.c index efedfdfb07..37027751b4 100644 --- a/gfx/sdl_gfx.c +++ b/gfx/sdl_gfx.c @@ -34,6 +34,10 @@ #include "fonts/fonts.h" #endif +#ifndef __APPLE__ // Broken on OSX. +#include "SDL/SDL_syswm.h" +#endif + static void convert_15bit_15bit_direct(uint16_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt); static void convert_32bit_32bit_direct(uint32_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt); static void convert_15bit_15bit_shift(uint16_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt); diff --git a/input/dinput.c b/input/dinput.c index 66365941c8..535e967265 100644 --- a/input/dinput.c +++ b/input/dinput.c @@ -24,18 +24,291 @@ #include #include +// Context has to be global as joypads also ride on this context. static LPDIRECTINPUT8 g_ctx; +struct dinput_input +{ + LPDIRECTINPUTDEVICE8 keyboard; + LPDIRECTINPUTDEVICE8 mouse; // TODO. + const rarch_joypad_driver_t *joypad; + uint8_t state[256]; + int rk_to_di_lut[RETROK_LAST]; +}; + struct dinput_joypad { LPDIRECTINPUTDEVICE8 joypad; DIJOYSTATE2 joy_state; }; +struct key_map +{ + int di; + int rk; +}; + +static const struct key_map rk_to_di[] = { + { DIK_LEFT, RETROK_LEFT }, + { DIK_RIGHT, RETROK_RIGHT }, + { DIK_UP, RETROK_UP }, + { DIK_DOWN, RETROK_DOWN }, + { DIK_RETURN, RETROK_RETURN }, + { DIK_TAB, RETROK_TAB }, + { DIK_INSERT, RETROK_INSERT }, + { DIK_DELETE, RETROK_DELETE }, + { DIK_RSHIFT, RETROK_RSHIFT }, + { DIK_LSHIFT, RETROK_LSHIFT }, + { DIK_LCONTROL, RETROK_LCTRL }, + { DIK_END, RETROK_END }, + { DIK_HOME, RETROK_HOME }, + { DIK_NEXT, RETROK_PAGEDOWN }, + { DIK_PRIOR, RETROK_PAGEUP }, + { DIK_LALT, RETROK_LALT }, + { DIK_SPACE, RETROK_SPACE }, + { DIK_ESCAPE, RETROK_ESCAPE }, + { DIK_BACKSPACE, RETROK_BACKSPACE }, + { DIK_NUMPADENTER, RETROK_KP_ENTER }, + { DIK_NUMPADPLUS, RETROK_KP_PLUS }, + { DIK_NUMPADMINUS, RETROK_KP_MINUS }, + { DIK_NUMPADSTAR, RETROK_KP_MULTIPLY }, + { DIK_NUMPADSLASH, RETROK_KP_DIVIDE }, + { DIK_GRAVE, RETROK_BACKQUOTE }, + { DIK_PAUSE, RETROK_PAUSE }, + { DIK_NUMPAD0, RETROK_KP0 }, + { DIK_NUMPAD1, RETROK_KP1 }, + { DIK_NUMPAD2, RETROK_KP2 }, + { DIK_NUMPAD3, RETROK_KP3 }, + { DIK_NUMPAD4, RETROK_KP4 }, + { DIK_NUMPAD5, RETROK_KP5 }, + { DIK_NUMPAD6, RETROK_KP6 }, + { DIK_NUMPAD7, RETROK_KP7 }, + { DIK_NUMPAD8, RETROK_KP8 }, + { DIK_NUMPAD9, RETROK_KP9 }, + { DIK_0, RETROK_0 }, + { DIK_1, RETROK_1 }, + { DIK_2, RETROK_2 }, + { DIK_3, RETROK_3 }, + { DIK_4, RETROK_4 }, + { DIK_5, RETROK_5 }, + { DIK_6, RETROK_6 }, + { DIK_7, RETROK_7 }, + { DIK_8, RETROK_8 }, + { DIK_9, RETROK_9 }, + { DIK_F1, RETROK_F1 }, + { DIK_F2, RETROK_F2 }, + { DIK_F3, RETROK_F3 }, + { DIK_F4, RETROK_F4 }, + { DIK_F5, RETROK_F5 }, + { DIK_F6, RETROK_F6 }, + { DIK_F7, RETROK_F7 }, + { DIK_F8, RETROK_F8 }, + { DIK_F9, RETROK_F9 }, + { DIK_F10, RETROK_F10 }, + { DIK_F11, RETROK_F11 }, + { DIK_F12, RETROK_F12 }, + { DIK_A, RETROK_a }, + { DIK_B, RETROK_b }, + { DIK_C, RETROK_c }, + { DIK_D, RETROK_d }, + { DIK_E, RETROK_e }, + { DIK_F, RETROK_f }, + { DIK_G, RETROK_g }, + { DIK_H, RETROK_h }, + { DIK_I, RETROK_i }, + { DIK_J, RETROK_j }, + { DIK_K, RETROK_k }, + { DIK_L, RETROK_l }, + { DIK_M, RETROK_m }, + { DIK_N, RETROK_n }, + { DIK_O, RETROK_o }, + { DIK_P, RETROK_p }, + { DIK_Q, RETROK_q }, + { DIK_R, RETROK_r }, + { DIK_S, RETROK_s }, + { DIK_T, RETROK_t }, + { DIK_U, RETROK_u }, + { DIK_V, RETROK_v }, + { DIK_W, RETROK_w }, + { DIK_X, RETROK_x }, + { DIK_Y, RETROK_y }, + { DIK_Z, RETROK_z }, +}; + +static void init_lut(int *lut) +{ + for (unsigned i = 0; i < sizeof(rk_to_di) / sizeof(rk_to_di[0]); i++) + lut[rk_to_di[i].rk] = rk_to_di[i].di; +} + static unsigned g_joypad_cnt; static struct dinput_joypad g_pads[MAX_PLAYERS]; -static void dinput_destroy(void) +static void dinput_destroy_context(void) +{ + if (g_ctx) + { + IDirectInput8_Release(g_ctx); + g_ctx = NULL; + } +} + +static bool dinput_init_context(void) +{ + if (g_ctx) + return true; + + if (driver.display_type != RARCH_DISPLAY_WIN32) + { + RARCH_ERR("Cannot open DInput as no Win32 window is present.\n"); + return false; + } + + CoInitialize(NULL); + + // Who said we shouldn't have same call signature in a COM API? <_< +#ifdef __cplusplus + if (FAILED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, + (void**)&g_ctx, NULL))) +#else + if (FAILED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8, + (void**)&g_ctx, NULL))) +#endif + { + RARCH_ERR("Failed to init DirectInput.\n"); + return false; + } + + return true; +} + +static void *dinput_init(void) +{ + if (!dinput_init_context()) + return NULL; + + struct dinput_input *di = (struct dinput_input*)calloc(1, sizeof(*di)); + if (!di) + return NULL; + +#ifdef __cplusplus + if (FAILED(IDirectInput8_CreateDevice(g_ctx, GUID_SysKeyboard, &di->keyboard, NULL))) +#else + if (FAILED(IDirectInput8_CreateDevice(g_ctx, &GUID_SysKeyboard, &di->keyboard, NULL))) +#endif + goto error; + + IDirectInputDevice8_SetDataFormat(di->keyboard, &c_dfDIKeyboard); + IDirectInputDevice8_SetCooperativeLevel(di->keyboard, + (HWND)driver.video_window, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); + IDirectInputDevice8_Acquire(di->keyboard); + + init_lut(di->rk_to_di_lut); + di->joypad = input_joypad_init_first(); + + return di; + +error: + dinput_destroy_context(); + free(di); + return NULL; +} + +static void dinput_poll(void *data) +{ + struct dinput_input *di = (struct dinput_input*)data; + + memset(di->state, 0, sizeof(di->state)); + if (FAILED(IDirectInputDevice8_GetDeviceState(di->keyboard, + sizeof(di->state), di->state))) + { + IDirectInputDevice8_Acquire(di->keyboard); + IDirectInputDevice8_GetDeviceState(di->keyboard, sizeof(di->state), di->state); + } + + input_joypad_poll(di->joypad); +} + +static bool dinput_keyboard_pressed(struct dinput_input *di, unsigned key) +{ + if (key >= RETROK_LAST) + return false; + + return di->state[di->rk_to_di_lut[key]] & 0x80; +} + +static bool dinput_is_pressed(struct dinput_input *di, const struct retro_keybind *binds, + unsigned port, unsigned id) +{ + if (id >= RARCH_BIND_LIST_END) + return false; + + const struct retro_keybind *bind = &binds[id]; + return dinput_keyboard_pressed(di, bind->key) || input_joypad_pressed(di->joypad, port, bind); +} + +static bool dinput_key_pressed(void *data, int key) +{ + return dinput_is_pressed((struct dinput_input*)data, g_settings.input.binds[0], 0, key); +} + +static int16_t dinput_input_state(void *data, + const struct retro_keybind **binds, unsigned port, + unsigned device, unsigned index, unsigned id) +{ + struct dinput_input *di = (struct dinput_input*)data; + switch (device) + { + case RETRO_DEVICE_JOYPAD: + return dinput_is_pressed(di, binds[port], port, id); + + case RETRO_DEVICE_KEYBOARD: + return dinput_keyboard_pressed(di, id); + + case RETRO_DEVICE_ANALOG: + return input_joypad_analog(di->joypad, port, index, id, g_settings.input.binds[port]); + + case RETRO_DEVICE_MOUSE: // TODO. + case RETRO_DEVICE_LIGHTGUN: + return 0; + + default: + return 0; + } +} + +static void dinput_free(void *data) +{ + struct dinput_input *di = (struct dinput_input*)data; + LPDIRECTINPUT8 hold_ctx = g_ctx; + + if (di) + { + g_ctx = NULL; // Prevent a joypad driver to kill our context prematurely. + di->joypad->destroy(); + g_ctx = hold_ctx; + + if (di->keyboard) + IDirectInputDevice8_Release(di->keyboard); + + free(di); + } + + dinput_destroy_context(); +} + +const input_driver_t input_dinput = { + dinput_init, + dinput_poll, + dinput_input_state, + dinput_key_pressed, + dinput_free, + "dinput", +}; + +static void dinput_joypad_destroy(void) { for (unsigned i = 0; i < MAX_PLAYERS; i++) { @@ -46,12 +319,11 @@ static void dinput_destroy(void) } } - if (g_ctx) - IDirectInput8_Release(g_ctx); - - g_ctx = NULL; g_joypad_cnt = 0; memset(g_pads, 0, sizeof(g_pads)); + + // Can be blocked by global Dinput context. + dinput_destroy_context(); } static BOOL CALLBACK enum_axes_cb(const DIDEVICEOBJECTINSTANCE *inst, void *p) @@ -64,8 +336,8 @@ static BOOL CALLBACK enum_axes_cb(const DIDEVICEOBJECTINSTANCE *inst, void *p) range.diph.dwHeaderSize = sizeof(DIPROPHEADER); range.diph.dwHow = DIPH_BYID; range.diph.dwObj = inst->dwType; - range.lMin = -32768; - range.lMax = 32767; + range.lMin = -0x7fff; + range.lMax = 0x7fff; IDirectInputDevice8_SetProperty(joypad, DIPROP_RANGE, &range.diph); return DIENUM_CONTINUE; @@ -98,42 +370,19 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p) return DIENUM_CONTINUE; } -static bool dinput_init(void) +static bool dinput_joypad_init(void) { - if (driver.display_type != RARCH_DISPLAY_WIN32) - { - RARCH_ERR("Cannot open DInput as no Win32 window is present.\n"); + if (!dinput_init_context()) return false; - } - - CoInitialize(NULL); - -#ifdef __cplusplus - if (FAILED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, - (void**)&g_ctx, NULL))) -#else - if (FAILED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8, - (void**)&g_ctx, NULL))) -#endif - { - RARCH_ERR("Failed to init DirectInput.\n"); - goto error; - } - - RARCH_LOG("Enumerating DInput devices ...\n"); - IDirectInput8_EnumDevices(g_ctx, DI8DEVCLASS_GAMECTRL, enum_joypad_cb, NULL, DIEDFL_ATTACHEDONLY); - RARCH_LOG("Done enumerating DInput devices ...\n"); + RARCH_LOG("Enumerating DInput joypads ...\n"); + IDirectInput8_EnumDevices(g_ctx, DI8DEVCLASS_GAMECTRL, + enum_joypad_cb, NULL, DIEDFL_ATTACHEDONLY); + RARCH_LOG("Done enumerating DInput joypads ...\n"); return true; - -error: - dinput_destroy(); - return NULL; } -static bool dinput_button(unsigned port_num, uint16_t joykey) +static bool dinput_joypad_button(unsigned port_num, uint16_t joykey) { if (joykey == NO_BTN) return false; @@ -180,7 +429,7 @@ static bool dinput_button(unsigned port_num, uint16_t joykey) return false; } -static int16_t dinput_axis(unsigned port_num, uint32_t joyaxis) +static int16_t dinput_joypad_axis(unsigned port_num, uint32_t joyaxis) { if (joyaxis == AXIS_NONE) return 0; @@ -214,9 +463,6 @@ static int16_t dinput_axis(unsigned port_num, uint32_t joyaxis) case 5: val = pad->joy_state.lRz; break; } - if (val < -0x7fff) // So abs() of -0x8000 can't mess us up. - val = -0x7fff; - if (is_neg && val > 0) val = 0; else if (is_pos && val < 0) @@ -225,7 +471,7 @@ static int16_t dinput_axis(unsigned port_num, uint32_t joyaxis) return val; } -static void dinput_poll(void) +static void dinput_joypad_poll(void) { for (unsigned i = 0; i < MAX_PLAYERS; i++) { @@ -237,27 +483,35 @@ static void dinput_poll(void) if (FAILED(IDirectInputDevice8_Poll(pad->joypad))) { - IDirectInputDevice8_Acquire(pad->joypad); - continue; + if (FAILED(IDirectInputDevice8_Acquire(pad->joypad))) + { + memset(&pad->joy_state, 0, sizeof(DIJOYSTATE2)); + continue; + } + + // If this fails, something *really* bad must have happened. + if (FAILED(IDirectInputDevice8_Poll(pad->joypad))) + continue; } - IDirectInputDevice8_GetDeviceState(pad->joypad, sizeof(DIJOYSTATE2), &pad->joy_state); + IDirectInputDevice8_GetDeviceState(pad->joypad, + sizeof(DIJOYSTATE2), &pad->joy_state); } } } -static bool dinput_query_pad(unsigned pad) +static bool dinput_joypad_query_pad(unsigned pad) { return pad < MAX_PLAYERS && g_pads[pad].joypad; } const rarch_joypad_driver_t dinput_joypad = { - dinput_init, - dinput_query_pad, - dinput_destroy, - dinput_button, - dinput_axis, - dinput_poll, - "DInput", + dinput_joypad_init, + dinput_joypad_query_pad, + dinput_joypad_destroy, + dinput_joypad_button, + dinput_joypad_axis, + dinput_joypad_poll, + "dinput", }; diff --git a/settings.c b/settings.c index f55d0b3f7e..22b36e2708 100644 --- a/settings.c +++ b/settings.c @@ -109,6 +109,8 @@ const char *config_get_default_input(void) return "ps3"; case INPUT_SDL: return "sdl"; + case INPUT_DINPUT: + return "dinput"; case INPUT_X: return "x"; case INPUT_XENON360: