八.滚动条
1.概念
1.1滚动条既有垂直方向的(供上下移动),也有水平方向的(供左右移动)
1.2程序实际上是将文件相对于显示窗口向上移动 ---- 向上滚动意味着朝文件的开头移动,向下滚动意味着朝文件尾部移动
1.3关键字
在CreateWindow的第三个参数中包括窗口风格标识号WS_VSCROLL(垂直滚动)和(或)WS_HSCROLL(水平滚动)
这些滚动条默认在窗口的右部和底部
垂直滚动条显示在窗口的左侧: WS_EX_LEAFTSCROLLBAR
2.使能、禁止滚动条
EnableScrollBar (hWnd, SB_HORZ, TRUE);
EnableScrollBar (hWnd, SB_VERT, FALSE);
3.滚动条的范围和位置
滚动条的属性 ------ 范围 : 最小值 和 最大值
位置 :滚动滑块在次范围内的位置
结构体:SCROLLINFO si;
si.nMax = 100;
si.nMin = 0;
si.nPage = 10;
si.nPos = 0;
SetScrollInfo (hWnd, Bar, &si, bRedraw);
窗口根据新范围重画滚动条,则设置 bRedraw 为 TRUE
SetScrollRange 调用了影响滚动条位置的其他函数 bRedraw 设定为 FALSE
处理滚动条鼠标事件
1.使用者 ----》 拖动滚动滑块 ---》 移动滚动滑块
2.为包含滚动条的窗口处理程序 ----》 发送滚动条消息
程序编写者
1.初始化滚动条的位置和范围
2.处理窗口处理程序的滚动条消息
3.更新滚动条内滚动滑块的位置
4.显示区的区域的内容 ------- 滚动条的更改
4.滚动条消息
产生的事件:鼠标单击滚动条 拖动滚动滑块
消息: MSG_VSCROLL(供上下移动) MSG_HSCROLL(供左右移动)
wParam消息参数 ----》 通知码
SB_LINEUP SB_LINEDOWN SB_PAGEUP SB_PAGEDOWN
SB_LINELEFT SB_LINERIGHT SB_PAGELEFT SB_PAGERIGHT
SB_THUMBTRACK SB_THUMBPOSITION
在滑动过程中
wParam : SB_THUMBTRACK -------- lParam : 是使用者在拖动滑块时的目前位置
在滑动完成后
在SB_THUMBTRACK或SB_THUMBPOSITION中,如果不调用SetScrollPos函数,滑块就会回到原来的位置
如果在滑动中如果要移动显示的区域,有些程序数据量大,重绘效率低很难跟的上消息
这时可以只处理SB_THUMBPOSITION
5.相关函数
EnableScrollBar (hWnd, SB_HORZ, FALSE);
SetScrollRange (hWnd, SB_VERT, 0, 20);
ShowScrollBar (hWnd, SB_HORZ, FALSE);
在MSG_HSCROLL中 ---》向右滚:ScrollWindow (hWnd, -GetSysCharWidth (), 0, NULL, NULL);
每次滚一个系统字符宽度
SB_LINEDOWN向上滚每次滚一个 20 个象素高:ScrollWindow (hWnd, 0, -20, NULL, NULL);
相当于外面的滑动框是静止不动的,要看到下面的区域,显示区域需要向上移动(向上移动对应y轴)
九.键盘和鼠标
1.键盘
1.1输入流程
键盘 -----(原始输入数据)-----> 键盘设备驱动 -------> 底层事件处理 ----(击键消息)----->消息队列----->窗口过程
设备驱动程序: 键盘(接收原始的输入事件或数据) ----> MiniGUI抽象的键盘和输入
1.2MiniGUI抽象的键盘和输入
特点: 1.支持255个键
2.每个不同的键对应独一无二的"扫描码"
3.129以下的对应PC键盘
1.3击键消息
按下: MSG_KEYDOWN 或者 MSG_SYSKEYDOWN
释放: MSG_KEYUP 或者 MSG_SYSKEYUP
长按不放 ----> 会产生一系列的MSG_KEYDOWN 自动重复特性
作用:系统击键消息:控制菜单的激活 非系统击键消息:应用程序
产生系统按键消息:ALT按下击键 非系统按键消息:普通击键
击键消息的wParam --- 扫描码 IParam --- SHIFT、ALT、CTRL特殊键标志
1.4字符消息 --- MSG_CHAR MSG_SYSCHAR
TranslateMessage(&Msg);
根据击键消息的MSG_KEYDOWN和MSG_SYSKEYDOWN的扫描码和特殊符号的组合--->字符编码(ascii码)
wParam:按下字符键的ASCII码 lParam:特殊按键
注:用途
MSG_KEYDOWN:读取游标键、功能键、Delete、Insert、Shift、Ctrl以及Alt
MSG_CHAR: 读取输入到窗口的键盘字符
1.5键状态
处理组合键 ----- lparam与相关的宏位与
特殊换档键: Shift Ctrl Alt
开关键: Caps Lock、Num Lock 和 Scroll Lock
KS_CAPSLOCK CapsLock 键被锁住
KS_NUMLOCK NumLock 键被锁住
KS_SCROLLLOCK ScrollLock 键被锁住
KS_LEFTCTRL 左 Ctrl 键被按下
KS_RIGHTCTRL 右 Ctrl 键被按下
KS_CTRL 任何一个 Ctrl 键被按下
KS_LEFTSHIFT 左 Shift 键被按下
KS_RIGHTSHIFT 右 Shift 键被按下
KS_SHIFT 任何一个 Shift 键被按下
KS_IMEPOST 鼠标消息由 IME 窗口投递
KS_LEFTBUTTON 鼠标左键被按下
KS_RIGHTBUTTON 鼠标右键被按下
KS_MIDDLBUTTON 鼠标中键被按下
KS_CAPTURED 鼠标被窗口捕获(只能用于鼠标消息)
这些键均能用于击键消息和鼠标消息
得到这些消息和状态: 1.在消息过程处理函数的lparam消息与状态位与
2.DWORD GUIAPI GetShiftKeyStatus (void);
例:GetShiftKeyStatus() & KS_CTRL 来确定左或右 Ctrl 键是否被按下
3.BOOL GUIAPI GetKeyStatus (UINT uKey);
查询的是该键的扫描码,如果该键被按下,GetKeyStatus返回TRUE,否则返回FALSE
1.6 输入焦点
具有输入焦点的键盘可以接收键盘输入
活动窗口、活动窗口的子窗口、活动窗口的子窗口的子窗口
子窗口一般通过一个闪烁的插入符 ------- 代表这个窗口有输入焦点
输入焦点是窗口的一个属性 ---- 移动输入焦点让显示在屏幕上的所有窗口共享键盘
系统-----(MSG_KILLFOCUS)-----失去焦点的窗口
系统-----(MSG_SETFOCUS)------得到焦点的窗口
应用程序 GetFocusChild 获得某个窗口中具有输入焦点的子窗口的句柄
#define GetFocus GetFocusChild
HWND GUIAPI GetFocusChild (HWND hWnd);
父窗口 -----(设置输入焦点) ----- 子窗口
#define SetFocus SetFocusChild
HWND GUIAPI SetFocusChild (HWND hWnd);
消息把击键消息发送到具有输入焦点的窗口
2.鼠标
2.1相关概念
鼠标设备---(原始输入数据)---->鼠标设备驱动------->底层事件处理----(鼠标消息)---->消息队列---->窗口过程
屏幕:鼠标光标的小位图
鼠标光标的小位图里面有一个像素点 ----- 热点
热点 ----- 跟踪和识别光标的位置
系统把鼠标消息发送到具有热点的窗口
2.2鼠标消息
事件的产生:用户移动鼠标、按下或者释放鼠标按钮
鼠标消息:客户区消息和非客户区消息(通常处理客户区消息而忽略非客户区消息)
客户区消息:
MSG_MOUSEMOVE 移动鼠标
MSG_LBUTTONDOWN 鼠标左按钮被按下
MSG_LBUTTONUP 鼠标左按钮被释放
MSG_RBUTTONDOWN 鼠标右按钮被按下
MSG_RBUTTONUP 鼠标右按钮被释放
MSG_LBUTTONDBLCLK 鼠标左按钮被双击
MSG_RBUTTONDBLCLK 鼠标右按钮被双击
wParam参数:键状态值 例:lParam & KS_SHIFT) 为 TRUE
lParam参数:光标热点的位置 低位字(x) 高位字(y) ------> 客户区坐标
当窗口捕获鼠标时,上述消息的位置坐标 -----> 屏幕坐标
非客户区消息:标题栏、菜单和窗口滚动条
MSG_NCLBUTTONDOWN 鼠标左按钮被按下
MSG_NCLBUTTONUP 鼠标左按钮被释放
MSG_NCRBUTTONDOWN 鼠标右按钮被按下
MSG_NCRBUTTONUP 鼠标右按钮被释放
MSG_NCLBUTTONDBLCLK 鼠标左按钮被双击
MSG_NCRBUTTONDBLCLK 鼠标右按钮被双击
wParam参数: 指明移动或单击鼠标按钮时的非客户区位置
lParam参数: 低位字(x) 高位字(y) -------> 窗口坐标
wParam参数值: 击中检测码
#define HT_UNKNOWN 0x00
#define HT_OUT 0x01
#define HT_MENUBAR 0x02
#define HT_TRANSPARENT 0x03
#define HT_BORDER_TOP 0x04
#define HT_BORDER_BOTTOM 0x05
#define HT_BORDER_LEFT 0x06
#define HT_BORDER_RIGHT 0x07
#define HT_CORNER_TL 0x08
#define HT_CORNER_TR 0x09
#define HT_CORNER_BL 0x0A
#define HT_CORNER_BR 0x0B
#define HT_CLIENT 0x0C
#define HT_NEEDCAPTURE 0x10
#define HT_BORDER 0x11
#define HT_NCLIENT 0x12
#define HT_CAPTION 0x13
#define HT_ICON 0x14
#define HT_CLOSEBUTTON 0x15
#define HT_MAXBUTTON 0x16
#define HT_MINBUTTON 0x17
#define HT_HSCROLL 0x18
#define HT_VSCROLL 0x19
哪些窗口会收到鼠标消息----->含有热点的窗口或者捕捉鼠标的窗口
MSG_HITTEST(MSG_NCHITTEST)
wParam: 光标热点的 x 坐标
lParam: 光标热点的 y 坐标
缺省的鼠标消息处理程序:对MSG_HITTEST处理 返回值:击中检测码
如果光标热点在客户区 -----> 返回HT_CLIENT 光标热点屏幕坐标转为客户区坐标 ---> 向相应的窗口过程发送客户区鼠标消息
如果光标热点在窗口的非客户区 -----> 击中检测码返回 ----> 击中检测码(wParam),光标坐标(lParam)--> 向相应的窗口发送非客户区鼠标消息
2.3 鼠标捕获
在某一时刻只能有一个窗口捕获鼠标
HWND GUIAPI SetCapture(HWND hWnd);//使某个窗口捕获鼠标
void GUIAPI ReleaseCapture(void);//
HWND GUIAPI GetCapture(void);//来确定当前是哪个窗口捕获了鼠标
3.事件钩子
3.1正常的途径
(键盘事件和鼠标事件) -----> 底层设备 ------> 最终的应用程序窗口过程
机制
底层设备 ------(消息)---------(钩子函数)-------> 返回值 ---->(继续传递) -----> 窗口
底层设备 ------(消息)---------(钩子函数)-------> 返回值 ---->不再传递
钩子函数的原型
MiniGUI-Threads 和 MiniGUI-Standalone
typedef int (* MSGHOOK)(void* context, HWND dst_wnd, int msg, WPARAM wparam, LPARAM lparam);
context:注册钩子时传入的一个上下文信息
dst_wnd:该消息的目标主窗口
msg: 消息的标识符
wparam和lparam是消息的两个参数
返回值: HOOK_GOON 继续传递事件
HOOK_STOP 停止事件的继续传递
注册键盘和鼠标事件的钩子函数
MSGHOOK GUIAPI RegisterKeyMsgHook (void* context, MSGHOOK hook);
MSGHOOK GUIAPI RegisterMouseMsgHook (void* context, MSGHOOK hook);
context:上下文信息
hook:回调函数的指针
返回值:会返回先前注册的钩子函数的指针
注销先前的钩子函数
MSGHOOK GUIAPI RegisterKeyMsgHook (void* context, MSGHOOK hook);
MSGHOOK GUIAPI RegisterMouseMsgHook (void* context, MSGHOOK hook);
hook = NULL
钩子回调函数是由 MiniGUI 桌面线程调用的,也就是说,钩子回调函数是在桌面线程中执行的,因此,不能在钩子
回调函数中向其他线程通过 SendMessage 的方式发送消息,这样会导致可能的死锁发生。
MiniGUI-Processes模式
HWND GUIAPI RegisterKeyHookWindow (HWND hwnd, DWORD flag);
HWND GUIAPI RegisterMouseHookWindow (HWND hwnd, DWORD flag);
hwnd:客户端窗口句柄
flag: 控制是否停止处理钩子消息
HOOK_GOON 用来继续, HOOK_STOP 用来停止
服务器进程
typedef int (* SRVEVTHOOK) (PMSG pMsg);
SRVEVTHOOK GUIAPI SetServerEventHook (SRVEVTHOOK SrvEvtHook);
pMsg 是要传递的消息结构指针。服务器可以随意修改该指针指向的消息结构中的值
返回值: HOOK_GOON 正常处理
HOOK_STOP 取消处理
作用:使用钩子函数,我们可以监测系统的空闲时间,并在系统空闲时间到达设定值时启动屏幕保护程序