diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c index 8ed7cd7526..cb4d05f694 100644 --- a/gfx/context/wgl_ctx.c +++ b/gfx/context/wgl_ctx.c @@ -175,6 +175,13 @@ static void create_gl_context(HWND hwnd) } } +#ifdef __cplusplus +extern "C" +#endif +bool dinput_handle_message(void *dinput, UINT message, WPARAM wParam, LPARAM lParam); + +static void *dinput; + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { @@ -226,7 +233,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; } - + if (dinput_handle_message(dinput, message, wparam, lparam)) + return 0; return DefWindowProc(hwnd, message, wparam, lparam); } @@ -512,7 +520,7 @@ static void gfx_ctx_destroy(void) static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data) { - void *dinput = input_dinput.init(); + dinput = input_dinput.init(); *input = dinput ? &input_dinput : NULL; *input_data = dinput; } diff --git a/gfx/d3d9/d3d9.cpp b/gfx/d3d9/d3d9.cpp index ae9093a48f..980daa3871 100644 --- a/gfx/d3d9/d3d9.cpp +++ b/gfx/d3d9/d3d9.cpp @@ -60,11 +60,17 @@ namespace Monitor static unsigned cur_mon_id; } +#ifdef __cplusplus +extern "C" +#endif +bool dinput_handle_message(void *dinput, UINT message, WPARAM wParam, LPARAM lParam); + namespace Callback { static bool quit = false; static D3DVideo *curD3D = nullptr; static HRESULT d3d_err; + static void *dinput; LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -98,10 +104,9 @@ namespace Callback if (new_width && new_height) curD3D->resize(new_width, new_height); return 0; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); } + if (dinput_handle_message(dinput, message, wParam, lParam)) + return 0; return DefWindowProc(hWnd, message, wParam, lParam); } } @@ -1317,9 +1322,9 @@ static void *d3d9_init(const video_info_t *info, const input_driver_t **input, if (input && input_data) { - void *dinput = input_dinput.init(); - *input = dinput ? &input_dinput : nullptr; - *input_data = dinput; + Callback::dinput = input_dinput.init(); + *input = Callback::dinput ? &input_dinput : nullptr; + *input_data = Callback::dinput; } return vid; diff --git a/input/dinput.c b/input/dinput.c index 8d178c8a38..9a95ff848e 100644 --- a/input/dinput.c +++ b/input/dinput.c @@ -27,10 +27,19 @@ #include #include #include +#include // Context has to be global as joypads also ride on this context. static LPDIRECTINPUT8 g_ctx; +struct pointer_status +{ + int pointer_id; + int pointer_x; + int pointer_y; + struct pointer_status *next; +}; + struct dinput_input { LPDIRECTINPUTDEVICE8 keyboard; @@ -43,6 +52,7 @@ struct dinput_input int mouse_x; int mouse_y; bool mouse_l, mouse_r, mouse_m; + struct pointer_status pointer_head; // dummy head for easier iteration }; struct dinput_joypad @@ -234,11 +244,22 @@ static int16_t dinput_mouse_state(struct dinput_input *di, unsigned id) static int16_t dinput_pointer_state(struct dinput_input *di, unsigned index, unsigned id, bool screen) { - if (index != 0) + int16_t res_x = 0, res_y = 0, res_screen_x = 0, res_screen_y = 0; + unsigned num = 0; + struct pointer_status *check_pos = di->pointer_head.next; + while (check_pos && num < index) + { + num++; + check_pos = check_pos->next; + } + if (!check_pos && index > 0) // index = 0 has mouse fallback return 0; - int16_t res_x = 0, res_y = 0, res_screen_x = 0, res_screen_y = 0; - bool valid = input_translate_coord_viewport(di->mouse_x, di->mouse_y, + int x = check_pos ? check_pos->pointer_x : di->mouse_x; + int y = check_pos ? check_pos->pointer_y : di->mouse_y; + bool pointer_down = check_pos ? true : di->mouse_l; + + bool valid = input_translate_coord_viewport(x, y, &res_x, &res_y, &res_screen_x, &res_screen_y); if (!valid) @@ -262,7 +283,7 @@ static int16_t dinput_pointer_state(struct dinput_input *di, unsigned index, uns case RETRO_DEVICE_ID_POINTER_Y: return res_y; case RETRO_DEVICE_ID_POINTER_PRESSED: - return di->mouse_l; + return pointer_down; default: return 0; } @@ -299,6 +320,116 @@ static int16_t dinput_input_state(void *data, } } +// these are defined in later SDKs, thus ifdeffed +#ifndef WM_POINTERUPDATE +#define WM_POINTERUPDATE 0x0245 +#endif +#ifndef WM_POINTERDOWN +#define WM_POINTERDOWN 0x0246 +#endif +#ifndef WM_POINTERUP +#define WM_POINTERUP 0x0247 +#endif +#ifndef GET_POINTERID_WPARAM +#define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam)) +#endif + +// stores x/y in client coordinates +void dinput_pointer_store_pos(struct pointer_status *pointer, WPARAM lParam) +{ + POINT point; + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + ScreenToClient((HWND)driver.video_window, &point); + pointer->pointer_x = point.x; + pointer->pointer_y = point.y; +} + +void dinput_add_pointer(struct dinput_input *di, struct pointer_status *new_pointer) +{ + new_pointer->next = NULL; + struct pointer_status *insert_pos = &di->pointer_head; + while (insert_pos->next) + insert_pos = insert_pos->next; + insert_pos->next = new_pointer; +} + +void dinput_delete_pointer(struct dinput_input *di, int pointer_id) +{ + struct pointer_status *check_pos = &di->pointer_head; + while (check_pos && check_pos->next) + { + if (check_pos->next->pointer_id == pointer_id) + { + struct pointer_status *to_delete = check_pos->next; + check_pos->next = check_pos->next->next; + free(to_delete); + } + check_pos = check_pos->next; + } +} + +struct pointer_status *dinput_find_pointer(struct dinput_input *di, int pointer_id) +{ + struct pointer_status *check_pos = di->pointer_head.next; + while (check_pos) + { + if (check_pos->pointer_id == pointer_id) + break; + check_pos = check_pos->next; + } + return check_pos; +} + +void dinput_clear_pointers(struct dinput_input *di) +{ + struct pointer_status *pointer = &di->pointer_head; + while (pointer->next) + { + struct pointer_status *del = pointer->next; + pointer->next = pointer->next->next; + free(del); + } +} + +#ifdef __cplusplus +extern "C" +#endif +bool dinput_handle_message(void *dinput, UINT message, WPARAM wParam, LPARAM lParam) +{ + struct dinput_input *di = (struct dinput_input *)dinput; + /* WM_POINTERDOWN arrives for each new touch event with a new id - add to list + WM_POINTERUP arrives once the pointer is no longer down - remove from list + WM_POINTERUPDATE arrives for both pressed and hovering pointers - ignore hovering + */ + switch (message) + { + case WM_POINTERDOWN: + { + struct pointer_status *new_pointer = (struct pointer_status *)malloc(sizeof(struct pointer_status)); + new_pointer->pointer_id = GET_POINTERID_WPARAM(wParam); + dinput_pointer_store_pos(new_pointer, lParam); + dinput_add_pointer(di, new_pointer); + return true; + } + case WM_POINTERUP: + { + int pointer_id = GET_POINTERID_WPARAM(wParam); + dinput_delete_pointer(di, pointer_id); + return true; + } + case WM_POINTERUPDATE: + { + int pointer_id = GET_POINTERID_WPARAM(wParam); + struct pointer_status *pointer = dinput_find_pointer(di, pointer_id); + if (pointer) + dinput_pointer_store_pos(pointer, lParam); + return true; + } + } + return false; +} + static void dinput_free(void *data) { struct dinput_input *di = (struct dinput_input*)data; @@ -310,6 +441,8 @@ static void dinput_free(void *data) di->joypad->destroy(); g_ctx = hold_ctx; + dinput_clear_pointers(di); // clear any leftover pointers + if (di->keyboard) IDirectInputDevice8_Release(di->keyboard); diff --git a/media/rarch.manifest b/media/rarch.manifest new file mode 100644 index 0000000000..aad83c561a --- /dev/null +++ b/media/rarch.manifest @@ -0,0 +1,8 @@ + + + + + true + + + diff --git a/media/rarch.rc b/media/rarch.rc index 271494820e..02a5c5afef 100644 --- a/media/rarch.rc +++ b/media/rarch.rc @@ -1 +1,2 @@ 1 ICON "retroarch-icon.ico" +1 24 "rarch.manifest"