mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-11 16:49:27 +01:00
Windows: --game-window, on Vulkan
A second Win32 window, added as a Game output like the SDL one. Keys typed into it still go to the emulator; the mouse doesn't. It's for testing multiple outputs (standing in for a TV over AirPlay) until real multi-window support takes it over. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
82e6ac86f0
commit
5009724d91
5 files changed
+102
-2
No files matched your search
@@ -61,6 +61,8 @@
|
||||
#include "Windows/Debugger/Debugger_MemoryDlg.h"
|
||||
|
||||
#include "Common/GPU/GraphicsContext.h"
|
||||
#include "Common/GPU/thin3d.h"
|
||||
#include "Common/SysError.h"
|
||||
|
||||
#include "Windows/main.h"
|
||||
#include "Windows/DinputDevice.h"
|
||||
@@ -1348,4 +1350,95 @@ namespace MainWindow {
|
||||
PostMessage(hwndMain, WM_USER_RUN_CALLBACK, reinterpret_cast<WPARAM>(callback), reinterpret_cast<LPARAM>(userdata));
|
||||
}
|
||||
|
||||
// --game-window: a second window showing just the game. For now it's only a way to test multiple outputs on
|
||||
// the desktop, standing in for a TV over AirPlay. Later, real multi-window support (like ImGui's multi-viewports)
|
||||
// will take over these pieces: the window class, the input forwarding and the output lifetime.
|
||||
static HWND hwndGame;
|
||||
static int gameOutputId;
|
||||
|
||||
static LRESULT CALLBACK GameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_SIZE:
|
||||
if (gameOutputId != 0 && wParam != SIZE_MINIMIZED) {
|
||||
Native_ResizeOutput(gameOutputId, LOWORD(lParam), HIWORD(lParam));
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_CLOSE:
|
||||
// The window has to outlive the swapchain, so it stays until we quit.
|
||||
Native_RemoveOutput(gameOutputId);
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
return 0;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) {
|
||||
WindowsRawInput::GainFocus();
|
||||
g_InputManager.GainFocus();
|
||||
} else {
|
||||
WindowsRawInput::LoseFocus();
|
||||
g_InputManager.LoseFocus();
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_INPUT:
|
||||
{
|
||||
// Keys still go to the emulator. The mouse would get main window coordinates, so it's left out.
|
||||
RAWINPUTHEADER header;
|
||||
UINT size = sizeof(header);
|
||||
if (GetRawInputData((HRAWINPUT)lParam, RID_HEADER, &header, &size, sizeof(RAWINPUTHEADER)) != (UINT)-1 && header.dwType == RIM_TYPEKEYBOARD) {
|
||||
return WindowsRawInput::Process(hWnd, wParam, lParam);
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
case WM_CHAR:
|
||||
return WindowsRawInput::ProcessChar(hWnd, wParam, lParam);
|
||||
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateGameWindow() {
|
||||
if ((GPUBackend)g_Config.iGPUBackend != GPUBackend::VULKAN) {
|
||||
ERROR_LOG(Log::System, "--game-window needs Vulkan");
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr const wchar_t *szGameWindowClass = L"PPSSPPGameWnd";
|
||||
WNDCLASSEX wcex{};
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.lpfnWndProc = (WNDPROC)GameWndProc;
|
||||
wcex.hInstance = hInst;
|
||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
wcex.lpszClassName = szGameWindowClass;
|
||||
wcex.hIcon = LoadIcon(hInst, (LPCTSTR)IDI_PPSSPP);
|
||||
wcex.hIconSm = (HICON)LoadImage(hInst, (LPCTSTR)IDI_PPSSPP, IMAGE_ICON, 16, 16, LR_SHARED);
|
||||
RegisterClassEx(&wcex);
|
||||
|
||||
RECT rc{ 0, 0, 960, 544 };
|
||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
||||
// No owner: an owned window is destroyed along with the main window, which can be before the swapchain is.
|
||||
hwndGame = CreateWindowEx(0, szGameWindowClass, L"PPSSPP game", WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInst, NULL);
|
||||
if (!hwndGame) {
|
||||
ERROR_LOG(Log::System, "Error creating the game window: %s", GetLastErrorMsg().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
RECT client;
|
||||
GetClientRect(hwndGame, &client);
|
||||
Draw::SwapchainDesc desc{};
|
||||
desc.winsys = WINDOWSYSTEM_WIN32;
|
||||
desc.data1 = hInst;
|
||||
desc.data2 = hwndGame;
|
||||
desc.width = client.right - client.left;
|
||||
desc.height = client.bottom - client.top;
|
||||
desc.tag = "GameWindow";
|
||||
gameOutputId = Native_AddOutput(OutputRole::Game, desc);
|
||||
|
||||
ShowWindow(hwndGame, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
|
||||
} // namespace MainWindow
|
||||
Reference in new issue
Block a user