Duilib 中的消息处理过程:
我们首先从窗口的创建开始,RegisterWindowClass
时注册了消息处理函数 CWindowWnd::__WndProc
,在 CreateWindowEx
创建窗口之后,static void CPaintManagerUI::MessageLoop()
首先进行消息的过滤,未处理的消息再发送给窗口。除了 WM_NCCREATE
和 WM_NCDESTROY
之外的消息都由 LRESULT WindowImplBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
进行处理,最关键的一步是 WM_CREATE
对应的 OnCreate
函数,在 OnCreate
中初始化 CPaintManagerUI
,读取 xml 初始化所有的 CControlUI
, xml 这部分内容可以参考之前的 Blog : Duilib 源码分析之 xml 加载篇 和 Duilib 源码分析之 xml 解析篇
下一步,在 HandleMessage
中屏蔽了非客户区的绘制,Duilib 绘制的只有客户区,所谓的标题栏都是在客户区进行自绘的。
OnNcCalcSize
和OnNcPaint
屏蔽了非客户区OnNcHitTest
实现了普通窗口在非客户区边缘鼠标可拖拽改变窗口大小的功能和拖动标题栏移动窗口的功能,主要是通过控制返回值来实现的
static void CPaintManagerUI::MessageLoop()
, 核心是调用 GetMessage
读取消息,读取到消息后,首先调用 bool CPaintManagerUI::TranslateMessage(const LPMSG pMsg)
进行处理,若没有进行处理,则调用默认的消息处理。
在 bool CPaintManagerUI::TranslateMessage(const LPMSG pMsg)
的处理过程中,分为窗口是否是有 WS_CHILD
样式,处理过程稍有不同,但都是要找到当前消息对应的窗口的 CPaintManagerUI
,然后进行以下两项处理:
bool CPaintManagerUI::TranslateAccelerator(LPMSG pMsg)
目前只有CWebBrowserUI
需要进行这种处理(在控件创建后通过GetManager()->AddTranslateAccelerator(this)
添加到需要处理TranslateAccelerator
的列表中),最终会调用到HRESULT CComPtr<IOleInPlaceActiveObject>::TranslateAccelerator(MSG* pMsg)
, 作用是将WM_KEYDOWN
或WM_SYSKEYDOWN
翻译为WM_COMMAND
或WM_SYSCOMMAND
然后再发送给窗口bool PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)
处理键盘事件
- 首先遍历
m_aPreMessageFilters
调用MessageHandler
处理键盘事件,默认m_aPreMessageFilters
会添加WindowImplBase
, 在当前版本的 duilib 中并没有在这个函数中屏蔽VK_RETURN
和VK_ESCAPE
- 继续处理
VK_TAB
, 若当前焦点所在控件是CRichEditUI
且在输入状态下不希望通过 tab 改变焦点 (IsWantTab() == true) 或当前焦点所在控件是 WkeWebkitUI ,也不进行焦点控件的切换。 否则则找下一个控件 SetFocus (Shift 按下时找上一个) WM_SYSCHAR
处理快捷键,很多时候我们都会为按钮或者菜单项加快捷键 (ALT+自定义按键),找到对应的控件后执行对应的响应函数
- 首先遍历
上述过程未处理的情况下,消息会发送到各自的窗口进行处理,这部分的处理也分为三种情况:
- 用户自定义消息:需要重载
LRESULT WindowImplBase::HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
, 处理后把bHandled
设置为true
可以防止消息继续走默认的处理函数 - 由
bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)
处理的消息,这部分内容是 Duilib 中最为核心的处理内容 - 通过
DefWindowProc
执行默认消息处理