fix(fx-gui): re-enable real-input fallback (anchored, non-topmost)
This commit is contained in:
@@ -270,14 +270,51 @@ uint64_t frameHash(HWND hwnd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void danceStart(HWND hwnd, HWND target, int x, int y) {
|
void danceStart(HWND hwnd, HWND target, int x, int y) {
|
||||||
// Embedded mode: the native window NEVER comes on-screen — showing it
|
// Real-input fallback (only entered when synthetic PostMessage was probed
|
||||||
// topmost over the panel was the "floating always-on-top" bug. Real
|
// as rejected — iZotope/JUCE editors): hardware input needs the plugin
|
||||||
// hardware input would require the window on-screen, so it is disabled;
|
// window visible under the cursor. Anchored mode: place it exactly over
|
||||||
// relayInput always uses synthetic PostMessage.
|
// the embed panel rect (borderless, WS_EX_NOACTIVATE so the DAW keeps
|
||||||
// ponytail: re-enable real input only with a proper sibling placement
|
// focus, HWND_TOP NOT TOPMOST so it never floats over other apps — the
|
||||||
// (owned window, WS_EX_NOACTIVATE, no WS_EX_TOPMOST) if a plugin rejects
|
// "floating always-on-top" bug that got real input disabled in 4bb0db2).
|
||||||
// synthetic clicks.
|
if (g_embedRect.right > g_embedRect.left && g_embedRect.bottom > g_embedRect.top) {
|
||||||
(void)hwnd; (void)target; (void)x; (void)y;
|
const int cw = g_embedRect.right - g_embedRect.left;
|
||||||
|
const int ch = g_embedRect.bottom - g_embedRect.top;
|
||||||
|
LONG_PTR style = GetWindowLongPtrA(hwnd, GWL_STYLE);
|
||||||
|
if (style & (WS_CAPTION | WS_THICKFRAME | WS_SYSMENU |
|
||||||
|
WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) {
|
||||||
|
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU |
|
||||||
|
WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
|
||||||
|
SetWindowLongPtrA(hwnd, GWL_STYLE, style);
|
||||||
|
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
||||||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
|
||||||
|
SWP_NOACTIVATE | SWP_FRAMECHANGED);
|
||||||
|
}
|
||||||
|
SetWindowPos(hwnd, HWND_TOP, g_embedRect.left, g_embedRect.top,
|
||||||
|
cw, ch, SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||||||
|
fxGuiRequestResize(hwnd, cw, ch);
|
||||||
|
Sleep(60); // let the compositor repaint so the editor sees itself active
|
||||||
|
g_dance = true;
|
||||||
|
g_anchored = true; // stays over the panel until /close (re-anchored by /show)
|
||||||
|
g_parkUntil = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (g_dance) return;
|
||||||
|
// No rect known: shift the window so the clicked point sits under the
|
||||||
|
// cursor (cursor already over the embed panel inside the DAW).
|
||||||
|
POINT pt = { x, y };
|
||||||
|
ClientToScreen(target, &pt); // screen pos of the clicked point (child offscreen)
|
||||||
|
POINT cur;
|
||||||
|
GetCursorPos(&cur);
|
||||||
|
RECT wr = {0};
|
||||||
|
GetWindowRect(hwnd, &wr);
|
||||||
|
const int nx = wr.left + (cur.x - pt.x);
|
||||||
|
const int ny = wr.top + (cur.y - pt.y);
|
||||||
|
GetCursorPos(&g_savedCursor);
|
||||||
|
SetWindowPos(hwnd, HWND_TOP, nx, ny, 0, 0,
|
||||||
|
SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
|
||||||
|
Sleep(60); // let the compositor repaint so the editor sees itself active
|
||||||
|
g_dance = true;
|
||||||
|
g_parkUntil = GetTickCount() + 3000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void danceEnd(HWND hwnd) {
|
void danceEnd(HWND hwnd) {
|
||||||
@@ -353,7 +390,8 @@ void relayInput(HWND hwnd, const json_object_s* o) {
|
|||||||
if (resp) {
|
if (resp) {
|
||||||
g_miss = 0; // PostMessage responded — keep it
|
g_miss = 0; // PostMessage responded — keep it
|
||||||
} else if (++g_miss >= 2) {
|
} else if (++g_miss >= 2) {
|
||||||
g_miss = 0; // real-input mode disabled: window must stay off-screen
|
g_realInput = true; // synthetic input rejected — go real hardware input
|
||||||
|
g_miss = 0;
|
||||||
}
|
}
|
||||||
g_preClickHash = 0;
|
g_preClickHash = 0;
|
||||||
}
|
}
|
||||||
@@ -532,9 +570,13 @@ void runHttpServer(HWND hwnd, std::atomic<bool>& stop) {
|
|||||||
if (!IsWindowVisible(hwnd))
|
if (!IsWindowVisible(hwnd))
|
||||||
SetWindowPos(hwnd, HWND_NOTOPMOST, -20000, -20000, 0, 0,
|
SetWindowPos(hwnd, HWND_NOTOPMOST, -20000, -20000, 0, 0,
|
||||||
SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||||||
|
if (!g_realInput) {
|
||||||
|
// Real-input active: the dance/anchor state is owned by the
|
||||||
|
// input relay — /show must not yank the window off-screen.
|
||||||
g_dance = false;
|
g_dance = false;
|
||||||
g_anchored = false;
|
g_anchored = false;
|
||||||
g_parkUntil = 0;
|
g_parkUntil = 0;
|
||||||
|
}
|
||||||
sendResponse(c, 200, "application/json", "{\"ok\":true}", 11);
|
sendResponse(c, 200, "application/json", "{\"ok\":true}", 11);
|
||||||
} else if (req.path == "/preset") {
|
} else if (req.path == "/preset") {
|
||||||
std::string b64;
|
std::string b64;
|
||||||
|
|||||||
@@ -1725,7 +1725,7 @@ static int fxGuiCreateWindow(const std::string& name, bool offscreen,
|
|||||||
RegisterClassA(&wc);
|
RegisterClassA(&wc);
|
||||||
const int x = offscreen ? -20000 : CW_USEDEFAULT;
|
const int x = offscreen ? -20000 : CW_USEDEFAULT;
|
||||||
const int y = offscreen ? -20000 : CW_USEDEFAULT;
|
const int y = offscreen ? -20000 : CW_USEDEFAULT;
|
||||||
const DWORD exStyle = offscreen ? WS_EX_TOOLWINDOW : 0;
|
const DWORD exStyle = offscreen ? (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE) : 0;
|
||||||
// Borderless (WS_POPUP): GetWindowRect == client rect, so anchored
|
// Borderless (WS_POPUP): GetWindowRect == client rect, so anchored
|
||||||
// placement over the embed panel is exact. A captioned/bordered window
|
// placement over the embed panel is exact. A captioned/bordered window
|
||||||
// (WS_OVERLAPPEDWINDOW) put the client area ~31px lower/right of the
|
// (WS_OVERLAPPEDWINDOW) put the client area ~31px lower/right of the
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user