RichEdit control具有此非常烦人的功能。每当用户尝试将光标移过其“ 终点”时,它都会发出蜂鸣声。例如,您可以使用也实现RICHEDIT的WordPad
对其进行测试。打开它,输入一些文本,然后按【{{1}】键。如果光标不在行首:
按下Home
键会将其移至该位置,但是再次按下Home
键将产生此提示音。
乍看之下,似乎像覆盖Home
和WM_KEYDOWN
消息并阻止RICHEDIT可以发出蜂鸣声的情况是一种解决方案...直到我真正开始实现它。但是不幸的是,它并没有听起来那么简单,因为该控件在许多情况下都发出哔哔声!因此,我的按键阻止代码实际上膨胀到了300多个行,而且我仍然看到有些按键不是我要考虑的,或者更糟的是,我可能重写了一些有用的行为。 (有关详细信息,请阅读下文。)
然后,我决定查看RICHEDIT控件本身的实现。确实可以肯定,例如,如果我们看一下WM_KEYUP
按键的实现,则在Windows 10操作系统上的Home
具有称为C:\WINDOWS\SysWOW64\msftedit.dll
(或?Home@CTxtSelection@@QAEHHH@Z
已取消映射的偏移量public: int __thiscall CTxtSelection::Home(int,int)
,即已硬编码为调用MessageBeep(MB_OK),或者完全我要消除的内容:
如果您在上面的屏幕快照中查看地址0x3FC00
,则有一种内置的方法可以绕过它,看起来像标志0x6B64FD38
。
因此,在深入研究0x800
之后,似乎有一个名为msftedit.dll
(或?OnAllowBeep@CTxtEdit@@QAEJH@Z
被拆掉)的函数可以修改此标志:
经过更多研究,我发现RICHEDIT控件内置了COM接口,例如public: long __thiscall CTxtEdit::OnAllowBeep(int)
和ITextServices
,它们在ITextServices::OnTxPropertyBitsChange
中将该标记引用为ITextHost
方法。
但是,不幸的是,我似乎找不到如何直接更改TXTBIT_ALLOWBEEP
标志的方式(COM不是我的强项。)我试图研究实现ITextHost
,但是它有一个许多虚拟方法与我不知道如何实现的目标无关。
有人知道如何清除TXTBIT_ALLOWBEEP
标志吗?
PS。这就是为什么我没有采用覆盖按键的方法的原因:
仅举一个例子。假设我覆盖了TXTBIT_ALLOWBEEP
键。我需要确保光标不在该行的开头,而且也没有选择。但是,我需要确保在光标位于窗口最上方的情况下,VK_HOME
键没有按下。然后,与Ctrl
键相同,我什至不确定Shift
对它的作用……等等。哦,这只是Alt
键。还有上,下,左,右,PageUp,PageDown,End,Delete和Backspace。 (这就是我所知道的。可能还有更多,而且我什至没有在谈论IME或其他键盘布局等。)换句话说,这变得一团糟!
因此,最终我意识到,预测按键不是可行的方法。
答案 0 :(得分:6)
首先,我们需要向丰富的编辑窗口发送EM_GETOLEINTERFACE
消息-这是检索IRichEditOle对象,客户端可以使用该对象来访问丰富的编辑控件的组件对象模型(COM)功能。
然后要获取ITextServices
指针,请对EM_GETOLEINTERFACE
返回的专用QueryInterface
指针调用IUnknown
。
这里存在一个有趣的地方-IID_ITextServices
鲜为人知,但需要从 Msftedit.dll
来自About Windowless Rich Edit Controls
Msftedit.dll 会导出名为 IID_ITextServices 的接口标识符(IID),您可以使用该接口标识符查询IUnknown指针以获取 ITextServices 接口。
在获得ITextServices
指针之后-我们只需使用TXTBIT_ALLOWBEEP
掩码调用OnTxPropertyBitsChange
代码示例:
#include <textserv.h>
if (HMODULE hmodRichEdit = LoadLibrary(L"Msftedit.dll"))
{
// create richedit window
if (HWND hwndRich = CreateWindowExW(0, MSFTEDIT_CLASS, ...))
{
if (IID* pIID_ITS = (IID*) GetProcAddress(hmodRichEdit, "IID_ITextServices"))
{
IUnknown* pUnk;
if (SendMessageW(hwndRich, EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk))
{
ITextServices* pTxtSrv;
HRESULT hr = pUnk->QueryInterface(*pIID_ITS, (void**)&pTxtSrv);
pUnk->Release();
if (0 <= hr)
{
pTxtSrv->OnTxPropertyBitsChange(TXTBIT_ALLOWBEEP, 0);
pTxtSrv->Release();
}
}
}
}
}