Add WGL context.

This commit is contained in:
Themaister 2012-09-30 11:26:26 +02:00
parent 9a07e23ecb
commit dd6d27c108
12 changed files with 714 additions and 69 deletions

View File

@ -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)

View File

@ -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__)

View File

@ -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;

View File

@ -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;

View File

@ -24,6 +24,8 @@
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#else
#include "SDL/SDL_syswm.h"
#endif
#include "SDL.h"

371
gfx/context/wgl_ctx.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
// Win32/WGL context.
#include "../../driver.h"
#include "../gfx_context.h"
#include "../gl_common.h"
#include "../gfx_common.h"
#include <windows.h>
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",
};

View File

@ -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;

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -24,18 +24,291 @@
#include <stddef.h>
#include <string.h>
// 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);
if (FAILED(IDirectInputDevice8_Acquire(pad->joypad)))
{
memset(&pad->joy_state, 0, sizeof(DIJOYSTATE2));
continue;
}
IDirectInputDevice8_GetDeviceState(pad->joypad, sizeof(DIJOYSTATE2), &pad->joy_state);
// 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);
}
}
}
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",
};

View File

@ -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: