山东大学软件工程应用与实践——WeaselTSF(一)

news/2024/7/16 8:06:58 标签: visual studio, c++, ide

2021SC@SDUSC

文章目录

  • 简单介绍
  • WeaselTSF.h

从本篇博客开始分析WeaselTFS这个包中的代码。

简单介绍

WeaselTSF.vcproj
This is the main project file for VC++ projects generated using an Application Wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the Application Wizard.

WeaselTSF.vcproj是使用应用程序向导生成的VC++项目的主项目文件。它包含生成文件的VisualC++的版本信息,和有关使用应用程序向导选择的平台、配置和项目功能的信息。

WeaselTSF.cpp
This is the main DLL source file.

WeaselTSF.cpp是主DLL源文件。

Other standard files:
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file named WeaselTSF.pch and a precompiled types file named StdAfx.obj.

其他标准文件StdAfx.h, StdAfx.cpp,这些文件用于构建WeaselTSF.PCH的预编译头(PCH)文件和StdAfx.obj的预编译类型文件。

WeaselTSF.h

#include <WeaselCommon.h>
#include "Globals.h"
#include "WeaselIPC.h"

class CCandidateList;
class CLangBarItemButton;
class CCompartmentEventSink;

class WeaselTSF:
	public ITfTextInputProcessorEx,
	public ITfThreadMgrEventSink,
	public ITfTextEditSink,
	public ITfTextLayoutSink,
	public ITfKeyEventSink,
	public ITfCompositionSink,
	public ITfThreadFocusSink,
	public ITfActiveLanguageProfileNotifySink,
	public ITfEditSession
{
public:
	WeaselTSF();
	~WeaselTSF();

	/* IUnknown */
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	/* ITfTextInputProcessor */
	STDMETHODIMP Activate(ITfThreadMgr *pThreadMgr, TfClientId tfClientId);
	STDMETHODIMP Deactivate();

	/* ITfTextInputProcessorEx */
	STDMETHODIMP ActivateEx(ITfThreadMgr *pThreadMgr, TfClientId tfClientId, DWORD dwFlags);

	/* ITfThreadMgrEventSink */
	STDMETHODIMP OnInitDocumentMgr(ITfDocumentMgr *pDocMgr);
	STDMETHODIMP OnUninitDocumentMgr(ITfDocumentMgr *pDocMgr);
	STDMETHODIMP OnSetFocus(ITfDocumentMgr *pDocMgrFocus, ITfDocumentMgr *pDocMgrPrevFocus);
	STDMETHODIMP OnPushContext(ITfContext *pContext);
	STDMETHODIMP OnPopContext(ITfContext *pContext);

	/* ITfTextEditSink */
	STDMETHODIMP OnEndEdit(ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord);

	/* ITfTextLayoutSink */
	STDMETHODIMP OnLayoutChange(ITfContext *pContext, TfLayoutCode lcode, ITfContextView *pContextView);

	/* ITfKeyEventSink */
	STDMETHODIMP OnSetFocus(BOOL fForeground);
	STDMETHODIMP OnTestKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten);
	STDMETHODIMP OnKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten);
	STDMETHODIMP OnTestKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten);
	STDMETHODIMP OnKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten);
	STDMETHODIMP OnPreservedKey(ITfContext *pContext, REFGUID rguid, BOOL *pfEaten);

	// ITfThreadFocusSink
	STDMETHODIMP OnSetThreadFocus();
	STDMETHODIMP OnKillThreadFocus();

	/* ITfCompositionSink */
	STDMETHODIMP OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition *pComposition);

	/* ITfEditSession */
	STDMETHODIMP DoEditSession(TfEditCookie ec);

	/* ITfActiveLanguageProfileNotifySink */
	STDMETHODIMP OnActivated(REFCLSID clsid, REFGUID guidProfile, BOOL isActivated);

	///* ITfCompartmentEventSink */
	//STDMETHODIMP OnChange(_In_ REFGUID guid);
	
	/* Compartments */
    BOOL _IsKeyboardDisabled();
    BOOL _IsKeyboardOpen();
    HRESULT _SetKeyboardOpen(BOOL fOpen);

	/* Composition */
	void _StartComposition(com_ptr<ITfContext> pContext, BOOL fCUASWorkaroundEnabled);
	void _EndComposition(com_ptr<ITfContext> pContext, BOOL clear);
	BOOL _ShowInlinePreedit(com_ptr<ITfContext> pContext, const std::shared_ptr<weasel::Context> context);
	void _UpdateComposition(com_ptr<ITfContext> pContext);
	BOOL _IsComposing();
	void _SetComposition(com_ptr<ITfComposition> pComposition);
	void _SetCompositionPosition(const RECT &rc);
	BOOL _UpdateCompositionWindow(com_ptr<ITfContext> pContext);
	void _FinalizeComposition();
	void _AbortComposition(bool clear = true);

	/* Language bar */
	HWND _GetFocusedContextWindow();
	void _HandleLangBarMenuSelect(UINT wID);

	/* IPC */
	void _EnsureServerConnected();

	/* UI */
	void _UpdateUI(const weasel::Context & ctx, const weasel::Status & status);
	void _StartUI();
	void _EndUI();
	void _ShowUI();
	void _HideUI();
	com_ptr<ITfContext> _GetUIContextDocument();


	com_ptr<ITfThreadMgr> _GetThreadMgr() { return _pThreadMgr; }

private:
	/* TSF Related */
	BOOL _InitThreadMgrEventSink();
	void _UninitThreadMgrEventSink();

	BOOL _InitTextEditSink(com_ptr<ITfDocumentMgr> pDocMgr);

	BOOL _InitKeyEventSink();
	void _UninitKeyEventSink();
	void _ProcessKeyEvent(WPARAM wParam, LPARAM lParam, BOOL *pfEaten);

	BOOL _InitPreservedKey();
	void _UninitPreservedKey();

	BOOL _InitLanguageBar();
	void _UninitLanguageBar();
	void _UpdateLanguageBar(weasel::Status stat);
	void _ShowLanguageBar(BOOL show);
	void _EnableLanguageBar(BOOL enable);

	BOOL _InsertText(com_ptr<ITfContext> pContext, const std::wstring& ext);

	void _DeleteCandidateList();

	BOOL _InitCompartment();
	void _UninitCompartment();
	HRESULT _HandleCompartment(REFGUID guidCompartment);

	bool isImmersive() const {
		return (_activateFlags & TF_TMF_IMMERSIVEMODE) != 0;
	}

	com_ptr<ITfThreadMgr> _pThreadMgr;
	TfClientId _tfClientId;
	DWORD _dwThreadMgrEventSinkCookie;

	com_ptr<ITfContext> _pTextEditSinkContext;
	DWORD _dwTextEditSinkCookie, _dwTextLayoutSinkCookie;
	BYTE _lpbKeyState[256];
	BOOL _fTestKeyDownPending, _fTestKeyUpPending;

	com_ptr<ITfContext> _pEditSessionContext;
	std::wstring _editSessionText;

	com_ptr<CCompartmentEventSink> _pKeyboardCompartmentSink;

	com_ptr<ITfComposition> _pComposition;

	com_ptr<CLangBarItemButton> _pLangBarButton;

	com_ptr<CCandidateList> _cand;

	LONG _cRef;	// COM ref count

	/* CUAS Candidate Window Position Workaround */
	BOOL _fCUASWorkaroundTested, _fCUASWorkaroundEnabled;

	/* Weasel Related */
	weasel::Client m_client;
	DWORD _activateFlags;

	/* IME status */
	weasel::Status _status;
};

这里使用了TSF(Text Services Framework),TSF是文本服务框架的简称,基于TSF的每一个输入法IME都是COM组件。支持TSF的应用程序可以在不用感知文本设备的前提下,接受从不同文本设备(键盘、手写、语音等)来源的文本输入。此外,TSF的一个重要优势是对输入法权限的管控程度远远高于IMM-IME,大大有利于系统的安全性。

输入法广泛使用 IMM32 接口,也发展成熟,XP 开始微软推广 TSF,Vista 操作系统默认开启了 TSF 管理器。但 TSF
一直饱受非议,虽然设计的很通用,但使用 COM 组件、接口隐晦、操作麻烦,而且从输入法角度来说,能做的事情似乎并不比 IMM32
强多少。此外,TSF 文档不全,样例单一,个别输入法功能上(比如输入法窗口管理)甚至比 IMM32 还要弱。TSF
似乎一直不怎么受到输入法开发者待见。直到 Win8 之后,METRO 界面只能使用 TSF 接口,于是主流输入法纷纷实现
TSF,用于处理全屏模式、游戏、以及 METRO。

TSF 特点
使用 COM 组件,扩展性非常好,但上手难度大。
本身着重文字服务,比如手写输入、语音输入,甚至纠错、翻译什么的,都是可以用 TSF 实现。
APP 和 IME 之间有更多信息可以通讯。
IME 相关功能提供不全,如只提供了输入字属性和语言栏修改,输入法窗口均需要自己实现。(因为这一点,主流的纯 TSF 输入法都放弃输入法状态栏)
大部分注册表相关任务(比如注册输入法,注册快捷键)需要自己实现。

输入法文件的本质是个 dll,只要 dll 编译正确,就可以注册进操作系统。而 TSF 输入法,则是一个可注册的,包含 COM 接口的 dll。

COM 是微软的核心接口方案,COM 在 Windows 和 Office 中使用非常广泛,比如看似笨重的 IE 其实在为整个操作系统实现了网页相关的接口。COM 的一大特点是跨进程的,使用 COM 的时候,你不知道对面是跟进程,还是个被操作系统托管的 dll,而 COM 对象而言,也会在不同进程里被使用。

DLL DEF
编译 dll 需要暴露外部接口,暴露的方式就是在编译的时候指定 def 文件。一个 COM 组件的 def 文件至少是这样的:

LIBRARY

EXPORTS
        DllGetClassObject               PRIVATE
        DllCanUnloadNow                 PRIVATE
        DllRegisterServer               PRIVATE
        DllUnregisterServer             PRIVATE

这个包里的WeaselTFS.def文件即为如此:
在这里插入图片描述
其中 DllRegisterServer 和 DllUnregisterServer 是被注册(安装卸载),也就是调用 regsvr32.exe 注册时触发的函数。
而组件实际被调用的时候,DllGetClassObject 会被调用,通常你需要返回一个 ClassFactory,注意引用管理。
DllCanUnloadNow 则是用来计算能否卸载,需要跟引用管理配合。

下篇继续~


http://www.niftyadmin.cn/n/823742.html

相关文章

山东大学软件工程应用于实践——WeaselTSF(二)

2021SCSDUSC 文章目录TSF的构架图TFS代码实例WeaselTFS.h详解ITfTextInputProcessorEx、ITfTextInputProcessorITfThreadMgrEventSinkITfKeyEventSinkITfContext、ITfEditSessionITfContextComposition、ITfCompositionITfTextEditSink、ITfCompositionSinkITfThreadFocusSinkI…

性能调优案例分享:Mysql的cpu过高

性能调优案例分享&#xff1a;Mysql的cpu过高 问题&#xff1a;一个系统&#xff0c;Mysql数据库&#xff0c;数据量变大之后。mysql的cpu占用率很高&#xff0c;一个测试端访问服务器时mysql的cpu占用率为15% &#xff0c;6个测试端连服务器的时候mysql cpu占用率为50%~60% 。…

山东大学软件工程应用于实践——WeaselTSF(三)

2021SCSDUSC 文章目录Register.hRegister.cpp本篇首先分析下WeaselTSF包里Register.h以及Register.cpp这两个文件。Register.h #pragma once#include "Globals.h"BOOL RegisterProfiles(); void UnregisterProfiles(); BOOL RegisterCategories(); void UnregisterC…

JAVA大数运算

java大数是个好东西&#xff0c;用起来方便&#xff0c;代码短. 代码如下: import java.util.*; import java.math.*; public class Main {public static void main(String args[]) {Scanner cin new Scanner(System.in);BigInteger a , b;while(cin.hasNext()) {a cin.nextB…

山东大学软件工程应用与实践——WeaselIME(一)

2021SCSDUSC 文章目录IME概述IME工作原理IME命令IME示例从这一篇开始分析WeaselIME包的关键代码。在这里我们先简单了解一下IME。IME概述 IME是指Input Method Editors输入法编辑器&#xff0c;它是一种专门的应用程序&#xff0c; 用来输入代表东亚地区书面语言文字的不同字符…

Oracle新建表

-- Create table create table T_HQ_B (xzingm VARCHAR2(10),zhuz VARCHAR2(20),zhis NUMBER,bianh VARCHAR2(10) not null )(initial 64Kminextents 1maxextents unlimited); -- Add comments to the columns comment on column T_HQ_B.xzingmis 姓名; comment on colum…

ubuntu 下node 环境的安装

1. 安装nodejs sudo apt-get install nodejs 注意&#xff1a;包名是nodejs 2. 建立node软连接 #找到nodejs位置 which nodejs # /usr/bin/nodejs sudo ln -s /usr/bin/nodejs /usr/bin/node 3. 安装npm(Node package Manager) curl http://npmjs.org/install.sh | sudo sh ps&…

山东大学软件工程应用与实践——WeaselIME(二)

2021SCSDUSC 文章目录IME常用函数IME 文件中的常用结构IME常用函数 BOOL WINAPI ImmGenerateMessage( //将汉字串法发送到与当前输入法相关联的应用软件中HIMC hIMC);//成功为TRUE&#xff0c;否则为FALSELRESULT WINAPI ImmRequestMessage( //向应用程序发送WM_IME_REQUEST消…