#define _WIN32_WINNT 0x0501 #include #include "video.h" #include "wx-sdl2-video.h" #include "wx-utils.h" #include "ibm.h" #include "mouse.h" #include "wx-display.h" #include "plat-keyboard.h" #ifdef _WIN32 #define BITMAP WINDOWS_BITMAP #undef UNICODE #include #include #undef BITMAP #endif HHOOK hKeyboardHook; static HINSTANCE hinstance = 0; static HWND hwnd = 0; static HMENU menu = 0; #define szClassName "PCemMainWnd" #define szSubClassName "PCemSubWnd" static RAWINPUTDEVICE device; static uint16_t scancode_map[65536]; SDL_mutex* rendererMutex; SDL_cond* rendererCond; SDL_Thread* renderthread = NULL; SDL_Window* window = NULL; SDL_Window* dummy_window = NULL; int rendering = 0; int mousecapture = 0; extern int pause; extern int video_scale; extern int take_screenshot; void* window_ptr; void* menu_ptr; SDL_Rect remembered_rect; int remembered_mouse_x = 0; int remembered_mouse_y = 0; int custom_resolution_width = 640; int custom_resolution_height = 480; int win_doresize = 0; int winsizex = 640, winsizey = 480; void renderer_start(); void renderer_stop(int timeout); int trigger_fullscreen = 0; int trigger_screenshot = 0; int trigger_togglewindow = 0; int trigger_inputrelease = 0; extern void device_force_redraw(); extern void mouse_wheel_update(int); extern void toggle_fullscreen(); void display_resize(int width, int height) { winsizex = width*(video_scale+1) >> 1; winsizey = height*(video_scale+1) >> 1; SDL_Rect rect; rect.x = rect.y = 0; rect.w = winsizex; rect.h = winsizey; sdl_scale(video_fullscreen_scale, rect, &rect, winsizex, winsizey); winsizex = rect.w; winsizey = rect.h; win_doresize = 1; } void releasemouse() { if (mousecapture) { SDL_SetWindowGrab(window, SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE); mousecapture = 0; } } int is_fullscreen() { if (window) { int flags = SDL_GetWindowFlags(window); return (flags&SDL_WINDOW_FULLSCREEN) || (flags&SDL_WINDOW_FULLSCREEN_DESKTOP); } return 0; } /* This is so we can disambiguate scan codes that would otherwise conflict and get passed on incorrectly. */ UINT16 convert_scan_code(UINT16 scan_code) { switch (scan_code) { case 0xE001: return 0xF001; case 0xE002: return 0xF002; case 0xE005: return 0xF005; case 0xE006: return 0xF006; case 0xE007: return 0xF007; case 0xE071: return 0xF008; case 0xE072: return 0xF009; case 0xE07F: return 0xF00A; case 0xE0E1: return 0xF00B; case 0xE0EE: return 0xF00C; case 0xE0F1: return 0xF00D; case 0xE0FE: return 0xF00E; case 0xE0EF: return 0xF00F; default: return scan_code; } } void get_registry_key_map() { char *keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; char *valueName = "Scancode Map"; char buf[32768]; DWORD bufSize; HKEY hKey; int j; /* First, prepare the default scan code map list which is 1:1. Remappings will be inserted directly into it. 65536 bytes so scan codes fit in easily and it's easy to find what each maps too, since each array element is a scan code and provides for E0, etc. ones too. */ for (j = 0; j < 65536; j++) scancode_map[j] = convert_scan_code(j); bufSize = 32768; pclog("Preparing scan code map list...\n"); /* Get the scan code remappings from: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) { if(RegQueryValueEx(hKey, valueName, NULL, NULL, (LPBYTE)buf, &bufSize) == ERROR_SUCCESS) { UINT32 *bufEx2 = (UINT32 *) buf; int scMapCount = bufEx2[2]; pclog("%lu scan code mappings found!\n", scMapCount); if ((bufSize != 0) && (scMapCount != 0)) { UINT16 *bufEx = (UINT16 *) (buf + 12); pclog("More than zero scan code mappings found, processing...\n"); for (j = 0; j < scMapCount*2; j += 2) { /* Each scan code is 32-bit: 16 bits of remapped scan code, and 16 bits of original scan code. */ int scancode_unmapped = bufEx[j + 1]; int scancode_mapped = bufEx[j]; scancode_mapped = convert_scan_code(scancode_mapped); scancode_map[scancode_unmapped] = scancode_mapped; pclog("Scan code mapping %u detected: %X -> %X\n", scancode_unmapped, scancode_mapped, scancode_map[scancode_unmapped]); } pclog("Done processing!\n"); } } RegCloseKey(hKey); } pclog("Done preparing!\n"); } LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) { if (nCode < 0 || nCode != HC_ACTION || (!mousecapture && !video_fullscreen)) return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam; if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1;//disable windows keys if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1;//disable alt-escape BOOL bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);//checks ctrl key pressed if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; //disable ctrl-escape return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); } LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: /* pass through commands to wx window */ wx_winsendmessage(window_ptr, message, wParam, lParam); return 0; break; case WM_INPUT: { UINT size; RAWINPUT *raw; if (!infocus) break; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); raw = malloc(size); /* Here we read the raw input data for the keyboard */ GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); /* If the input is keyboard, we process it */ if (raw->header.dwType == RIM_TYPEKEYBOARD) { const RAWKEYBOARD rawKB = raw->data.keyboard; USHORT scancode = rawKB.MakeCode; // pclog("Keyboard input received: S:%X VK:%X F:%X\n", c, d, e); /* If it's not a scan code that starts with 0xE1 */ if (!(rawKB.Flags & RI_KEY_E1)) { if (rawKB.Flags & RI_KEY_E0) scancode |= (0xE0 << 8); /* Remap it according to the list from the Registry */ scancode = scancode_map[scancode]; if ((scancode >> 8) == 0xF0) scancode |= 0x100; /* Extended key code in disambiguated format */ else if ((scancode >> 8) == 0xE0) scancode |= 0x80; /* Normal extended key code */ /* If it's not 0 (therefore not 0xE1, 0xE2, etc), then pass it on to the rawinputkey array */ if (!(scancode & 0xf00)) rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); } } free(raw); } break; case WM_SETFOCUS: infocus=1; break; case WM_KILLFOCUS: infocus=0; if (is_fullscreen()) window_dowindowed = 1; window_doinputrelease = 1; memset(rawinputkey, 0, sizeof(rawinputkey)); break; case WM_CLOSE: case WM_DESTROY: case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: return 0; case WM_SYSCOMMAND: if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0 && (video_fullscreen || mousecapture)) return 0; /*disable ALT key for menu*/ break; default: break; } return DefWindowProc (hwnd, message, wParam, lParam); } LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } int display_init() { SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1"); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { printf("SDL could not initialize! Error: %s\n", SDL_GetError()); return 0; } SDL_version ver; SDL_GetVersion(&ver); printf("SDL %i.%i.%i initialized.\n", ver.major, ver.minor, ver.patch); return 1; } void display_close() { SDL_Quit(); } void display_start(void* wnd_ptr) { window_ptr = wnd_ptr; menu_ptr = wx_getmenu(wnd_ptr); get_registry_key_map(); infocus = 1; atexit(releasemouse); rendererMutex = SDL_CreateMutex(); rendererCond = SDL_CreateCond(); renderer_start(); } void display_stop() { renderer_stop(10 * 1000); SDL_DestroyMutex(rendererMutex); SDL_DestroyCond(rendererCond); SDL_DetachThread(renderthread); releasemouse(); } void sdl_set_window_title(const char* title) { if (hwnd && !is_fullscreen()) SetWindowText(hwnd, title); } int get_border_size(int* top, int* left, int* bottom, int* right) { int res = SDL_GetWindowBordersSize(window, top, left, bottom, right); if (top) *top -= GetSystemMetrics(SM_CYMENUSIZE); return res; } static const struct { SDL_Scancode sdl; int system; } SDLScancodeToSystemScancode[] = { { SDL_SCANCODE_A, 0x1e }, { SDL_SCANCODE_B, 0x30 }, { SDL_SCANCODE_C, 0x2e }, { SDL_SCANCODE_D, 0x20 }, { SDL_SCANCODE_E, 0x12 }, { SDL_SCANCODE_F, 0x21 }, { SDL_SCANCODE_G, 0x22 }, { SDL_SCANCODE_H, 0x23 }, { SDL_SCANCODE_I, 0x17 }, { SDL_SCANCODE_J, 0x24 }, { SDL_SCANCODE_K, 0x25 }, { SDL_SCANCODE_L, 0x26 }, { SDL_SCANCODE_M, 0x32 }, { SDL_SCANCODE_N, 0x31 }, { SDL_SCANCODE_O, 0x18 }, { SDL_SCANCODE_P, 0x19 }, { SDL_SCANCODE_Q, 0x10 }, { SDL_SCANCODE_R, 0x13 }, { SDL_SCANCODE_S, 0x1f }, { SDL_SCANCODE_T, 0x14 }, { SDL_SCANCODE_U, 0x16 }, { SDL_SCANCODE_V, 0x2f }, { SDL_SCANCODE_W, 0x11 }, { SDL_SCANCODE_X, 0x2d }, { SDL_SCANCODE_Y, 0x15 }, { SDL_SCANCODE_Z, 0x2c }, { SDL_SCANCODE_0, 0x0B }, { SDL_SCANCODE_1, 0x02 }, { SDL_SCANCODE_2, 0x03 }, { SDL_SCANCODE_3, 0x04 }, { SDL_SCANCODE_4, 0x05 }, { SDL_SCANCODE_5, 0x06 }, { SDL_SCANCODE_6, 0x07 }, { SDL_SCANCODE_7, 0x08 }, { SDL_SCANCODE_8, 0x09 }, { SDL_SCANCODE_9, 0x0A }, { SDL_SCANCODE_GRAVE, 0x29 }, { SDL_SCANCODE_MINUS, 0x0c }, { SDL_SCANCODE_EQUALS, 0x0d }, { SDL_SCANCODE_NONUSBACKSLASH, 0x56 }, { SDL_SCANCODE_BACKSLASH, 0x2b }, { SDL_SCANCODE_BACKSPACE, 0x0e }, { SDL_SCANCODE_SPACE, 0x39 }, { SDL_SCANCODE_TAB, 0x0f }, { SDL_SCANCODE_CAPSLOCK, 0x3a }, { SDL_SCANCODE_LSHIFT, 0x2a }, { SDL_SCANCODE_LCTRL, 0x1d }, { SDL_SCANCODE_LGUI, 0xdb }, { SDL_SCANCODE_LALT, 0x38 }, { SDL_SCANCODE_RSHIFT, 0x36 }, { SDL_SCANCODE_RCTRL, 0x9d }, { SDL_SCANCODE_RGUI, 0xdc }, { SDL_SCANCODE_RALT, 0xb8 }, { SDL_SCANCODE_SYSREQ, 0x54 }, { SDL_SCANCODE_APPLICATION, 0xdd }, { SDL_SCANCODE_RETURN, 0x1c }, { SDL_SCANCODE_ESCAPE, 0x01 }, { SDL_SCANCODE_F1, 0x3B }, { SDL_SCANCODE_F2, 0x3C }, { SDL_SCANCODE_F3, 0x3D }, { SDL_SCANCODE_F4, 0x3e }, { SDL_SCANCODE_F5, 0x3f }, { SDL_SCANCODE_F6, 0x40 }, { SDL_SCANCODE_F7, 0x41 }, { SDL_SCANCODE_F8, 0x42 }, { SDL_SCANCODE_F9, 0x43 }, { SDL_SCANCODE_F10, 0x44 }, { SDL_SCANCODE_F11, 0x57 }, { SDL_SCANCODE_F12, 0x58 }, { SDL_SCANCODE_SCROLLLOCK, 0x46 }, { SDL_SCANCODE_LEFTBRACKET, 0x1a }, { SDL_SCANCODE_RIGHTBRACKET, 0x1b }, { SDL_SCANCODE_INSERT, 0xd2 }, { SDL_SCANCODE_HOME, 0xc7 }, { SDL_SCANCODE_PAGEUP, 0xc9 }, { SDL_SCANCODE_DELETE, 0xd3 }, { SDL_SCANCODE_END, 0xcf }, { SDL_SCANCODE_PAGEDOWN, 0xd1 }, { SDL_SCANCODE_UP, 0xc8 }, { SDL_SCANCODE_LEFT, 0xcb }, { SDL_SCANCODE_DOWN, 0xd0 }, { SDL_SCANCODE_RIGHT, 0xcd }, { SDL_SCANCODE_NUMLOCKCLEAR, 0x45 }, { SDL_SCANCODE_KP_DIVIDE, 0xb5 }, { SDL_SCANCODE_KP_MULTIPLY, 0x37 }, { SDL_SCANCODE_KP_MINUS, 0x4a }, { SDL_SCANCODE_KP_PLUS, 0x4e }, { SDL_SCANCODE_KP_ENTER, 0x9c }, { SDL_SCANCODE_KP_PERIOD, 0x53 }, { SDL_SCANCODE_KP_0, 0x52 }, { SDL_SCANCODE_KP_1, 0x4f }, { SDL_SCANCODE_KP_2, 0x50 }, { SDL_SCANCODE_KP_3, 0x51 }, { SDL_SCANCODE_KP_4, 0x48 }, { SDL_SCANCODE_KP_5, 0x4c }, { SDL_SCANCODE_KP_6, 0x4d }, { SDL_SCANCODE_KP_7, 0x47 }, { SDL_SCANCODE_KP_8, 0x48 }, { SDL_SCANCODE_KP_9, 0x49 }, { SDL_SCANCODE_SEMICOLON, 0x27 }, { SDL_SCANCODE_APOSTROPHE, 0x28 }, { SDL_SCANCODE_COMMA, 0x33 }, { SDL_SCANCODE_PERIOD, 0x34 }, { SDL_SCANCODE_SLASH, 0x35 }, { SDL_SCANCODE_PRINTSCREEN, 0xb7 } }; int sdl_scancode(SDL_Scancode scancode) { int i; for (i = 0; i < SDL_arraysize(SDLScancodeToSystemScancode); ++i) { if (SDLScancodeToSystemScancode[i].sdl == scancode) { return SDLScancodeToSystemScancode[i].system; } } return -1; } SDL_Event event; SDL_Rect rect; int border_x, border_y = 0; uint64_t render_time = 0; int render_fps = 0; uint32_t render_frame_time = 0; uint32_t render_frames = 0; void window_setup() { SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "0"); SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1"); if (start_in_fullscreen) { start_in_fullscreen = 0; window_dofullscreen = 1; window_doinputgrab = 1; } if (window_remember) { rect.x = window_x; rect.y = window_y; rect.w = window_w; rect.h = window_h; } else { rect.x = SDL_WINDOWPOS_CENTERED; rect.y = SDL_WINDOWPOS_CENTERED; rect.w = 640; rect.h = 480; } if (vid_resize == 2) { rect.w = custom_resolution_width; rect.h = custom_resolution_height; } } int window_create() { int i; WNDCLASSEX wincl; /* Data structure for the windowclass */ hinstance = (HINSTANCE)GetModuleHandle(NULL); /* The Window structure */ wincl.hInstance = hinstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = CS_DBLCLKS; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = NULL;//LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx(&wincl)) return 0; wincl.lpszClassName = szSubClassName; wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */ if (!RegisterClassEx(&wincl)) return 0; menu = CreateMenu(); HMENU native_menu = (HMENU)wx_getnativemenu(menu_ptr); int count = GetMenuItemCount(native_menu); MENUITEMINFO info; for (i = 0; i < count; ++i) { char label[256]; memset(&info, 0, sizeof(MENUITEMINFO)); info.cbSize = sizeof(MENUITEMINFO); info.fMask = MIIM_TYPE | MIIM_ID; info.fType = MFT_STRING; info.cch = 256; info.dwTypeData = label; if (GetMenuItemInfo(native_menu, i, 1, &info)) AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)GetSubMenu(native_menu, i), info.dwTypeData); } /* The class is registered, let's create the program*/ hwnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ "PCem v14", /* Title Text */ WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ menu, /* Menu */ hinstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); /* Make the window visible on the screen */ ShowWindow(hwnd, 1); memset(rawinputkey, 0, sizeof(rawinputkey)); device.usUsagePage = 0x01; device.usUsage = 0x06; device.dwFlags = RIDEV_NOHOTKEYS; device.hwndTarget = hwnd; if (RegisterRawInputDevices(&device, 1, sizeof(device))) pclog("Raw input registered!\n"); else pclog("Raw input registration failed!\n"); hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); if (requested_render_driver.sdl_window_params & SDL_WINDOW_OPENGL) { /* create dummy window for opengl */ dummy_window = SDL_CreateWindow("GL3 test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); if (dummy_window) { char ptr[32]; snprintf(ptr, 31, "%p", dummy_window); ptr[31] = 0; SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, ptr); } } window = SDL_CreateWindowFrom(hwnd); if (!window) { char message[200]; sprintf(message, "SDL window could not be created! Error: %s\n", SDL_GetError()); wx_messagebox(window_ptr, message, "SDL Error", WX_MB_OK); return 0; } SDL_SetWindowPosition(window, rect.x, rect.y); SDL_SetWindowSize(window, rect.w, rect.h); if (vid_resize) window_dosetresize = 1; render_time = 0; render_fps = 0; render_frame_time = SDL_GetTicks(); render_frames = 0; return 1; } void window_close() { int i; sdl_renderer_close(); int count = GetMenuItemCount(menu); for (i = 0; i < count; ++i) RemoveMenu(menu, 0, MF_BYPOSITION); DestroyMenu(menu); menu = 0; SetMenu(hwnd, 0); if (window) { SDL_GetWindowPosition(window, &rect.x, &rect.y); SDL_GetWindowSize(window, &rect.w, &rect.h); get_border_size(&border_y, &border_x, 0, 0); rect.x -= border_x; rect.y -= border_y; SDL_DestroyWindow(window); } window = NULL; if (dummy_window) { SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, ""); SDL_DestroyWindow(dummy_window); } dummy_window = NULL; UnhookWindowsHookEx( hKeyboardHook ); DestroyWindow(hwnd); hwnd = NULL; UnregisterClass(szSubClassName, hinstance); UnregisterClass(szClassName, hinstance); } int render() { uint64_t start_time = timer_read(); uint64_t end_time; if (window_doreset) { pclog("window_doreset\n"); window_doreset = 0; renderer_doreset = 0; return 0; } if (window_dosetresize) { window_dosetresize = 0; SDL_GetWindowSize(window, &rect.w, &rect.h); SDL_SetWindowResizable(window, vid_resize == 1); SDL_SetWindowSize(window, rect.w, rect.h); if (vid_resize == 2) SDL_SetWindowSize(window, custom_resolution_width, custom_resolution_height); device_force_redraw(); } if (renderer_doreset) { pclog("renderer_doreset\n"); renderer_doreset = 0; sdl_renderer_close(); sdl_renderer_init(window); device_force_redraw(); video_wait_for_blit(); } while(SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONUP: if (!mousecapture) { if (event.button.button == SDL_BUTTON_LEFT && !pause) { window_doinputgrab = 1; if (video_fullscreen) window_dofullscreen = 1; } } else if (event.button.button == SDL_BUTTON_MIDDLE && !is_fullscreen() && !(mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) window_doinputrelease = 1; break; case SDL_MOUSEWHEEL: if (mousecapture) mouse_wheel_update(event.wheel.y); break; case SDL_WINDOWEVENT: if (event.window.event == SDL_WINDOWEVENT_CLOSE) wx_stop_emulation(window_ptr); if (event.window.event == SDL_WINDOWEVENT_RESIZED) device_force_redraw(); if (window_remember) { int flags = SDL_GetWindowFlags(window); if (!(flags&SDL_WINDOW_FULLSCREEN) && !(flags&SDL_WINDOW_FULLSCREEN_DESKTOP)) { if (event.window.event == SDL_WINDOWEVENT_MOVED) { get_border_size(&border_y, &border_x, 0, 0); window_x = event.window.data1-border_x; window_y = event.window.data2-border_y; } else if (event.window.event == SDL_WINDOWEVENT_RESIZED) { window_w = event.window.data1; window_h = event.window.data2; } //save_window_pos = 1; } } break; } } if (rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEDOWN)] && (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) && (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)])) trigger_fullscreen = 1; else if (trigger_fullscreen) { trigger_fullscreen = 0; toggle_fullscreen(); } else if (rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEUP)] && (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) && (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)])) trigger_screenshot = 1; else if (trigger_screenshot) { trigger_screenshot = 0; take_screenshot = 1; } else if (event.key.keysym.scancode == SDL_SCANCODE_END && (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)])) trigger_inputrelease = 1; else if (trigger_inputrelease) { trigger_inputrelease = 0; if (!is_fullscreen()) window_doinputrelease = 1; } if (window_doremember) { window_doremember = 0; SDL_GetWindowPosition(window, &window_x, &window_y); SDL_GetWindowSize(window, &window_w, &window_h); get_border_size(&border_y, &border_x, 0, 0); window_x -= border_x; window_y -= border_y; saveconfig(NULL); } if (window_dotogglefullscreen) { window_dotogglefullscreen = 0; if (SDL_GetWindowGrab(window) || is_fullscreen()) { window_doinputrelease = 1; if (is_fullscreen()) window_dowindowed = 1; } else { window_doinputgrab = 1; window_dofullscreen = 1; } } if (window_dofullscreen) { window_dofullscreen = 0; SetMenu(hwnd, 0); video_wait_for_blit(); SDL_RaiseWindow(window); SDL_GetGlobalMouseState(&remembered_mouse_x, &remembered_mouse_y); SDL_GetWindowPosition(window, &remembered_rect.x, &remembered_rect.y); get_border_size(&border_y, &border_x, 0, 0); remembered_rect.x -= border_x; remembered_rect.y -= border_y; SDL_GetWindowSize(window, &remembered_rect.w, &remembered_rect.h); SDL_SetWindowFullscreen(window, video_fullscreen_mode == 0 ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN); device_force_redraw(); } if (window_doinputgrab) { window_doinputgrab = 0; mousecapture = 1; SDL_GetRelativeMouseState(0, 0); SDL_SetWindowGrab(window, SDL_TRUE); SDL_SetRelativeMouseMode(SDL_TRUE); } if (mousecapture) { SDL_Rect rect; SDL_GetWindowSize(window, &rect.w, &rect.h); SDL_WarpMouseInWindow(window, rect.w/2, rect.h/2); } if (window_doinputrelease) { window_doinputrelease = 0; releasemouse(); } if (window_dowindowed) { window_dowindowed = 0; SetMenu(hwnd, menu); SDL_SetWindowFullscreen(window, 0); SDL_SetWindowSize(window, remembered_rect.w, remembered_rect.h); SDL_SetWindowPosition(window, remembered_rect.x, remembered_rect.y); SDL_WarpMouseGlobal(remembered_mouse_x, remembered_mouse_y); device_force_redraw(); } if (win_doresize) { int flags = SDL_GetWindowFlags(window); win_doresize = 0; if (!vid_resize || (flags&SDL_WINDOW_FULLSCREEN)) { SDL_GetWindowSize(window, &rect.w, &rect.h); if (rect.w != winsizex || rect.h != winsizey) { SDL_GetWindowPosition(window, &rect.x, &rect.y); SDL_SetWindowSize(window, winsizex, winsizey); SDL_SetWindowPosition(window, rect.x, rect.y); device_force_redraw(); } } } if (sdl_renderer_update(window)) sdl_renderer_present(window); end_time = timer_read(); render_time += end_time - start_time; ++render_frames; uint32_t ticks = SDL_GetTicks(); if (ticks-render_frame_time >= 1000) { render_fps = render_frames/((ticks-render_frame_time)/1000.0); render_frames = 0; render_frame_time = ticks; } return 1; } int renderer_thread(void* params) { int internal_rendering; SDL_LockMutex(rendererMutex); SDL_CondSignal(rendererCond); SDL_UnlockMutex(rendererMutex); window_setup(); rendering = 1; while (rendering) { if (!window_create()) rendering = 0; renderer_doreset = 1; internal_rendering = 1; while (rendering && internal_rendering) { if (!render()) internal_rendering = 0; SDL_Delay(1); } window_close(); } SDL_LockMutex(rendererMutex); SDL_CondSignal(rendererCond); SDL_UnlockMutex(rendererMutex); return SDL_TRUE; } void* timer = 0; void render_timer() { #ifdef PCEM_RENDER_TIMER_LOOP /* For some reason this while-loop works on OSX, which also fixes missing events. No idea why though. */ renderer_thread(0); #else if (rendering && !render()) { window_close(); window_create(); renderer_doreset = 1; } #endif } void render_start_timer() { #ifdef PCEM_RENDER_TIMER_LOOP timer = wx_createtimer(render_timer); wx_starttimer(timer, 500, 1); #else window_setup(); if (window_create()) { rendering = 1; renderer_doreset = 1; wx_starttimer(timer, 1, 0); } #endif } void renderer_start() { if (!rendering) { #ifdef PCEM_RENDER_WITH_TIMER render_start_timer(); #else SDL_LockMutex(rendererMutex); renderthread = SDL_CreateThread(renderer_thread, "SDL2 Thread", NULL); SDL_CondWait(rendererCond, rendererMutex); SDL_UnlockMutex(rendererMutex); #endif } } void renderer_stop(int timeout) { #if defined(PCEM_RENDER_WITH_TIMER) && !defined(PCEM_RENDER_TIMER_LOOP) rendering = 0; window_close(); wx_destroytimer(timer); #else if (rendering) { SDL_LockMutex(rendererMutex); rendering = 0; if (timeout) SDL_CondWaitTimeout(rendererCond, rendererMutex, timeout); else SDL_CondWait(rendererCond, rendererMutex); SDL_UnlockMutex(rendererMutex); renderthread = NULL; } if (timer) wx_destroytimer(timer); #endif }