SetFocus 到父窗口,然后回到子窗口

Posted

技术标签:

【中文标题】SetFocus 到父窗口,然后回到子窗口【英文标题】:SetFocus to parent window, then back to child window 【发布时间】:2013-07-06 08:35:34 【问题描述】:

我正在尝试使用 VSTGUI 4.0 实现 VST。我的 DAW 使用 WM_KEYDOWN 和 WM_KEYUP 消息来发送基于键盘按下的 MIDI 音符,以便您可以使用键盘演奏 VST。问题是,VSTGUI 在收到 WM_LBUTTONDOWN 消息时会这样做:

win32Frame->prevFocus = SetFocus (win32Frame->getPlatformWindow ());

CPoint where ((CCoord)((int)(short)LOWORD(lParam)), (CCoord)((int)(short)HIWORD(lParam)));
if (pFrame->platformOnMouseDown (where, buttons) == kMouseEventHandled)
    SetCapture (win32Frame->getPlatformWindow ());
return 0;

这会从 DAW 中窃取焦点,并且不允许它处理按键。 VSTGUI 需要窗口焦点来处理 WM_MOUSEWHEEL 和 WM_KEYUP/WM_KEYDOWN 事件以调整控件。但是当您在 VST 中调整控件时,您显然希望能够使用键盘弹奏音符以查看它们的声音,因此这两个功能都很重要。

我想解决问题的唯一方法是 SetFocus() 到父窗口,使用 SendMessage() 将 WM_KEYUP/WM_KEYDOWN 消息发送回它,然后 SetFocus() 回到 VST 窗口:

case WM_KEYDOWN:
    ...code to handle modifiers like shift, ctrl, etc...
    else
    
        SetFocus(win32Frame->prevFocus);
        SendMessage(win32Frame->prevFocus, message, wParam, lParam);
        SetFocus(win32Frame->getPlatformWindow ());
    

这非常有效,直到您单击 VST 并同时按下一个键,此时会发生未定义的事情(冻结 DAW、使 DAW 崩溃、堆栈溢出等)。

很明显,我对此采取了错误的方法。我觉得我需要 PostMessage() 并等待回调,然后再将焦点返回到 VST 或类似的东西。即使这听起来有点混乱,那么处理此类问题的正确方法到底是什么?

请记住,我无权访问传递消息的 DAW 窗口的代码,因此我无法实现自定义消息或类似的东西。

【问题讨论】:

哇,这真是一些丑陋的代码。不确定如果他们每个人都能得到报酬,他们是否可以在那里获得更多的演员表。如果那不是代码气味,我不知道是什么。无论如何,我不明白为什么你需要捕获鼠标。输入焦点还不够好吗? 我需要将输入焦点赋予 DAW,以便它可以通过键盘发送音符事件来播放 VST。真的很奇怪,我有点需要 DAW 和 VST 同时拥有键盘焦点。即使我可以只给 VST 鼠标滚轮焦点就足够了,但键盘和鼠标滚轮焦点似乎是一回事。我也不能编写代码在 VST 中手动播放 MIDI 音符,因为我需要考虑 DAW 特定的东西,比如八度音阶。哦,是的,代码太糟糕了哈哈,VST SDK 和 VSTGUI 可能是我用过的最糟糕的代码库。 您似乎混淆了输入焦点和捕获鼠标。代码的第一个 sn-p 捕获鼠标,这是破坏键盘加速器和助记符的原因。这是一个与输入焦点类似但不同的问题。虽然我想到如果问题是让一个未聚焦的窗口接收滚动消息,您可以在聚焦窗口上处理它们并将它们转发到未聚焦的窗口。窗口实际上不需要输入焦点来滚动,它只需要焦点来接收消息而无需特殊干预。 问题是我无法访问父窗口代码,它属于 DAW (FL Studio)。所以我不能真正转发它的消息。这就是为什么我试图将消息向上传递的原因,这确实感觉像是在像 Windows 消息这样的涓滴系统中打破形式。我看了一下全局消息挂钩,但这似乎有点粗略?我不确定当窗口失焦并位于其他窗口后面时,这种事情是如何处理的。 在窗口没有焦点时处理键盘消息是完全正常的。样板示例是 Alt+F4,无论焦点如何都有效。它在消息循环中完成,在消息被发送到通常编写 TranslateMessage() 和 TranslateAccelerator() 的地方之前完成。如果您无法更改 DAW,那么您就有问题了。 PostMessage() 可以在一定程度上起作用,但无需更改焦点并使用可靠的窗口句柄即可。问题的根源更可能是您没有正确实施 ActiveX 合同。 【参考方案1】:

非常感谢 Hans Passant 解决了这个问题!

崩溃问题是由于我的窗口句柄不可靠。我停止将窗口句柄存储在一个变量中,而是使用 GetParent() 在现场得到它。

我也不需要将焦点设置到当前窗口,我需要做的只是将我的 SendMessage 替换为 PostMessage。所以新代码:

case WM_KEYDOWN:
    ...code to handle modifiers like shift, ctrl, etc...
    else
    
        PostMessage(GetParent(win32Frame->getPlatformWindow ()), message, wParam, lParam);
    

【讨论】:

以上是关于SetFocus 到父窗口,然后回到子窗口的主要内容,如果未能解决你的问题,请参考以下文章

window.open()打开一个子窗口,怎么实现在子窗口选择数据,然后提交把数据加到父窗口。

滚动子窗口“溢出”到父窗口

showModalDialog/showModelessDialog实例,父窗口向子窗口传递值,子窗口设置父窗口的值,子窗口关闭的时候返回值到父窗口.关闭刷新父窗口

将子窗口停靠到父窗口

visual c++ 中 怎样把子窗口传值到父窗口?

Qt 子窗口内嵌到父窗口中