目录:

  • 滚动条
  • 键盘
  • 鼠标

滚动条ScrollBar

发送消息:WM_VSCROLL和WM_HSCROLL

参数wParam:wParam消息参数被分为一个低字组和一个高字组。wParam的低字组是一个数值,它指出了鼠标对滚动条进行的操作。这个数值被看作一个「通知码」。通知码的值由以SB(代表「scroll bar(滚动条)」)开头的标识符定义。wParam的高字组存当前滚动条的位置信息。

参数lParam: 对于来自作为窗口的一部分而建立的滚动条消息,您可以忽略lParam;它只用于作为子窗口而建立的滚动条(通常在对话框内)。

也带有wParam和lParam消息参数。

以下是在WINUSER.H中定义的通知码:

#define SB_LINEUP       0
#define SB_LINELEFT 0
#define SB_LINEDOWN 1
#define SB_LINERIGHT 1
#define SB_PAGEUP 2
#define SB_PAGELEFT 2
#define SB_PAGEDOWN 3
#define SB_PAGERIGHT 3
#define SB_THUMBPOSITION 4
#define SB_THUMBTRACK 5
#define SB_TOP 6
#define SB_LEFT 6
#define SB_BOTTOM 7
#define SB_RIGHT 7
#define SB_ENDSCROLL 8

使用示范代码:

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ //......
hwnd = CreateWindow (szAppName, TEXT ("Get System Metrics No. 2"),
WS_OVERLAPPEDWINDOW | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ; //......
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_CREATE:
// Initialization
SetScrollRange (hwnd, SB_VERT, , NUMLINES - , FALSE) ;
SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;
return ;
case WM_VSCROLL: switch (LOWORD (wParam)) {
case SB_LINEUP:iVscrollPos++;break;
case SB_PAGEUP:break;
case SB_THUMBPOSITION:break;
//...... } //...... } }

键盘

发送消息:【按键消息】和【字符消息】

【按键消息】:

 

键按下

键释放

非系统键

WM_KEYDOWN

WM_KEYUP

系统键

WM_SYSKEYDOWN

WM_SYSKEYUP

(系统键:WM_SYSKEYDOWN和WM_SYSKEYUP消息经常由与Alt相组合的按键产生,这些按键启动程序菜单或者系统菜单上的选项,或者用于切换活动窗口等系统功能(Alt-Tab或者Alt-Esc),也可以用作系统菜单快捷键(Alt键与一个功能键相结合,例如Alt-F4用于关闭应用程序)。)

【字符消息】:TranslateMessage把字符消息放入消息队列中。此字符消息将是GetMessage从消息队列中得到的按键消息之后的下一个消息。

 

字符

死字符

非系统字符

WM_CHAR

WM_DEADCHAR

系统字符

WM_SYSCHAR

WM_SYSDEADCHAR

参数wParam:对所有四类按键消息,wParam是虚拟键代码,表示按下或释放的键,而lParam则包含属于按键的其它数据。

对于字符消息,wParam是字符的ASCII编码等,lParam 同上

参数lParam:如下图:

重复计数

重复计数是该消息所表示的按键次数,大多数情况下,重复计数设定为1。不过,如果按下一个键之后,您的窗口消息处理程序不够快,以致不能处理自动重复速率(您可以在「控制台」的「键盘」中进行设定)下的按键消息,Windows就把几个WM_KEYDOWN或者WM_SYSKEYDOWN消息组合到单个消息中,并相应地增加重复计数。WM_KEYUP或WM_SYSKEYUP消息的重复计数总是为1。

因为重复计数大于1指示按键速率大于您程序的处理能力,所以您也可能想在处理键盘消息时忽略重复计数。几乎每个人都有文书处理或执行电子表格时画面卷过头的经验,因为多余的按键堆满了键盘缓冲区,所以当程序用一些时间来处理每一次按键时,如果忽略您程序中的重复计数,就能够解决此问题。不过,有时可能也会用到重复计数,您应该尝试使用两种方法执行程序,并从中找出一种较好的方法。

OEM扫描码

OEM扫描码是由硬件(键盘)产生的代码。这对中古时代的汇编程序写作者来说应该很熟悉,它是从PC相容机种的ROM BIOS服务中所获得的值(OEM指的是PC的原始设备制造商(Original Equipment Manufacturer)及其与「IBM标准」同步的内容)。在此我们不需要更多的信息。除非需要依赖实际键盘布局的样貌,不然Windows程序可以忽略掉几乎所有的OEM扫描码信息,参见第二十二章的程序KBMIDI

扩充键旗标

如果按键结果来自IBM增强键盘的附加键之一,那么扩充键旗标为1(IBM增强型键盘有101或102个键。功能键在键盘顶端,光标移动键从数字键盘中分离出来,但在数字键盘上还保留有光标移动键的功能)。对键盘右端的Alt和Ctrl键,以及不是数字键盘那部分的光标移动键(包括Insert和Delete键)、数字键盘上的斜线(/)和Enter键以及Num Lock键等,此旗标均被设定为1。Windows程序通常忽略扩充键旗标。

内容代码

右按键时,假如同时压下ALT键,那么内容代码为1。对WM_SYSKEYUP与WM_SYSKEYDOWN而言,此位总视为1;而对WM_SYSKEYUP与WM_KEYDOW消息而言,此位为0。除了两个之外:

  • 如果活动窗口最小化了,则它没有输入焦点。这时候所有的按键都会产生WM_SYSKEYUP和WM_SYSKEYDOWN消息。如果Alt键未被按下,则内容代码字段被设定为0。Windows使用WM_SYSKEYUP和WM_SYSKEYDOWN消息,从而使最小化了的活动窗口不处理这些按键。
     
  • 对于一些外国语文(非英文)键盘,有些字符是通过Shift、Ctrl或者Alt键与其它键相组合而产生的。这时内容代码为1,但是此消息并非系统按键消息。
     

键的先前状态

如果在此之前键是释放的,则键的先前状态为0,否则为1。对WM_KEYUP或者WM_SYSKEYUP消息,它总是设定为1;但是对WM_KEYDOWN或者WM_SYSKEYDOWN消息,此位可以为0,也可以为1。如果为1,则表示该键是自动重复功能所产生的第二个或者后续消息。

转换状态

如果键正被按下,则转换状态为0;如果键正被释放,则转换状态为1。对WM_KEYDOWN或者WM_SYSKEYDOWN消息,此字段为0;对WM_KEYUP或者WM_SYSKEYUP消息,此字段为1。

位移状态

在处理按键消息时,您可能需要知道是否按下了位移键(Shift、Ctrl和Alt)或开关键(Caps Lock、Num Lock和Scroll Lock)。通过呼叫GetKeyState函数,您就能获得此信息。例如:

iState = GetKeyState (VK_SHIFT) ;
//如果按下了Shift,则iState值为负(即设定了最高位置位)。如果Caps Lock键打开,则从
iState = GetKeyState (VK_CAPITAL) ;
//传回的值低位被设为1。此位与键盘上的小灯保持一致。 /*
您在使用GetKeyState时,会带有虚拟键码VK_SHIFT、VK_CONTROL和VK_MENU(在说明Alt键时呼叫)。使用GetKeyState时,您也可以用下面的标识符来确定按下的Shift、Ctrl或Alt键是左边的还是右边的:VK_LSHIFT、VK_RSHIFT、VK_LCONTROL、VK_RCONTROL、VK_LMENU、VK_RMENU。这些标识符只用于GetKeyState和GetAsyncKeyState 使用虚拟键码VK_LBUTTON、VK_RBUTTON和VK_MBUTTON,您也可以获得鼠标键的状态。 注意GetKeyState的使用,它并非实时检查键盘状态,而只是检查直到目前为止正在处理的消息的键盘状态。多数情况下,这正符合您的要求。如果您需要确定使用者是否按下了Shift-Tab,请在处理Tab键的WM_KEYDOWN消息时呼叫GetKeyState,带有参数VK_SHIFT。如果GetKeyState传回的值为负,那么您就知道在按下Tab键之前按下了Shift键。并且,如果在您开始处理Tab键之前,已经释放了Shift键也没有关系。您知道,在按下Tab键的时候Shift键是按下的。 */

使用示范代码:

//对于 IParam 的读取代码 (片段)
//......
TCHAR * szFormat[] = {
TEXT ("%-13s %3d %-15s%c%6u %4d %3s %3s %4s %4s"),
TEXT ("%-13s 0x%04X%1s%c %6u %4d %3s %3s %4s %4s") } ;
//......
TextOut (hdc, , (cyClient / cyChar - - i)*cyChar,szBuffer,
wsprintf (szBuffer, szFormat [iType],
szMessage [pmsg[i].message - WM_KEYFIRST],
pmsg[i].wParam,
(PTSTR) (iType ? TEXT (" ") : szKeyName),
(TCHAR) (iType ? pmsg[i].wParam : ' '),
LOWORD (pmsg[i].lParam),
HIWORD (pmsg[i].lParam) & 0xFF,
0x01000000 & pmsg[i].lParam ? szYes : szNo,
0x20000000 & pmsg[i].lParam ? szYes : szNo,
0x40000000 & pmsg[i].lParam ? szDown : szUp,
0x80000000 & pmsg[i].lParam ? szUp:szDown));
//......

鼠标:

发送消息:鼠标定义了21种消息,不过,其中有11个消息和显示区域无关(下面称之为「非显示区域」消息),Windows程序经常忽略这些消息。

【显示区域相关】:WM_MOUSEMOVE +

按下

释放

按下(双键)

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_MBUTTONDOWN

WM_MBUTTONUP

WM_MBUTTONDBLCLK

WM_RBUTTONDOWN

WM_RBUTTONUP

WM_RBUTTONDBLCLK

【显示区域无关】:WM_NCMOUSEMOVE +

按下

释放

按下(双击)

WM_NCLBUTTONDOWN

WM_NCLBUTTONUP

WM_NCLBUTTONDBLCLK

WM_NCMBUTTONDOWN

WM_NCMBUTTONUP

WM_NCMBUTTONDBLCLK

WM_NCRBUTTONDOWN

WM_NCRBUTTONUP

WM_NCRBUTTONDBLCLK

+ WM_NCHITTEST

参数wParam:【显示区域】wParam的值指示鼠标按键以及Shift和Ctrl键的状态

       【非显示区域】wParam参数指明移动或者按鼠标按键的非显示区域。它设定为WINUSER.H中定义的以HT开头的标识符之一(HT表示「命中测试」)。

参数lParam:   【显示区域】Client鼠标的位置:低字组为x坐标,高字组为y坐标
       【非显示区域】屏幕鼠标的位置:低字组为x坐标,高字组为y坐标

使用小妙招(1):

wParam的值指示鼠标按键以及Shift和Ctrl键的状态。您可以使用表头文件WINUSER.H中定义的位屏蔽来测试wParam。MK前缀代表「鼠标按键」。

MK_LBUTTON

按下左键

MK_MBUTTON

按下中键

MK_RBUTTON

按下右键

MK_SHIFT

按下Shift键

MK_CONTROL

按下Ctrl键

wparam & MK_SHIFT 是TRUE(非0),您就知道当左键按下时也按下了Shift键。
妙招实例:
 //实现 左键 拖动时 画点
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON && iCount < ) {
pt[iCount ].x = LOWORD (lParam) ;
pt[iCount++].y = HIWORD (lParam) ; hdc = GetDC (hwnd) ;
SetPixel(hdc,LOWORD(lParam),HIWORD(lParam), ) ;
ReleaseDC (hwnd, hdc) ;
}
return ;
使用小妙招(2):

Windows函数GetKeyState(在“指导书”第六章中介绍过)可以使用虚拟键码VK_LBUTTON、VK_RBUTTON、VK_MBUTTON、VK_SHIFT和VK_CONTROL来传回鼠标按键与Shift键的状态。
使用小妙招(3):
检测双击事件需要在创建窗口时指定参数:  wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;

使用小妙招(4):

对于非显示区域的鼠标事件、以及下文将提到的“鼠标拦截”,得到的是整个屏幕的图素坐标,要得到其对应的可以直接使用的Client坐标,

您可以用两个Windows函数将屏幕坐标转换为显示区域坐标或者反之:

ScreenToClient (hwnd, &pt) ;

ClientToScreen (hwnd, &pt) ;

使用小妙招(5):
21个鼠标消息中的20个,最后一个消息是WM_NCHITTEST,它代表「非显示区域命中测试」。此消息优先于所有其它的显示区域和非显示区域鼠标消息。lParam参数含有鼠标位置的x和y屏幕坐标,
wParam参数没有用。

Windows应用程序通常把这个消息传送给DefWindowProc,然后Windows用WM_NCHITTEST消息产生与鼠标位置相关的所有其它鼠标消息。对于非显示区域鼠标消息,在处理WM_NCHITTEST时,从DefWindowProc传回的值将成为鼠标消息中的wParam参数,这个值可以是任意非显示区域鼠标消息的wParam值再加上以下内容:

HTCLIENT

HTNOWHERE

HTTRANSPARENT

HTERROR

显示区域

不在窗口中

窗口由另一个窗口覆盖

使DefWindowProc产生警示用的哔声

【猜测】【windows 来处理的话,自动处理了坐标转换等等;其返回的HT_... 就可以决定接下来产生的下一个消息:

“相当”于:

if(inClient)  SendClientMessage( hwnd,MOUSETYPE(MK_TEST),wParam(Shift...),lParam(PosTranslate));

else  SendClientMessage( hwnd,MOUSETYPE2(MK_TEST),wParam(HTClient...),lParam(PosOrigon));】
所以:

case WM_NCHITTEST:
return (LRESULT) HTNOWHERE ;

就可以有效地禁用您窗口中的所有显示区域和非显示区域鼠标消息。

使用小妙招(6):

对于一些有需要的应用,可以使用 鼠标拦截

SetCapture (hwnd) ;
ReleaseCapture () ;
/*
在32位的Windows中,鼠标拦截要比在以前的Windows版本中有多一些限制。特别是,如果鼠标被拦截,而鼠标按键目前并未被按下,并且鼠标光标移到了另一个窗口上,
那么将不是由拦截鼠标的那个窗口,而是由光标下面的窗口来接收鼠标消息。对于防止一个程序在拦截鼠标之后不释放它而引起整个系统的混乱,这是必要的。
*/

windows 编程 —— 消息与参数(滚动条、键盘、鼠标)的更多相关文章

  1. windows 编程 —— 消息与参数(定时器、初始化消息、改变大小)

    目录: 定时器 WM_TIMER 初始化消息 WM_CREATE 改变大小 WM_SIZE 定时器: 接收消息:WM_TIMER 参数wParam:wParam参数等于定时器的ID值(上述情形为1). ...

  2. 深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)

    1,回调函数工作机制 回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了. 2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的. 下面还是以 ...

  3. Windows 编程 键盘

    键盘对于大家来说可能再也熟悉不过了,它和鼠标是现在最常用的电脑输入设备.虽然在现在的图形界面操作系统下使用鼠标比使用键盘更方便.更广泛,但是鼠标还是一时半会儿取代不了它的老前辈——键盘的地位,尤其是在 ...

  4. Windows 窗体消息大全(速查)

    Windows窗口消息大全,全不全自己撸 通用窗口消息 WM_NULL:--------->空消息,可检测程序是否有响应等 WM_CREATE:--------->新建一个窗口 WM_DE ...

  5. Windows编程 鼠标

    客户区鼠标消息 由上一回我们得知Windows只把键盘消息发送给拥有输入焦点的窗口,而鼠标消息与此不同:只要鼠标跨越窗口或者在某窗口下按下鼠标键,那么窗口过程就会收到鼠标消息,不管该窗口是否活动或者是 ...

  6. 【Visual C++】游戏编程学习笔记之七:键盘输入消息

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  7. mac与windows共享键盘鼠标(synergy)

    桌面上有两台电脑, 一台mac一台windows, 由于桌面空间紧张, 放两套键盘鼠标有点浪费空间, 如果能让mac和windows共享键盘鼠标就好了, 经过一番搜寻, 找到了一款名为synergy的 ...

  8. windows编程,消息函数中拦截消息的问题

    很多年没有写windows窗口程序了,今天自制基于vulkan的程序时遇到了一些问题,部分代码如下: LRESULT CALLBACK XWindow::WndProc(HWND hWnd, UINT ...

  9. Windows编程入门程序详解

    引用:http://blog.csdn.net/jarvischu/article/details/8115390 1.     程序 /******************************* ...

随机推荐

  1. singleTask TaskAffinity allowTaskReparenting

    关于singleTask TaskAffinity allowTaskReparenting 一.Activity的LaunchMode 1.standard 2.singleTop:FLAG_ACT ...

  2. 【转】 iOS Provisioning Profile(Certificate)与Code Signing详解

    原文:http://blog.csdn.net/phunxm/article/details/42685597 引言 关于开发证书配置(Certificates & Identifiers & ...

  3. Swift - 06 - 数值类型转换和类型别名

    //: Playground - noun: a place where people can play import UIKit var str = "Hello, playground& ...

  4. Xcode换版本或者改名字后无法使用simpholders2

    修改一下路径,在终端下输入下面的命令sudo /usr/bin/xcode-select -switch /Applications/Xcode.app/Contents/Developer 敲回车后 ...

  5. 微信小应用vs progressive-web-apps

    https://developers.google.com/web/progressive-web-apps/

  6. gdb调试 使用心得

    1: 对于在应用程序中加入参数进行调试的方法:   直接用 gdb app -p1 -p2 这样进行调试是不行的.   需要像以下这样使用:    #gdb app    (gdb) r -p1 -p ...

  7. 初涉JavaScript模式 (13) : 代码复用 【上】

    引子 博客断了一段时间,不是不写,一是没时间,二是觉得自己沉淀不够,经过一段时间的学习和实战,今天来总结下一个老生常谈的东西: 代码复用. 为何复用 JS门槛低,故很多人以为写几个特效就会JS,其实真 ...

  8. phpcms首页商机的调用,多种方式

    <hr /> {pc:get sql="select * from phpcms_yp_buy" order="updatetime DESC"} ...

  9. Tomcat 9.0安装配置

    本文转自:http://blog.sina.com.cn/s/blog_15126e2170102w5o8.html 一.JDK的安装与配置 1.从官网下载jdk,注意是jdk不是jre.最好从官网下 ...

  10. [转]解读ASP.NET 5 & MVC6系列(7):依赖注入

    本文转自:http://www.cnblogs.com/TomXu/p/4496440.html 在前面的章节(Middleware章节)中,我们提到了依赖注入功能(Dependency Inject ...