应用程序未通过文本服务框架 DLL 检测输入语言更改

Posted

技术标签:

【中文标题】应用程序未通过文本服务框架 DLL 检测输入语言更改【英文标题】:Application not detecting input language changes via Text Service Framework DLL 【发布时间】:2013-07-26 04:21:55 【问题描述】:

好的,我已经有一段时间了......

我正在尝试跟踪用户何时从语言栏更改输入语言。

我有一个文本服务 DLL - 从 MSDN 和 WinSDK 示例建模 - 注册良好,我可以使用接口 ITfActiveLanguageProfileNotifySink 和 ITfLanguageProfileNotifySink 并很好地查看这些事件。

我也终于意识到,当我更改语言时,这些事件发生在当前具有焦点的应用程序/进程中。

我需要做的是简单地让这些事件能够回调到我自己的应用程序,当它具有焦点时。我知道我错过了什么。

感谢您提供任何帮助。

谢谢。

【问题讨论】:

这是哪个操作系统?在 XP 到 Windows 7 上,语言更改是按进程进行的;在 Windows 8 上,语言更改是全局性的。 Eric - 这是在 Windows 7 上。应用程序如何接收这些已注册文本服务的回调?我的文本服务对象源自这两个接收器以及一个自定义接口。我在我的应用程序中获得了线程管理器,但之后似乎无论我做什么,我都无法在我的应用程序中看到这些事件。例如,如果我将窗口句柄传递给文本对象以使其回调,则此句柄似乎无效,即使我的应用程序具有焦点。 顺便说一句,很棒的博客!这是我找到的最有用的资源。 我不太确定我是否理解这个问题。文本服务会收到语言更改通知,并且(通常)使用它来决定是否开启。我相信应用程序也可以设置通知接收器,但创建线程管理器意味着应用程序还将创建一个文本存储,这可能比您想要的更多。您的文本服务还可以通过 COM、共享内存或您选择的 IPC 机制与您的应用程序通信。 Eric - 是的,我只想在文本服务收到语言更改通知时通知我的应用程序。例如,假设我们从 MSDN 示例中获取 BasicText 服务,并让该类派生自 ITfLanguageProfileNotifySink 和 ITfActiveLanguageProfileNotifySink。 CTextService 类:公共 ITfTextInputProcessor、公共 ITfLanguageProfileNotifySink、公共 ITfActiveLanguageProfileNotifySink 【参考方案1】:

我做了一些仔细检查,只要不调用 ITfThreadMgr::Activate,您应该能够在不实现 ITextStoreACP 的情况下创建线程管理器对象。

所以,代码应该是这样的:

HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))

    ITfThreadMgr* pThreadMgr(NULL);
    hr = CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, (LPVOID*) &pThreadMgr);
    if (SUCCEEDED(hr))
    
        ITfSource *pSource;
        hr = pThreadMgr->QueryInterface(IID_ITfSource, (LPVOID*)&pSource);
        if(SUCCEEDED(hr))
        
            hr = pSource->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, 
                (ITfActiveLanguageProfileNotifySink*)this,
                &m_dwCookie);

            pSource->Release();
        
    

或者,您可以使用ITfLanguageProfileNotifySink - 此接口由ItfInputProcessorProfiles 对象而不是ItfThreadMgr 驱动。在MSDN page for ItfLanguageProfileNotifySink 上有一个如何设置的示例。

对于这两个对象,您需要保持源对象(ITfThreadMgr 或 ITfInputProcessorProfiles)以及接收器对象(您实现的对象)处于活动状态,直到您的应用程序退出。

在您的应用程序退出之前,您需要使用ITfSource::UnadviseSink 从源对象中移除接收器,然后释放源对象(使用Release)。 (不过,您不需要在应用程序的整个生命周期中保持 ItfSource 接口处于活动状态。)

【讨论】:

Eric - 谢谢,我在没有注册我的文本服务的情况下让它在应用程序中工作。 ITfLanguageProfileNotifySink 接口似乎更适合,因为我在更改输入语言(从语言栏)时得到了 LANGID。但是这里有一个客户注意到的问题:为什么在更改中文(子)语言时没有收到这些通知,例如ChangJie或New Phonetic?再次感谢! @user2621234 - 这些不是子语言,它们是输入法。同一种语言可以有多种输入法。要跟踪输入法,您必须使用 ITfActiveLanguageProfileNotifySink 并弄清楚如何解释各种输入法的 CLSID。

以上是关于应用程序未通过文本服务框架 DLL 检测输入语言更改的主要内容,如果未能解决你的问题,请参考以下文章

Datumbox:基于Java的新的开源机器学习框架

MFC编写DLL怎么用C风格

如何在两个dll文件之间传送数据

VB.NET本地化,检测未翻译文本

未检测到通过 window.open() 运行的小程序的高度和宽度变化

如何修复文本字段中错误的键盘布局导致的错误