c - Win32 - 如何拦截和处理键盘输入?

标签 c winapi input

我正在尝试创建一个可用于包装控制台软件的简单程序。我有一个带有 EDIT 组件的基本窗口。我知道我可以使用 WM_KEYUP和其他人拦截键盘输入。我似乎找不到一种有效的方法来转换 CALLBACK WinProc 的任何参数;于是我将能够完成我程序的这一部分:

#include <windows.h>

#define IDC_MAIN_EDIT   101
#define WIDTH 800
#define HEIGHT 600

LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd) {
    WNDCLASSEX wClass;
    ZeroMemory(&wClass,sizeof(WNDCLASSEX));
    wClass.cbSize=sizeof(WNDCLASSEX);
    wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wClass.hIcon=NULL;
    wClass.hIconSm=NULL;
    wClass.hInstance=hInst;
    wClass.lpfnWndProc=(WNDPROC)WinProc;
    wClass.lpszClassName="Window Class";
    wClass.lpszMenuName=NULL;
    wClass.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClassEx(&wClass)) {
        int nResult=GetLastError();
        MessageBox(NULL,
            "Window class creation failed",
            "Window Class Failed",
            MB_ICONERROR);
    }
    HWND hWnd=CreateWindowEx(0,
            "Window Class",
            "Windows application",
            WS_OVERLAPPEDWINDOW,
            200,
            200,
            640,
            480,
            NULL,
            NULL,
            hInst,
            NULL);

    if(!hWnd) {
        int nResult=GetLastError();

        MessageBox(NULL,
            "Window creation failed",
            "Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(hWnd,nShowCmd);

    MSG msg;
    ZeroMemory(&msg,sizeof(MSG));

    while(GetMessage(&msg,NULL,0,0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {
    static HWND hEdit;
    switch(msg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
            break;
        case WM_CREATE:
            hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
                "EDIT",
                "",
                WS_CHILD|WS_VISIBLE|ES_MULTILINE|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE,
                0,
                0,
                WIDTH,
                HEIGHT,
                hWnd,
                (HMENU)IDC_MAIN_EDIT,
                GetModuleHandle(NULL),
                NULL);
            HFONT hFont = CreateFont(0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("Courier New"));
            SendMessage(hEdit, WM_SETFONT, (WPARAM)hFont, 0);
            SendMessage(hEdit,
                WM_SETTEXT,
                0,
                (LPARAM)"Insert text here...");
                break;
        case WM_SIZE:
            MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            break;
    }
    return DefWindowProc(hWnd,msg,wParam,lParam);
}

我应该说的是:我似乎找不到将键盘输入拦截为字符的方法。我怎样才能拦截所有正常的键盘输入?

最佳答案

回答你的问题:

What I should have said is: I can't seem to discover a way to intercept keyboard input as chars. How can I intercept all normal keyboard input?

看一下 Microsoft 的这个示例,了解如何处理 WM_CHAR 消息以获取键盘字符输入:

使用键盘输入

https://msdn.microsoft.com/en-us/library/windows/desktop/ms646268(v=vs.85).aspx

#define BUFSIZE 65535 
#define SHIFTED 0x8000 

LONG APIENTRY MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    HDC hdc;                   // handle to 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; // 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
    size_t * pcch;
    HRESULT hResult; 

    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:
        // check if current location is close enough to the
        // end of the buffer that a buffer overflow may
        // occur. If so, add null and display contents. 
    if (cch > BUFSIZE-5)
    {
        pchInputBuf[cch] = 0x00;
        SendMessage(hwndMain, WM_PAINT, 0, 0);
    } 
            switch (wParam) 
            { 
                case 0x08:  // backspace 
                case 0x0A:  // linefeed 
                case 0x1B:  // escape 
                    MessageBeep((UINT) -1); 
                    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((UINT) -1); 
                    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);
                    hResult = StringCchLength(szBuf, 128, pcch);
                    if (FAILED(hResult))
                    {
                    // TODO: write error handler
                    } 
                    GetTextExtentPoint32(hdc, szBuf, *pcch, 
                        &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; 
} 

关于c - Win32 - 如何拦截和处理键盘输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35877632/

相关文章:

c - 将数组引用到指针

c - 链表数组中的段错误

java - java创建的文件的UAC和文件虚拟化

c++ - 使用抽象类 boost 二进制序列化问题

input - ffmpeg 图像序列指定输入帧率

c - 在 C 编程中求解方程并从两个方程中找到 x 和 y 的值

c - 如何在进行系统调用时阻止控制台窗口出现?

winapi - 有没有办法在 Windows 上以编程方式查找芯片组的北桥、南桥名称和其他硬件信息?

c++ - 任务计划程序 : How to schedule a task to execute at login

Python 3 : How to ignore line breaks when using input()