控制台程序接收键盘消息

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


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值