如何通知操作系统将云剪贴板(或表情符号面板)定位在我的窗口上方?

huangapple go评论65阅读模式
英文:

How can I inform the OS to position the Cloud Clipboard (or Emoji Panel) over my window?

问题

我有一个基于传统的Win32 C++的Windows桌面应用程序。在窗口中,我处理<kbd>Ctrl+V</kbd>以处理粘贴的内容。同一个窗口还处理键击,将键入的字符添加到我管理的内容中。所有这些都很正常!

然而,如果用户按下<kbd>Win+V</kbd>从云剪贴板粘贴,或按下<kbd>Win+.</kbd>使用表情面板键入,那些弹出窗口并没有出现在我的窗口附近,即使它是活动窗口并具有输入焦点。

是否有API我应该调用,或者我需要响应的Windows消息,以通知操作系统我的窗口希望附近打开面板,最好沿着其边界,或者我提供的矩形?

我尝试调用SetCaretPos(),但这种行为不会影响任何事情。我看到周围有许多用于查看剪贴板内容更改的剪贴板查看器API,但那是用于希望监视剪贴板内容更改的窗口,而不是像我的这种普通接受输入的窗口。

我只是希望操作系统弹出窗口靠近我的窗口,就像普通的EditCombo控件在具有输入焦点时会发生的那样。

一些截图以说明:

所需位置,就像运行对话框一样:

如何通知操作系统将云剪贴板(或表情符号面板)定位在我的窗口上方?

使用MFC测试程序复制的错误:

如何通知操作系统将云剪贴板(或表情符号面板)定位在我的窗口上方?

要复制该错误,请创建一个支持标准Edit > Paste菜单项的MFC应用程序,其中包含ID_EDIT_PASTE加速键。将其映射到以下OnEditPaste处理程序(只是在MessageBox中显示任何CF_TEXT):

void TestView::OnEditPaste()
{
    if (OpenClipboard()) {
        if (auto hText = ::GetClipboardData(CF_TEXT); hText != NULL) {
            if (auto pData = ::GlobalLock(hText); pData) {
                std::string msg{(char*)pData, ::GlobalSize(hText)};
                ::MessageBoxA(GetSafeHwnd(), msg.c_str(), "Pasted", MB_OK);
                ::GlobalUnlock(hText);
            }
        }
        CloseClipboard();
    }
}

运行应用程序并激活视图。然后按<kbd>Win+V</kbd>,云剪贴板将远离窗口打开;这是我迫切希望解决的问题。

英文:

I have a traditional Win32 C++-based Windows desktop application. In the window, I handle <kbd>Ctrl+V</kbd> to process pasted content. The same window also handles keystrokes with the typed character added to the content I manage. All this works fine!

However, if the user presses <kbd>Win+V</kbd> to paste from the Cloud Clipboard, or presses <kbd>Win+.</kbd> to type using the Emoji panel, those popup windows are not positioned anywhere near my window, even though it is the active window with input focus.

Is there an API I should call, or a Windows message I need to be responding to, in order to inform the OS that my window wants the panel opened nearby, preferably along its border, or a rect I supply?

I have tried calling SetCaretPos(), but the behavior doesn't affect anything. I see APIs all around being a Clipboard Viewer, but that's for windows which want to watch for clipboard content changes, and not a normal window accepting input like mine.

I just want the OS popup to be near to my window, as happens for the common Edit or Combo controls when they have input focus.

Some screenshots to illustrate:

Desired Location ala the Run dialog:

如何通知操作系统将云剪贴板(或表情符号面板)定位在我的窗口上方?

Bug replicated with a MFC test program:

如何通知操作系统将云剪贴板(或表情符号面板)定位在我的窗口上方?

To replicate the bug yourself, create an MFC app supporting the standard Edit &gt; Paste menu item with the ID_EDIT_PASTE accelerator. Map that to an OnEditPaste handler like below (just shows any CF_TEXT in a MessageBox):

void TestView::OnEditPaste()
{
	if (OpenClipboard()) {
		if (auto hText = ::GetClipboardData(CF_TEXT); hText != NULL) {
			if (auto pData = ::GlobalLock(hText); pData) {
				std::string msg{(char*)pData, ::GlobalSize(hText)};
				::MessageBoxA(GetSafeHwnd(), msg.c_str(), &quot;Pasted&quot;, MB_OK);
				::GlobalUnlock(hText);
			}
		}
		CloseClipboard();
	}
}

Run your app and activate the view. Then press <kbd>Win+V</kbd> and the Cloud Clipboard opens far away; that's the issue I'm desperate to solve.

答案1

得分: 3

我在这里找到了类似的情况:如何在Win32中设置Emoji弹出位置

那个问题涉及到Emoji面板,但修复也影响了Cloud Clipboard的位置。看起来操作系统将它们都视为特殊的输入法编辑窗口。

关键是要响应WM_IME_REQUEST消息,具体来说,是IMR_QUERYCHARPOSITION查询。

如果你在使用MFC,你可能需要类似这样的代码。以下代码将提示符放置在窗口的左上角,但你应该能理解这个思路。

class TestView : public CView
{
    . . .
    afx_msg LRESULT OnImeRequest(WPARAM wParam, LPARAM lParam);
}

BEGIN_MESSAGE_MAP(TestView, CView)
    . . .
	ON_MESSAGE(WM_IME_REQUEST, OnImeRequest)
END_MESSAGE_MAP()

LRESULT TestView::OnImeRequest(WPARAM wParam, LPARAM lParam)
{
	switch (wParam) {
		case IMR_QUERYCHARPOSITION: {
			RECT rcWindow{};
			GetWindowRect(&rcWindow);

			IMECHARPOSITION* charPos = (IMECHARPOSITION*)lParam;
			charPos->dwSize = sizeof(IMECHARPOSITION);
			charPos->pt.x = rcWindow.left;
			charPos->pt.y = rcWindow.top;
			charPos->cLineHeight = 10;
			GetClientRect(&charPos->rcDocument);
			return 1;
		}
	}

	return 0;
}
英文:

I found a similar situation here: How to set Emoji popup position in Win32

That question is regarding the Emoji panel but the fix also affects the Cloud Clipboard location as well. It seems that the OS treats both as special IME windows.

The key is to respond to the WM_IME_REQUEST message, specifically, the IMR_QUERYCHARPOSITION query.

If you're using MFC, you'll want something like this. This just places the prompt in the top-left of the window but you should get the idea.

class TestView : public CView
{
    . . .
    afx_msg LRESULT OnImeRequest(WPARAM wParam, LPARAM lParam);
}

BEGIN_MESSAGE_MAP(TestView, CView)
    . . .
	ON_MESSAGE(WM_IME_REQUEST, OnImeRequest)
END_MESSAGE_MAP()

LRESULT TestView::OnImeRequest(WPARAM wParam, LPARAM lParam)
{
	switch (wParam) {
		case IMR_QUERYCHARPOSITION: {
			RECT rcWindow{};
			GetWindowRect(&amp;rcWindow);

			IMECHARPOSITION* charPos = (IMECHARPOSITION*)lParam;
			charPos-&gt;dwSize = sizeof(IMECHARPOSITION);
			charPos-&gt;pt.x = rcWindow.left;
			charPos-&gt;pt.y = rcWindow.top;
			charPos-&gt;cLineHeight = 10;
			GetClientRect(&amp;charPos-&gt;rcDocument);
			return 1;
		}
	}

	return 0;
}

huangapple
  • 本文由 发表于 2023年3月7日 00:33:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75653424.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定