C++之竹

无论是太阳下,还是风雨中,都要成长!

常用链接

统计

最新评论

Windows 控制台程序的事件捕获

      此篇内容属C++控制台编程的一点基础应用,所以嘛,偶就偷个懒,不再做文字的讲解,直接代码。

      哦,对了!代码之前,先就代码的组成作个简单说明。代码的内容共分为三块:

    1. 以宏RUN_ATEXIT_SAMPLE标识的atexit调用样例
    2. 以宏RUN_SETCONSOLECTRLHANDLER_SAMPLE标识的SetConsoleCtrlHandler调用样例
    3. 以宏RUN_READCONSOLEINPUT_SAMPLE标识的ReadConsoleInput调用样例

      其中,第3段样例代码来自于MSDN:http://msdn.microsoft.com/en-us/library/ms685035(v=VS.85).aspx

      OK,开始代码!!

#include <windows.h>
#include 
<iostream>
#include 
<string>

using namespace std;

#define RUN_ATEXIT_SAMPLE
#define RUN_SETCONSOLECTRLHANDLER_SAMPLE
#define RUN_READCONSOLEINPUT_SAMPLE

#define SECOND(n) (n * 1000)

// ATEXIT_SAMPLE
void Run_atexit_Sample(void);

// SETCONSOLECTRLHANDLER_SAMPLE
BOOL WINAPI ConsoleHandler(__in DWORD dwCtrlType);

// READCONSOLEINPUT_SAMPLE
HANDLE hStdin; 
DWORD fdwSaveOldMode;
VOID ErrorExit(LPSTR);
VOID KeyEventProc(KEY_EVENT_RECORD); 
VOID MouseEventProc(MOUSE_EVENT_RECORD); 
VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD); 
VOID Run_ReadConsoleInput_Sample(VOID);


int main(void)
{
#ifdef RUN_ATEXIT_SAMPLE
    Run_atexit_Sample();
#endif

#ifdef RUN_SETCONSOLECTRLHANDLER_SAMPLE
    cout 
<< "[RUN_SETCONSOLECTRLHANDLER_SAMPLE] START" << endl;
    cout 
<< "\t (Note: You just have 15sec to do the operations.)" << endl;
    
// 【SetConsoleCtrlHandler(HandlerRoutine, Add)】:
    
// Add == TRUE: 处理HandlerRoutine 被添加
    
//    如果 HandlerRoutine == NULL,则忽略对 CTRL+C 输入处理
    
// Add == FALSE: 处理HandlerRoutine 被移除
    
//    如果 HandlerRoutine == NULL,则恢复对 CTRL+C 输入的处理
    
// 对 CTRL+C 输入处理的忽略与恢复,将被子进程所继承
    if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE) == FALSE) {
        DWORD dwErr 
= GetLastError();
        cout 
<< "[RUN_SETCONSOLECTRLHANDLER_SAMPLE] Failed to SetConsoleCtrlHandler! Err: " << dwErr << endl;
        
return (int)dwErr;
    }


    Sleep(SECOND(
15));
    cout 
<< "[RUN_SETCONSOLECTRLHANDLER_SAMPLE] END" << endl;
#endif

#ifdef RUN_READCONSOLEINPUT_SAMPLE
    cout 
<< "[RUN_READCONSOLEINPUT_SAMPLE] Enter Run_ReadConsoleInput_Sample()" << endl;
    Run_ReadConsoleInput_Sample();
    cout 
<< "[RUN_READCONSOLEINPUT_SAMPLE] Leave Run_ReadConsoleInput_Sample()" << endl;
#endif

    system(
"pause");
    
return 0;
}


//////////////////////////////////////////////////////////////////////////

void ExitProc_1(void
{
    cout 
<< "[RUN_ATEXIT_SAMPLE] This is ExitProc_1" << endl;
}


void ExitProc_2(void
{
    cout 
<< "[RUN_ATEXIT_SAMPLE] This is ExitProc_2" << endl;
}


// 【注意】:
// 1. atexit() 成功时返回 0
// 2. atexit() 的参数类型为 void (__cdecl *func )( void )
// 3. atexit() 是将所传入的回调函数放入栈中,故回调函数的执行顺序与atexit的顺序相反
// 4. atexit() 只有当应用程序正常结束时,回调函数才能执行
// 5. atexit() 回调函数不能依赖于任何DLL,因为在回调函数执行时DLL可能已经被卸载
// 6. 类似函数:
//    _onexit(_onexit_t)  ==>  int (__clrcall * _onexit_t)(void) 
//    _onexit_m(_onexit_t_m) ==> int (__clrcall * _onexit_m_t)(void) 
//    其中,_onexit是微软的扩展;ANSI程序则应使用atexit;对于混合模式,则可使用_onexit_m版本
void Run_atexit_Sample(void)
{
    cout 
<< "[RUN_ATEXIT_SAMPLE] Enter Run_atexit_Sample()" << endl;
    cout 
<< "[RUN_ATEXIT_SAMPLE] Call atexit() first by ExitProc_1, then by ExitProc_2" << endl;
    atexit(ExitProc_1);
    atexit(ExitProc_2);

    cout 
<< "[RUN_ATEXIT_SAMPLE] Leave Run_atexit_Sample()" << endl;
}


//////////////////////////////////////////////////////////////////////////

// 如果事件得到了处理,则返回 TRUE
// 如果还需要将事件传递给下一个事件处理函数,则返回 FALSE
BOOL WINAPI ConsoleHandler( __in DWORD dwCtrlType )
{
    
switch (dwCtrlType) {
    
case CTRL_C_EVENT: // CTRL + C
        
// 亦可通过GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)触发
        cout << "\n[RUN_SETCONSOLECTRLHANDLER_SAMPLE] CTRL_C_EVENT" << endl;
        
break;
    
case CTRL_BREAK_EVENT: // CTRL + BREAK
        
// 亦可通过GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)触发
        cout << "\n[RUN_SETCONSOLECTRLHANDLER_SAMPLE] CTRL_BREAK_EVENT" << endl;
        
break;
    
case CTRL_CLOSE_EVENT: // 关闭控制台程序
        cout << "\n[RUN_SETCONSOLECTRLHANDLER_SAMPLE] CTRL_CLOSE_EVENT" << endl;
        
break;
    
case CTRL_LOGOFF_EVENT: // 用户注销(退出登录)
        cout << "\n[RUN_SETCONSOLECTRLHANDLER_SAMPLE] CTRL_LOGOFF_EVENT" << endl;
        
break;
    
case CTRL_SHUTDOWN_EVENT: // 关机
        cout << "\n[RUN_SETCONSOLECTRLHANDLER_SAMPLE] CTRL_SHUTDOWN_EVENT" << endl;
        
break;
    
default:
        cout 
<< "\n[RUN_SETCONSOLECTRLHANDLER_SAMPLE] Unknown console ctrl event: " << dwCtrlType << endl;
        
break;
    }


    
return TRUE;
}


//////////////////////////////////////////////////////////////////////////

VOID ErrorExit (LPSTR lpszMessage) 

    fprintf(stderr, 
"%s\n", lpszMessage); 

    
// Restore input mode on exit.

    SetConsoleMode(hStdin, fdwSaveOldMode);

    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:

        
if(mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
        
{
            printf(
"left button press \n");
        }

        
else if(mer.dwButtonState == RIGHTMOST_BUTTON_PRESSED)
        
{
            printf(
"right button press \n");
        }

        
else
        
{
            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");
    printf(
"Console screen buffer is %d columns by %d rows.\n", wbsr.dwSize.X, wbsr.dwSize.Y);
}


VOID Run_ReadConsoleInput_Sample( VOID )
{    
    DWORD cNumRead, fdwMode, 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 next 100 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
            }
 
        }

    }
 

    
// Restore input mode on exit.

    SetConsoleMode(hStdin, fdwSaveOldMode);
}

最后,本人还是博客新人,有什么好的意见或建议,还望各位能大力提点!!

 

posted on 2012-04-23 00:07 青碧竹 阅读(967) 评论(0)  编辑 收藏 引用 所属分类: C++基础


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理