这节讲述windows如何产生键盘输入和程序如何接受和处理输入;
所有Microsoft windows的应用程序应该能够从键盘和鼠标接收用户的输入,windows应用程序是以处理投递到窗口的消息的形式接收键盘输入的。
windows系统通过安装与当前键盘相应的键盘设备驱动程序为应用程序提供设备独立键盘支持,windows系统还通过使用由当前用户或应用程序选中的语言特有的键盘配置.提供语言独立键盘支持。键盘设备驱动器从键盘接收的扫描码,被发送到键盘配置,在这里扫描码被翻译成消息并投递到应用程序中相应的窗口。
给键盘上的每一个键赋唯一的值称之为扫描码,它是一个键盘键的设备独立标识。在用户敲键时键盘产生两个扫描码——一个是在用户按下键.另一个是在用户释放键。
键盘设备驱动程序截取一个扫描码,并把它翻译(映射)成虚键码.它是由windows系统定义的用来标识键的设备独立值。翻译了一个扫描码之后,键盘创建一条含有扫描码、虚键码及有关击键的其它信息的消息,然后再把这条消息放到系统消息队列中。windows从系统消息队列中移走这条消息,再把它投递到相应的线程消息队列中去。下图说明的是windows系统的键盘输入模式。
windows系统把键盘消息投递到创建具有输入焦点的窗口的线程消息队列中,键盘焦点是窗口的一个临时局性。windows系统通过移动键盘焦点让显示在屏幕上的所有窗口共享键盘,根据用户的意图,可以把键盘焦点从一个窗口移到另一个窗口。在键盘焦点没有移到另一个窗口之前,有键盘焦点的窗口接收(从创建它的线程的消息队列中)所有键盘消息。
一个线程可调用函数GetFocus来确定它的窗口(如果有的话)当前是否有键盘焦点,线程也可以调用函数SetFocus来把键盘焦点赋给它的窗口之一。如果键盘焦点从—个窗口改变到另一个窗口,系统向将要失去焦点的窗口发送WM_KILLFOCUS消息,而把WM_SETFOCUS消息发送给将要得到焦点的窗口。
键盘焦点的概念是与活动窗口紧密相关的,活动窗口是用户当前正在使用的顶层窗口。有键盘焦点的窗口可以是活动窗口本身,或者是活动窗口的一个子窗口。所以用户可以很容易地识别活动窗口.系统把它放在Z次序的顶部.并高亮显示它的标题栏(如果有的话)以及边框。
用户可通过单击来激活一个窗口,也可以通过用ALT+TAB or ALT+ESC组合键来选择它,或者是从MIi现中选择它。一个线程可通过使用函数SetActiveWindow来激活一个顶层窗口,使用函数GetActiveWindow可以确定一个顶层窗口是否是活动的。
如果一个窗口被禁止,而另——个被激活.windows系统把WM_ACTIVATE消息先发送到将要被禁止的窗口,然后再发送到将要被激活的窗口,如果一个窗口将被禁止,那么wParam参数的低位字是0,非0则表明这个窗口将被激活。如果默认窗口过程接收到WM_ACTIVATE消息,它就把键盘焦点设到活动窗口。
按下一个键就会产生一条WM_KEYDOWN 和 WM_SYSKEYDOWN消息,并将被放到与有键盘输入的窗口相应的线程消息队列中,释放一个键则会产生一条WM_KEYUP 和 WM_SYSKEYUP消息,同样也会被放到队列中。
按键和释放键消息通常是成对出现的,但如果用户按住键到一定的时间就启动了键盘的自动重复持性,系统就会产生一系列的WM_KEYDOWN 和 WM_SYSKEYDOWN消息,在用户释放这个键时.才产生一条WM_KEYUP 和 WM_SYSKEYUP消息。
windows对系统击键和非系统击键有个划分,系统击键产生系统击键消息:WM_SYSKEYDOWN 和 WM_SYSKEYUP。非系统击键产生非系统消息:WM_KEYDOWN 和 WM_KEYUP。
如果窗口过程必须处理系统击键消息,那么就必须确保在处理了这条消息后,还得把它传给函数DefWindowProc。否则,所有的系统操作包括alt键将被禁止,即使在窗口有键盘焦点的情况下也一样,就是说,用户不能得到窗口菜单或系统菜单.或者用从ALT+ESC or ALT+TAB组合键来激活另一个窗口。
系统击键消息主要用于windows系统而不是应用程序,windows系统用它们来给菜单提供内部键盘接口,以便用户控制要激活哪一个窗口。系统击键消息是在用户使用一个从ALT组合键时,或者是用户击键,但没有窗口具有键盘焦点(例如,活动应用程序窗口被最小化时),在这种情况下,消息就被邮递到与活动窗口相应的消息队列中。
非系统击键消息是用1:应用程序窗口,函数DefWindowProc在这里则没有什么用,窗口过程丢弃任何它不感兴趣的非系统击键消息。
击键消息的wParam参数含有一个被按过或被释放键的虚键码,窗口过程是根据虚键码的值决定是处理还是忽略某条击键消息。
一个典型的窗口过程处理的击键消息只是它接收的击键消息的一个很小的子集,其余的则被忽略了。例如,某一个窗口过程可能只处理WM_KEYDOWN消息,还有那些含有虚键码的移动光标键消息,shift键(也称控制键).以及功能键。一个典型的窗口过程不处理字符键的击键消息,而是用再数TranslateMessage把消息转换成字符消息。
有关TranslateMessage及字符消息.参见 “字符消息”。
击键消息的lParam参数含有产生消息的击键的附加信息,这个信息包括重复计数、扫描码、扩展键标志、关联码、前一次键状态标志以及转换状态标志。下图显示了这些标志和数值在lParam参数中的位置。
应用程序使用下列值来操作击键标志
值 意思
KF_ALTDOWN 操作 ALT 键标志, 指示如果 ALT键按下。
KF_DLGMODE 操作 对话模式标志, 指示对话框是否活动的。
KF_EXTENDED 操作 扩展键标志。
KF_MENUMODE 操作菜单模式标志, 指示菜单是否活动的。.
KF_REPEAT 操作重复记数。
KF_UP 操作转换状态标志。
通过检查重复计数以确定某条击键消息是否是多次击键.在产生WM_KEYDOWN或WM_SYSKEYDOWN消息速度快于应用程序对它的处理时,系统就增加计数,这经常发生在用户按住键足够长的时间后,启动了键盘的自动重复功能。系统就把这些连续产生的击键消息合并成一条按键消息,只是增加重复计数,而不是把每—次的按键消息都放到系统消息队列中去。释放—个键不会启动自动重复功能,因此所有WM_KEYUP和WM_SYSKEYUP消息的重复计数总是1。
扫描码是用户按一个键时由键盘硬件产生的值,它是用来标识键被按过的一个设备相关值.而不是键所代表的字符。应用程序通常不管扫描码,而是用设备独立虚键码来翻译击键消息。
扩展键标志表明是否有来自增强键盘上附加键的击键消息.扩展键包括右边的ALT和CTRL键,数字键盘左边的一组键:INS、DEL、HOME、END、PAGE UP、PAGEDOWN和箭头键;还有数字键盘上的NUMLOCK键;BREAK(CTRL+PAUSE)键;PRINT SCRN键;除号键(/)和ENTER键。如果是一个扩展键,扩展键标志就被置位。
关联码标明在产生击键消息时是否按下从ALT键,如果按下ALT为1.否则为0。
前一次键状态标志指示某键在产生击键消息之前是否被按下.如果被按下则为1,否则为0。用这个标志来识别一个由键盘自动重复功能产生的消息,由自动重复功能产生的WM_KEYDOWN和WM_SYSKEYDOWN击键消息,这个标志是l,对于WM_KEYUP和WM_SYSKEYUP消息则总是0。
转换状态标志指明是按键还是释放键产生的击键消息,对WM_KEYDOWN和WM_SYSKEYDOWN消息这个标志总是0,对WM KEYUP和WM_SYSKEYUP消息则总是1。
击键消息提供了许多有关击键的信息,但并不提供字符击键的字符码.要检取字符码,应用程序必须在它的线程消息环中含有函数TranslateMessage。TranslateMessage把WM_KEYDOWN或 WM_SYSKEYDOWN消息传给键盘处理例程,由处理例程检查消息的虚键码.如果对应的是一个字符键,就提供相应的字符码(考虑SHIFT和CAPS LOCK的状态),再产生一条含有字符码的字符消息放在消息队列的开始。消息环的下一次循环从队列中移走这条字符消息,并把这条消息发送到相应的窗口过程。
窗口能够接收四种不同的字符消息,包括WM_CHAR, WM_DEADCHAR, WM_SYSCHAR, 和WM_SYSDEADCHAR消息,函数TranslateMessage在处理WM_KEYDOWN消息时产生WM_CHAR 或 WM_DEADCHAR消息。同样在它处理WM_SYSKEYDOWN消息时,产生WM_SYSCHAR 或 WM_SYSDEADCHAR消息。
处理键盘输入的应用程序一般只处理WM_CHAR消息.而把其它的消息都传给函数DefWindowProc Windows系统用WM_SYSCHAR 和 WM_SYSDEADCHAR实现菜单别名。
所有字符消息的wParam参数含有被按过的字符键的字符码,这个字符码的值取决于接收消息的窗口的窗口类。如果是用函数RegisterClass的 Unicode版本来注册窗口类.系统就给这种窗口类的所有窗口提供Unicode字符,否则就提供windows系统字符集中的AscII字符码。有关Unicode参见“字符处理和Unicode”。
字符消息的lParam参数的内容等同于被翻译过的以产生字符消息的按键消息的lParam参数。有关lParam参数的内容,参见 “击键消息标志’
有一些非英语键盘所含的字符键,不是用来产生它们字符本身,而是用于给下一个击键添加一个变调符号,这些键称之为固定键。德文键盘上的音调符号就是一个固定键的例子,如果要在o上面加—个变调符号,德文用户一般先敲音调符号键,再按o键,具有键盘焦点的窗口将会接收下列一组消息:
WM_KEYDOWN
WM_DEADCHAR
WM_KEYUP
WM_KEYDOWN
WM_CHAR
WM_KEYUP
TranslateMessage处理由一个固定键产生的WM_KEYDOWN消息时产生WM_DEADCHAR消息,尽管WM_DEADCHAR消息的wParam参数中含有固定键变调符号的字符码,应用程序通常会忽略这条消息,而处理下一个击键产生的WM_CHAR消息,WM_CHAR消息的wParam参数含有音调符号的字符码。如果下一个击锈产生的字符不能与音调符号组合,windows系统就会产生两条WM_CHAR及消息,第一条消息的wParam参数是音调符号的字符码,第二条消息的wParam参数是下一个字符键的字符码。
函数TranslateMessage处理一条发自系统固定键(一个与ALT组合的固定键)的WM_SYSKEYDOW消息时产生WM_SYSDEADCHAR消息,应用程序通常忽略WM_SYSDEADCHAR消息。
在处理键盘消息的同时,应用程序可能需要确定与产生当前消息的键相关的键的状态,例如,字处理应用程序允许用户按SHIFT+END键来高亮显示某一段正文,那么它就得在检取由END键产生击键消息时检查SHIFT键的状态。应用程序可以用函数GetKeyState在产生当前消息时确定一个虚键的状恋,也可用函数GetAsyncKeyState检取一个虚键的当前状态。
键盘处理例程管理一个名字列表,产生一个字符的键的名字和由键产生的字符相同。非字符键的名字如TAB和ENTE只是用一个字符串来存储的,应用程序可通过调用GetKeyNameText从设备驱动程序中检取任意一个键的名字。
windows系统含有几个特殊用途的函数用来转换扫描码、字符码以及由不同击键消息提供的虚键码,这些函数包括MapVirtualKey, ToAscii, ToUnicode, 和 VkKeyScan。
windows系统提供了一些应用程序可用来定义热键的函数,热键是产生WM_HOTKEY消息的组合键,这条消息绕过线程消息队列中所有其它的消息被放置在最上面。应用程序使用热镶从用户得到高优先级的输入。例如,把CTRL+C组合键定义成一个热键,应用程序可允许用户中断一个长时操作。
要定义一个热键,应用程序要调用函数RegisterHotKey,指定产生WM_HOTKEY消息的组合键、接收消息的窗口的句柄、热键标识。如果用户按一个热键,一条WM_HOTKEY消息就被放到创建指定窗口的线程消息队列中,消息的wParam参数是热键的标识。应用程序可以为一个线程定义多个热键,但线程中的每一个热键都必须有一个唯一的标识。
在应用程序结束之前,应该用函数UnregisterHotKey销毁热键。
应用程序可以很简单的选择一个热键做热键控制。热键控制通常使用在活动窗口定义的热键; 他们不需要使用函数RegisterHotKey 和 UnregisterHotKey. 相反, 应用程序通常使用热键控制通过发送 WM_SETHOTKEY 消息来设置热键. 无论用户什么时候按热键,系统发送一个 WM_SYSCOMMAND消息来指定 SC_HOTKEY. 更多关于热键控制, 参见热键控制。
语言,键盘布局
ActivateKeyboardLayout激活一个新的键盘布局。键盘布局定义了按键在一种物理性键盘上的位置与含义
LoadKeyboardLayout载入一个键盘布局
GetKeyboardLayoutList获得系统适用的所有键盘布局的一个列表
GetKeyboardLayoutName取得当前活动键盘布局的名称取得当前活动键盘布局的名称
GetKeyboardLayout取得一个句柄,描述指定应用程序的键盘布局
UnloadKeyboardLayout卸载指定的键盘布局
窗口是以击键消息和字符消息的形式接收留盘输入的.与窗口相应的消息环必须包含把击键消息转换成相应字符消息的代码,如果窗口在它的客户区中显示键盘输入,那么就应该创建和显示一个插入符来指示下一个字符的位置。下一节讲解用于接收、处理和显示键盘输入的代码。
具有键盘焦点的窗口的窗口过程在用户敲键盘时接收击键消息,击键消息包括WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, 和 WM_SYSKEYUP,一个典型的窗口过程忽略除了WM_KEYDOWN之外的所有消息。windows系统在用户按一个键时投递WM_KEYDOWN消息。
如果窗口接收到WM_KEYDOWN消息,就应该检查伴随消息的虚键码来确定如何处理击键,虚键码是在消息的wParam参数中。通常应用程序所处理的非字符键击键只包括功能键,移动光标键和特殊键如INS、DEL、HOME及END。
下面的范例是一个典型的应用程序用来接收相处理击键消息的窗口过程框架。
case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT:
/* Process the LEFT ARROW key. */
break;
case VK_RIGHT:
/* Process the RIGHT ARROW key. */
break;
case VK_UP:
/* Process the UP ARROW key. */
break;
case VK_DOWN:
/* Process the DOWN ARROW key. */
break;
case VK_HOME:
/* Process the HOME key. */
break;
case VK_END:
/* Process the END key. */
break;
case VK_INSERT:
/* Process the INS key. */
break;
case VK_DELETE:
/* Process the DEL key. */
break;
case VK_F2:
/* Process the F2 key. */
break;
/* Process other noncharacter keystrokes. */
default:
break;
}
从用户接收字符输入的任何线程,在它的消息环中必须有函数TranslateMessage,这个函数用来检查击键消息的虚键码,如果虚键码对应于—个字符,就把字符消息放到消息队列中去,这条字符消息就会在消息环的下一个循环时被移走并被发送.消息的wParam参数包含的是字符码。
总的来说,线程消息环应该使用函数TranslateMessage来转换每一条消息,不只是虚键消息。尽管TranslateMessage对其它类型的消息没有什么影响,但这就保证键盘输入被正确转换。下面的例子说明如何在一个典型的线程消息环中包含函数TranslateMessage。
while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
if (TranslateAccelerator(hwndMain, haccl, &msg) == 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
窗口过程在函数TranslateMessage把虚键码转换成相应的字符码时接收字符消息,这些字符消息是WM_CHAR, WM_DEADCHAR, WM_SYSCHAR, 和 WM_SYSDEADCHAR。一个典型的窗口过程忽略除了WM_CHAR之外的所有字符消息。函数TranslateMessage在用户按下列键时产生一条WM_CHAR消息:
字符键
BACKSPACE
ENTER(回车)
ESC
SHIFT十ENTER(升行)
TAB
如果窗口过程接收到WM_CHAR及消息确定如何处理这个字符。 它应检查消息参数wParam中的字符码来
下面的范例是一个典型的应用程序用来接收相处冲字符消息的窗口过程框架。
case WM_CHAR:
switch (wParam) {
case 0x08:
/* Process a backspace. */
break;
case 0x0A:
/* Process a linefeed. */
break;
case 0x1B:
/* Process an escape. */
break;
case 0x09:
/* Process a tab. */
break;
case 0x0D:
/* Process a carriage return. */
break;
default:
/* Process displayable characters. */
break;
}
接收键盘输入的窗口通常要显示用户在窗口客户区中敲入的字符,窗口应该用插入符来指示下一个字符的位置。窗口还应该在它接收键盘焦点时创建和显示插入符,在失去焦点时隐藏和销毁插入符。窗口可通过处理WM_SETFOCUS 和 WM_KILLFOCUS消息来完成这些操作。有关插入符.参见 “插入符”。
这一节中的例子说明应用程序怎样才能接收键盘字符输入,在窗口客户区中显示它们,以及每一次对插入符位置的更新。还演示了如何移动插入符以响应LEFT ARROW, RIGHT ARROW, HOME 和 END击键,以及怎样高亮选中的正文以响应SHIFT+RIGHT ARROW组合键。
在处理WM_CREATE消息的过程中,范例中的窗口过程分配了64K的缓存区用于存储键盘输入,还检取了当前安装的字体的尺寸,保存字体中字符的高度及平均宽度,高度和宽度将用在处理WM_SIZE消息时结合客户区大小来计算行长及最大行数。
窗口过程在处理WM_SETFOCUS消息时创建和显示插入符,在处理WM_KILLFOCUS消息时隐藏和删除插入符。
在处理WM_CHAR消息时,应用程序显示字符,把它们存进缓存区,并更新插入符的位置。窗口过程也能把制表符转换成四个连续的空格。回车、升行及转义字符只发出一个响声.而不需要再对它们进行处理。
窗口过程在处理WM_KEYDOWN消息时完成插入符向左、向右、结束和开始位置的移动,在处理RIGHT ARROW键的活动时,窗口过程检查SHIFT键的状态,如果被按下了,在插入符被移动过程中高亮显示插入符右边的字符。
注意下面的这段代码既可以按Unicode编译,也可按ANSI来编译,如果源代码定义Unicode.那么字符串就按Unicode来处理,否则按州ANSI 字符处理。
#define BUFSIZE 65535
#define SHIFTED 0x8000
LONG APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)
HWND hwndMain;
UINT uMsg;
UINT wParam;
LONG lParam;
{
HDC hdc; /* handle of device context */
TEXTMETRIC tm; /* structure for text metrics */
static DWORD dwCharX; /* average width of characters */
static DWORD dwCharY; /* height of characters */
static DWORD dwClientX; /* width of client area */
static DWORD dwClientY; /* height of client area */
static DWORD dwLineLen; /* line length */
static DWORD dwLines; /* text lines in client area */
static int nCaretPosX = 0; /* horizontal position of caret */
static int nCaretPosY = 0; /* vertical position of caret */
static int nCharWidth = 0; /* width of a character */
static int cch = 0; /* characters in buffer */
static int nCurChar = 0; /* index of current character */
static PTCHAR pchInputBuf; /* address of input buffer */
int i, j; /* loop counters */
int cCR = 0; /* count of carriage returns */
int nCRIndex = 0; /* index of last carriage return */
int nVirtKey; /* virtual-key code */
TCHAR szBuf[128]; /* temporary buffer */
TCHAR ch; /* current character */
PAINTSTRUCT ps; /* required by BeginPaint */
RECT rc; /* output rectangle for DrawText */
SIZE sz; /* string dimensions */
COLORREF crPrevText; /* previous text color */
COLORREF crPrevBk; /* previous background color */
switch (uMsg) {
case WM_CREATE:
/* Get the metrics of the current font. */
hdc = GetDC(hwndMain);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndMain, hdc);
/* Save the average character width and height. */
dwCharX = tm.tmAveCharWidth;
dwCharY = tm.tmHeight;
/* Allocate a buffer to store keyboard input. */
pchInputBuf = (LPTSTR) GlobalAlloc(GPTR, BUFSIZE * sizeof(TCHAR));
return 0;
case WM_SIZE:
/* Save the new width and height of the client area. */
dwClientX = LOWORD(lParam);
dwClientY = HIWORD(lParam);
/* Calculate the maximum width of a line and the maximum number of lines in the client area. */
dwLineLen = dwClientX - dwCharX;
dwLines = dwClientY / dwCharY;
break;
case WM_SETFOCUS:
/* Create, position, and display the caret when the window receives the keyboard focus. */
CreateCaret(hwndMain, (HBITMAP) 1, 0, dwCharY);
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
ShowCaret(hwndMain);
break;
case WM_KILLFOCUS:
/* Hide and destroy the caret when the window loses the keyboard focus. */
HideCaret(hwndMain);
DestroyCaret();
break;
case WM_CHAR:
switch (wParam) {
case 0x08: /* backspace */
case 0x0A: /* linefeed */
case 0x1B: /* escape */
MessageBeep(0xFFFFFFFF);
return 0;
case 0x09: /* tab */
/* Convert tabs to four consecutive spaces. */
for (i = 0; i < 4; i++)
SendMessage(hwndMain, WM_CHAR, 0x20, 0);
return 0;
case 0x0D: /* carriage return */
/* Record the carriage return and position the caret at the beginning of the new line. */
pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCaretPosY += 1;
break;
default: /* displayable character */
ch = (TCHAR) wParam;
HideCaret(hwndMain);
/* Retrieve the character's width and output the character.*/
hdc = GetDC(hwndMain);
GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam, &nCharWidth);
TextOut(hdc, nCaretPosX, nCaretPosY * dwCharY, &ch, 1);
ReleaseDC(hwndMain, hdc);
/* Store the character in the buffer. */
pchInputBuf[cch++] = ch;
/* Calculate the new horizontal position of the caret. If the position exceeds the maximum,
* insert a carriage return and move the caret to the beginning of the next line. */
nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwLineLen) {
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCaretPosY;
}
nCurChar = cch;
ShowCaret(hwndMain);
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT: /* LEFT ARROW */
/* The caret can move only to the beginning of the current line. */
if (nCaretPosX > 0) {
HideCaret(hwndMain);
/* Retrieve the character to the left of the caret, calculate the character's
* width, then subtract the width from the current horizontal position of the caret
* to obtain the new position. */
ch = pchInputBuf[--nCurChar];
hdc = GetDC(hwndMain);
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = max(nCaretPosX - nCharWidth, 0);
ShowCaret(hwndMain);
}
break;
case VK_RIGHT: /* RIGHT ARROW */
/* Caret moves to the right or, when a carriage return is encountered, to the beginning of the next line. */
if (nCurChar < cch) {
HideCaret(hwndMain);
/* Retrieve the character to the right of the caret. If it's a carriage return,
* position the caret at the beginning of the next line.*/
ch = pchInputBuf[nCurChar];
if (ch == 0x0D) {
nCaretPosX = 0;
nCaretPosY++;
}
/* If the character isn't a carriage return, check to see whether the SHIFT
* key is down. If it is, invert the text colors and output the character. */
else {
hdc = GetDC(hwndMain);
nVirtKey = GetKeyState(VK_SHIFT);
if (nVirtKey & SHIFTED) {
crPrevText = SetTextColor(hdc,
RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc,
RGB(0,0,0));
TextOut(hdc, nCaretPosX,
nCaretPosY * dwCharY,
&ch, 1);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
}
/* Get the width of the character and calculate the new horizontal * position of the caret. */
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = nCaretPosX + nCharWidth;
}
nCurChar++;
ShowCaret(hwndMain);
break;
}
break;
case VK_UP: /* UP ARROW */
case VK_DOWN: /* DOWN ARROW */
MessageBeep(0xFFFFFFFF);
return 0;
case VK_HOME: /* HOME */
/* Set the caret's position to the upper left corner of the client area. */
nCaretPosX = nCaretPosY = 0;
nCurChar = 0;
break;
case VK_END: /* END */
/* Move the caret to the end of the text. */
for (i=0; i < cch; i++) {
/* Count the carriage returns and save the index of the last one. */
if (pchInputBuf[i] == 0x0D) {
cCR++;
nCRIndex = i + 1;
}
}
nCaretPosY = cCR;
/* Copy all text between the last carriage return and the end of the keyboard input buffer to a temporary buffer. */
for (i = nCRIndex, j = 0; i < cch; i++, j++)
szBuf[j] = pchInputBuf[i];
szBuf[j] = TEXT('/0');
/* Retrieve the text extent and use it to set the horizontal position of the caret. */
hdc = GetDC(hwndMain);
GetTextExtentPoint32(hdc, szBuf, lstrlen(szBuf), &sz);
nCaretPosX = sz.cx;
ReleaseDC(hwndMain, hdc);
nCurChar = cch;
break;
default:
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_PAINT:
if (cch == 0) /* nothing in input buffer */
break;
hdc = BeginPaint(hwndMain, &ps);
HideCaret(hwndMain);
/* Set the clipping rectangle, and then draw the text into it. */
SetRect(&rc, 0, 0, dwLineLen, dwClientY);
DrawText(hdc, pchInputBuf, -1, &rc, DT_LEFT);
ShowCaret(hwndMain);
EndPaint(hwndMain, &ps);
break;
. /* Process other messages. */
. case WM_DESTROY:
PostQuitMessage(0);
/* Free the input buffer. */
GlobalFree((HGLOBAL) pchInputBuf);
UnregisterHotKey(hwndMain, 0xAAAA);
break;
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}
ActivateKeyboardLayout
EnableWindow
GetActiveWindow
GetAsyncKeyState
GetFocus
GetKeyboardLayout
GetKeyboardLayoutList
GetKeyboardLayoutName
GetKeyboardState
GetKeyNameText
GetKeyState
IsWindowEnabled
keybd_event
LoadKeyboardLayout
MapVirtualKey
MapVirtualKeyEx
OemKeyScan
RegisterHotKey
SetActiveWindow
SetFocus
SetKeyboardState
ToAscii
ToAsciiEx
WM_ACTIVATE
WM_CHAR
ToUnicode
UnloadKeyboardLayout
UnregisterHotKey
VkKeyScan
VkKeyScanEx
Obsolete Functions
GetKBCodePage
WM_DEADCHAR
WM_GETHOTKEY
WM_HOTKEY
WM_KEYDOWN
WM_KEYUP
WM_KILLFOCUS
WM_SETFOCUS
WM_SETHOTKEY
WM_SYSCHAR
WM_SYSDEADCHAR
WM_SYSKEYDOWN
WM_SYSKEYUP