控制台程序接收键盘消息

来源:互联网 发布:dpp软件怎么用 编辑:程序博客网 时间:2024/05/16 04:46
DOS程序通过一个名为Winoldap的控制台程序来运行,而这个程序则是在32位Windows控制台窗口中运行。原理上,Winoldap利用x86的"Virtual86"模式来虚拟实模式。
创建控制台时,操作系统自动创建三个"标准"文件句柄。在高级控制台编程中,用两个API函数控制这些句柄

GetStdHandle和SetStdHandle

控制台使用的不是我们常见的Win32消息队列,而是事件队列。
事件队列和Windows消息队列差不多,不过是接收输入事件,而非消息。所以Spy++当然得不到消息

ReadConsoleInput可以用来获得控制台的输入,参考

MSDN给出了一个创建标准信息队列的例子

C/C++ code
#include <windows.h>#include <stdio.h>VOID ErrorExit(LPSTR);VOID KeyEventProc(KEY_EVENT_RECORD); VOID MouseEventProc(MOUSE_EVENT_RECORD); VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD); int main(VOID) { HANDLE hStdin; DWORD cNumRead, fdwMode, fdwSaveOldMode, i; INPUT_RECORD irInBuf[128]; int counter=0; // Get the standard input handle. hStdin = GetStdHandle(STD_INPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE) ErrorExit("GetStdHandle"); // Save the current input mode, to be restored on exit. if (! GetConsoleMode(hStdin, &fdwSaveOldMode) ) ErrorExit("GetConsoleMode"); // Enable the window and mouse input events. fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT; if (! SetConsoleMode(hStdin, fdwMode) ) ErrorExit("SetConsoleMode"); // Loop to read and handle the input events. while (counter++ <= 100) { // Wait for the events. if (! ReadConsoleInput( hStdin, // input buffer handle irInBuf, // buffer to read into 128, // size of read buffer &cNumRead) ) // number of records read ErrorExit("ReadConsoleInput"); // Dispatch the events to the appropriate handler. for (i = 0; i < cNumRead; i++) { switch(irInBuf[i].EventType) { case KEY_EVENT: // keyboard input KeyEventProc(irInBuf[i].Event.KeyEvent); break; case MOUSE_EVENT: // mouse input MouseEventProc(irInBuf[i].Event.MouseEvent); break; case WINDOW_BUFFER_SIZE_EVENT: // scrn buf. resizing ResizeEventProc( irInBuf[i].Event.WindowBufferSizeEvent); break; case FOCUS_EVENT: // disregard focus events case MENU_EVENT: // disregard menu events break; default: ErrorExit("Unknown event type"); break; } } } return 0; }VOID ErrorExit (LPSTR lpszMessage) { fprintf(stderr, "%s\n", lpszMessage); ExitProcess(0); }VOID KeyEventProc(KEY_EVENT_RECORD ker){ printf("Key event: "); if(ker.bKeyDown) printf("key pressed\n"); else printf("key released\n");}VOID MouseEventProc(MOUSE_EVENT_RECORD mer){#ifndef MOUSE_HWHEELED#define MOUSE_HWHEELED 0x0008#endif printf("Mouse event: "); switch(mer.dwEventFlags) { case 0: printf("button press\n"); break; case DOUBLE_CLICK: printf("double click\n"); break; case MOUSE_HWHEELED: printf("horizontal mouse wheel\n"); break; case MOUSE_MOVED: printf("mouse moved\n"); break; case MOUSE_WHEELED: printf("vertical mouse wheel\n"); break; default: printf("unknown\n"); break; }}VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD wbsr){ printf("Resize event\n");}

我就花点事件给你解释下
WINDOW_BUFFER_SIZE_EVENT 屏幕大小改变时发出 
MENU_EVENT 用户使用控制台菜单或工具栏时发出 
FOCUS_EVENT 控制台得到输入焦点时发出


这是内部实现,当然我们外部也可以获得。利用管道,然后GetStdHandle(STD_INPUT_HANDLE);

然后即可读取Console窗口的事件。

好久没见到这么值得我回,详细解释的帖子。希望对后面看帖的朋友有帮助


用钩子实现

C/C++ code
#include <stdio.h>#include <windows.h>HHOOK g_ms_hook = 0;HHOOK g_kb_hook = 0;LRESULT CALLBACK kb_proc (int code, WPARAM w, LPARAM l){ printf((w==WM_KEYDOWN)?"按下%c\n":"抬起%c\n",((PKBDLLHOOKSTRUCT)l)->vkCode); return CallNextHookEx (g_kb_hook, code, w, l);}LRESULT CALLBACK ms_proc (int code, WPARAM w, LPARAM l){ if(w == WM_LBUTTONDOWN) printf("按下左键\n"); else if(w == WM_LBUTTONUP) printf("抬起左键\n"); else printf("x:%d\ty:%d\n",((PMSLLHOOKSTRUCT)l)->pt.x,((PMSLLHOOKSTRUCT)l)->pt.y); return CallNextHookEx (g_ms_hook, code, w, l);}int main (void){ g_kb_hook = SetWindowsHookEx (WH_KEYBOARD_LL,kb_proc,GetModuleHandle (NULL),0); g_ms_hook = SetWindowsHookEx (WH_MOUSE_LL, ms_proc,GetModuleHandle(NULL),0); if (g_kb_hook == NULL || g_ms_hook == NULL) { printf("安装钩子出错\n"); return 0; }; MSG msg; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); }; UnhookWindowsHookEx (g_kb_hook); return 0;};
注意:用钩子的时候可能出现PKBDLLHOOKSTRUCT未定义问题,在头文件windows.g前加入如下则可以
//该定义用于启动钩子的结构体
#define _WIN32_WINNT 0x0400


原创粉丝点击