fix(bridge): anchored fx-gui embed - dance dat window dung panel rect, khong park/restore cursor, resize view qua WM_FXGUI_RESIZE
This commit is contained in:
@@ -41,6 +41,10 @@
|
||||
#include "vst3sdk/public.sdk/source/vst/moduleinfo/json.h"
|
||||
#endif
|
||||
|
||||
// Defined in RenderFxJob.cpp (global scope); declared here outside the
|
||||
// anonymous namespace so both TUs see the same symbol.
|
||||
extern void fxGuiRequestResize(HWND hwnd, int w, int h);
|
||||
|
||||
namespace {
|
||||
|
||||
// --- tiny JSON helpers (same API as RenderFxJob.cpp) ------------------------
|
||||
@@ -245,6 +249,12 @@ std::atomic<DWORD> g_parkUntil{0}; // safety restore deadline (GetTickCount)
|
||||
POINT g_savedCursor = {0, 0}; // cursor to restore after the dance
|
||||
int g_miss = 0; // consecutive no-response PostMessage clicks
|
||||
uint64_t g_preClickHash = 0;
|
||||
// Anchored mode: the frontend sends the embed panel's screen rect (physical
|
||||
// px) with every /input, so the real-input dance places the plugin window
|
||||
// exactly over the panel -- cursor never moves, no park/restore churn. Zero
|
||||
// rect = legacy cursor-relative mode.
|
||||
RECT g_embedRect = {0, 0, 0, 0};
|
||||
bool g_anchored = false; // window anchored over panel (stays until /close)
|
||||
|
||||
uint64_t frameHash(HWND hwnd) {
|
||||
std::vector<unsigned char> jpg;
|
||||
@@ -255,6 +265,33 @@ uint64_t frameHash(HWND hwnd) {
|
||||
}
|
||||
|
||||
void danceStart(HWND hwnd, HWND target, int x, int y) {
|
||||
// Anchored mode: place the host window's client area exactly over the embed
|
||||
// panel rect (borderless + topmost) so real mouse events hit the plugin
|
||||
// without moving the cursor, then ask the pump thread to size the plugin
|
||||
// view to the panel. No park deadline -- the window stays until /close.
|
||||
// Re-runs on every click so a scrolled/resized panel re-anchors.
|
||||
if (g_embedRect.right > g_embedRect.left && g_embedRect.bottom > g_embedRect.top) {
|
||||
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_TOPMOST, 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;
|
||||
g_parkUntil = 0; // anchored: stay until /close
|
||||
return;
|
||||
}
|
||||
if (g_dance) return;
|
||||
// Dat window ngay tai vi tri cursor (dang nam tren panel embed trong DAW)
|
||||
// chu khong nhay ra goc man hinh: shift window sao cho client point (x,y)
|
||||
@@ -278,6 +315,7 @@ void danceStart(HWND hwnd, HWND target, int x, int y) {
|
||||
|
||||
void danceEnd(HWND hwnd) {
|
||||
if (!g_dance) return;
|
||||
if (g_anchored) return; // anchored: stays until /close
|
||||
SetWindowPos(hwnd, HWND_NOTOPMOST, -20000, -20000, 0, 0,
|
||||
SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
SetCursorPos(g_savedCursor.x, g_savedCursor.y);
|
||||
@@ -305,6 +343,21 @@ void relayInput(HWND hwnd, const json_object_s* o) {
|
||||
const std::string type = memberString(o, "type", "");
|
||||
const int x = (int)memberInt(o, "x", 0);
|
||||
const int y = (int)memberInt(o, "y", 0);
|
||||
// Anchored rect from the embed panel (screen coords, physical px).
|
||||
const json_value_s* rv = memberValue(o, "rect");
|
||||
if (rv && rv->type == json_type_object) {
|
||||
const json_object_s* ro = static_cast<const json_object_s*>(rv->payload);
|
||||
const LONG rw = (LONG)memberInt(ro, "w", 0);
|
||||
const LONG rh = (LONG)memberInt(ro, "h", 0);
|
||||
if (rw > 0 && rh > 0) {
|
||||
g_embedRect.left = (LONG)memberInt(ro, "x", 0);
|
||||
g_embedRect.top = (LONG)memberInt(ro, "y", 0);
|
||||
g_embedRect.right = g_embedRect.left + rw;
|
||||
g_embedRect.bottom = g_embedRect.top + rh;
|
||||
} else {
|
||||
g_embedRect = {0, 0, 0, 0}; // empty rect -> back to cursor mode
|
||||
}
|
||||
}
|
||||
const int button = (int)memberInt(o, "button", 0);
|
||||
const int buttons = (int)memberInt(o, "buttons", 0); // DOM e.buttons bitmask
|
||||
const int deltaY = (int)memberInt(o, "deltaY", 0);
|
||||
@@ -324,7 +377,12 @@ void relayInput(HWND hwnd, const json_object_s* o) {
|
||||
// responds (reset miss); two consecutive no-response clicks mean the
|
||||
// editor rejects synthetic input — switch to real hardware input.
|
||||
if (!g_realInput) {
|
||||
if (isDown) {
|
||||
if (g_embedRect.right > g_embedRect.left) {
|
||||
// Anchored mode exists for plugins that need real input; the window
|
||||
// appears exactly over the panel, so probing PostMessage first only
|
||||
// wastes clicks.
|
||||
g_realInput = true;
|
||||
} else if (isDown) {
|
||||
g_preClickHash = frameHash(hwnd);
|
||||
} else if (isUp && g_preClickHash) {
|
||||
Sleep(250);
|
||||
|
||||
Reference in New Issue
Block a user