work in progress
This commit is contained in:
265
designer-test/src/window_controller.cpp
Normal file
265
designer-test/src/window_controller.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
// Window controller implementation
|
||||
#include "window_controller.h"
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
namespace mosis::test {
|
||||
|
||||
bool WindowController::FindWindow(const std::string& title) {
|
||||
m_hwnd = ::FindWindowA(nullptr, title.c_str());
|
||||
if (!m_hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_info.hwnd = m_hwnd;
|
||||
|
||||
// Get window rect
|
||||
::GetWindowRect(m_hwnd, &m_info.windowRect);
|
||||
|
||||
// Get client rect (relative to window)
|
||||
RECT clientRect;
|
||||
::GetClientRect(m_hwnd, &clientRect);
|
||||
m_info.clientRect = clientRect;
|
||||
|
||||
// Convert client area origin to screen coordinates
|
||||
POINT clientOrigin = {0, 0};
|
||||
::ClientToScreen(m_hwnd, &clientOrigin);
|
||||
m_info.clientX = clientOrigin.x;
|
||||
m_info.clientY = clientOrigin.y;
|
||||
|
||||
// Calculate client size and DPI scale
|
||||
int clientWidth = clientRect.right - clientRect.left;
|
||||
int clientHeight = clientRect.bottom - clientRect.top;
|
||||
m_info.clientWidth = clientWidth;
|
||||
m_info.clientHeight = clientHeight;
|
||||
|
||||
m_info.scaleX = static_cast<float>(clientWidth) / PHONE_WIDTH;
|
||||
m_info.scaleY = static_cast<float>(clientHeight) / PHONE_HEIGHT;
|
||||
|
||||
std::cout << "Found window: " << title << std::endl;
|
||||
std::cout << " Window rect: " << m_info.windowRect.left << "," << m_info.windowRect.top
|
||||
<< " - " << m_info.windowRect.right << "," << m_info.windowRect.bottom << std::endl;
|
||||
std::cout << " Client origin: " << m_info.clientX << "," << m_info.clientY << std::endl;
|
||||
std::cout << " Client size: " << clientWidth << "x" << clientHeight << std::endl;
|
||||
std::cout << " DPI scale: " << m_info.scaleX << " x " << m_info.scaleY << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::WaitForWindow(const std::string& title, int timeoutMs) {
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
|
||||
while (true) {
|
||||
if (FindWindow(title)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto elapsed = std::chrono::steady_clock::now() - startTime;
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() >= timeoutMs) {
|
||||
std::cerr << "Timeout waiting for window: " << title << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
LPARAM WindowController::PhoneToClientLParam(int phoneX, int phoneY) {
|
||||
// Scale phone coordinates to client coordinates
|
||||
int clientX = static_cast<int>(phoneX * m_info.scaleX);
|
||||
int clientY = static_cast<int>(phoneY * m_info.scaleY);
|
||||
|
||||
// Clamp to client area bounds
|
||||
clientX = std::max(0, std::min(clientX, static_cast<int>(PHONE_WIDTH * m_info.scaleX) - 1));
|
||||
clientY = std::max(0, std::min(clientY, static_cast<int>(PHONE_HEIGHT * m_info.scaleY) - 1));
|
||||
|
||||
return MAKELPARAM(clientX, clientY);
|
||||
}
|
||||
|
||||
bool WindowController::SendMouseDown(int phoneX, int phoneY) {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
// Convert to screen coordinates for SendInput
|
||||
int clientX = static_cast<int>(phoneX * m_info.scaleX);
|
||||
int clientY = static_cast<int>(phoneY * m_info.scaleY);
|
||||
int screenX = m_info.clientX + clientX;
|
||||
int screenY = m_info.clientY + clientY;
|
||||
|
||||
// Use SendInput for proper GLFW compatibility
|
||||
// First move the cursor to the position
|
||||
SetCursorPos(screenX, screenY);
|
||||
|
||||
// Send mouse down via SendInput
|
||||
INPUT input = {};
|
||||
input.type = INPUT_MOUSE;
|
||||
input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
|
||||
SendInput(1, &input, sizeof(INPUT));
|
||||
|
||||
std::cout << "MouseDown at phone(" << phoneX << "," << phoneY << ") -> screen("
|
||||
<< screenX << "," << screenY << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::SendMouseUp(int phoneX, int phoneY) {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
// Send mouse up via SendInput
|
||||
INPUT input = {};
|
||||
input.type = INPUT_MOUSE;
|
||||
input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
|
||||
SendInput(1, &input, sizeof(INPUT));
|
||||
|
||||
std::cout << "MouseUp at phone(" << phoneX << "," << phoneY << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::SendMouseMove(int phoneX, int phoneY) {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
int clientX = static_cast<int>(phoneX * m_info.scaleX);
|
||||
int clientY = static_cast<int>(phoneY * m_info.scaleY);
|
||||
int screenX = m_info.clientX + clientX;
|
||||
int screenY = m_info.clientY + clientY;
|
||||
|
||||
SetCursorPos(screenX, screenY);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::SendClick(int phoneX, int phoneY) {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
// Save current cursor position
|
||||
POINT oldPos;
|
||||
GetCursorPos(&oldPos);
|
||||
|
||||
// Ensure window is active
|
||||
SetForegroundWindow(m_hwnd);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Perform click
|
||||
SendMouseDown(phoneX, phoneY);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
SendMouseUp(phoneX, phoneY);
|
||||
|
||||
// Restore cursor position (optional - comment out if cursor restoration causes issues)
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
// SetCursorPos(oldPos.x, oldPos.y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::SendKey(UINT vkCode) {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
// Send key down and up
|
||||
LPARAM lParam = 1; // Repeat count = 1
|
||||
::PostMessage(m_hwnd, WM_KEYDOWN, vkCode, lParam);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
::PostMessage(m_hwnd, WM_KEYUP, vkCode, lParam | (1 << 30) | (1 << 31));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::SendChar(char c) {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
::PostMessage(m_hwnd, WM_CHAR, static_cast<WPARAM>(c), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::Activate() {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
::SetForegroundWindow(m_hwnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::Close() {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
::PostMessage(m_hwnd, WM_CLOSE, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowController::ResizeToPhone() {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
// Get current window rect to preserve position
|
||||
RECT currentRect;
|
||||
::GetWindowRect(m_hwnd, ¤tRect);
|
||||
|
||||
// Calculate window size needed for phone-sized client area
|
||||
RECT desiredRect = {0, 0, PHONE_WIDTH, PHONE_HEIGHT};
|
||||
DWORD style = ::GetWindowLong(m_hwnd, GWL_STYLE);
|
||||
DWORD exStyle = ::GetWindowLong(m_hwnd, GWL_EXSTYLE);
|
||||
::AdjustWindowRectEx(&desiredRect, style, FALSE, exStyle);
|
||||
|
||||
int newWidth = desiredRect.right - desiredRect.left;
|
||||
int newHeight = desiredRect.bottom - desiredRect.top;
|
||||
|
||||
// Check screen dimensions
|
||||
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
|
||||
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
std::cout << "ResizeToPhone: screen=" << screenWidth << "x" << screenHeight
|
||||
<< ", needed=" << newWidth << "x" << newHeight << std::endl;
|
||||
|
||||
// If screen is too small, we can't resize to full phone size
|
||||
if (newHeight > screenHeight) {
|
||||
std::cout << " Warning: Screen too small for full phone resolution, keeping current size" << std::endl;
|
||||
return true; // Not an error, just can't resize
|
||||
}
|
||||
|
||||
// Move window to top-left to ensure it fits on screen
|
||||
int newX = 0;
|
||||
int newY = 0;
|
||||
|
||||
std::cout << " Moving to (" << newX << "," << newY << ") size " << newWidth << "x" << newHeight << std::endl;
|
||||
::MoveWindow(m_hwnd, newX, newY, newWidth, newHeight, TRUE);
|
||||
|
||||
// Re-acquire window info
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
return FindWindow("Mosis Designer");
|
||||
}
|
||||
|
||||
bool WindowController::SendClickFromBottom(int clientX, int offsetFromBottom) {
|
||||
if (!m_hwnd) return false;
|
||||
|
||||
// Calculate Y position from bottom of client area
|
||||
int clientY = m_info.clientHeight - offsetFromBottom;
|
||||
|
||||
// Convert to screen coordinates
|
||||
int screenX = m_info.clientX + clientX;
|
||||
int screenY = m_info.clientY + clientY;
|
||||
|
||||
// Save current cursor position
|
||||
POINT oldPos;
|
||||
GetCursorPos(&oldPos);
|
||||
|
||||
// Ensure window is active
|
||||
SetForegroundWindow(m_hwnd);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Move cursor and click
|
||||
SetCursorPos(screenX, screenY);
|
||||
|
||||
INPUT input = {};
|
||||
input.type = INPUT_MOUSE;
|
||||
input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
|
||||
SendInput(1, &input, sizeof(INPUT));
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
|
||||
SendInput(1, &input, sizeof(INPUT));
|
||||
|
||||
std::cout << "ClickFromBottom at client(" << clientX << "," << clientY
|
||||
<< ") -> screen(" << screenX << "," << screenY << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mosis::test
|
||||
Reference in New Issue
Block a user