You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用WM_INPUT时程序运行缓慢甚至无响应?

问题:WM_INPUT消息导致程序卡顿崩溃

在Windows平台开发简易虚拟窗口管理器时,使用WM_KEY*/WM_SYSKEY*系列消息时程序运行流畅、响应迅速,但改用WM_INPUT消息后,大量键盘操作会导致程序严重卡顿,最终出现“未响应”提示并终止。代码采用C风格编写,使用g++编译,可视为C语言代码。

代码实现

#ifdef __MINGW32__
#   define _WIN32_WINNT 0x0501
#endif // __MINGW32__

#include <windows.h>
#include <stdint.h>
#include <stdio.h>

typedef struct{
    bool keys[256];
} KEYBOARD;

typedef struct{
    bool keys[5];
    int16_t deltaWheel;
    int deltaX;
    int deltaY;
} MOUSE;

KEYBOARD Keyboard;
MOUSE Mouse;

const int ScreenHeight = 1080;
const int ScreenWidth = 1920;
uint32_t* ScreenBitmap;
BITMAPINFO BitmapInfo = {};

bool Running;

void SetPixel(int x, int y, uint32_t color){
    if(x >= 0 & y >= 0 & x < ScreenWidth & y < ScreenHeight){
        ScreenBitmap[y * ScreenWidth + x] = color;
    }
}

uint32_t GetPixel(int x, int y){
    if(x >= 0 & y >= 0 & x < ScreenWidth & y < ScreenHeight){
        return ScreenBitmap[y * ScreenWidth + x];
    } else return 0;
}

void DrawRectangle(int X1, int Y1, int X2, int Y2, uint32_t color){
    int maxX = X2 >= ScreenWidth ? ScreenWidth - 1 : X2;
    int maxY = Y2 >= ScreenHeight ? ScreenHeight - 1: Y2;
    int minX = X1 < 0 ? 0 : X1;
    int minY = X2 < 0 ? 0 : Y1;

    for(int x = minX; x <= maxX; x++){
        for(int y = minY; y <= maxY; y++){
            SetPixel(x, y, color);
        }
    }
}

void UpdateScreenBitmap(){
    DrawRectangle(0, 0, ScreenWidth, ScreenHeight, 0x00000000);
}

LRESULT CALLBACK WindowProcedure(HWND WindowHandle, uint32_t Message, WPARAM WParam, LPARAM LParam){
    switch(Message){

        case WM_CREATE:{
            ScreenBitmap = (uint32_t*) VirtualAlloc(0, ScreenHeight * ScreenWidth * 4, MEM_COMMIT, PAGE_READWRITE);
            BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFO);
            BitmapInfo.bmiHeader.biWidth = ScreenWidth;
            BitmapInfo.bmiHeader.biHeight = -ScreenHeight;
            BitmapInfo.bmiHeader.biPlanes = 1;
            BitmapInfo.bmiHeader.biBitCount = 32;
            BitmapInfo.bmiHeader.biCompression = BI_RGB;
        } break;

        case WM_NCDESTROY:{
            Running = false;
        } break;

        case WM_PAINT:{
            InvalidateRect(WindowHandle, 0, 0);
            SetDIBitsToDevice(GetDC(WindowHandle), 0, 0, ScreenWidth, ScreenHeight, 0, 0, 0, ScreenHeight, ScreenBitmap, &BitmapInfo, DIB_RGB_COLORS);
            ValidateRect(WindowHandle, 0);
        } break;

        case WM_INPUT:{
            uint32_t RawInputSize = sizeof(RAWINPUT);
            RAWINPUT RawInput = {};
            GetRawInputData((HRAWINPUT)LParam, RID_INPUT, &RawInput, &RawInputSize, sizeof(RAWINPUTHEADER));
            if(RawInput.header.dwType == RIM_TYPEKEYBOARD){
                RAWKEYBOARD kb = RawInput.data.keyboard;
                Keyboard.keys[kb.MakeCode] = kb.Flags == 0 ? true : false;
            } else if(RawInput.header.dwType == RIM_TYPEMOUSE){
                for(int i = 0; i < 5; i++){
                    if(RawInput.data.mouse.usButtonFlags == (0b01 << 2*i)) Mouse.keys[i] = true;
                    if(RawInput.data.mouse.usButtonFlags == (0b10 << 2*i)) Mouse.keys[i] = false;
                }
                Mouse.deltaWheel = RawInput.data.mouse.usButtonData;
                Mouse.deltaX = RawInput.data.mouse.lLastX;
                Mouse.deltaY = RawInput.data.mouse.lLastY;
            }
        } break;
    }
    return DefWindowProc(WindowHandle, Message, WParam, LParam);
}

//int WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR ComandLine, int ShowComand){
int main(){

    if(true){
        AllocConsole();
        freopen("conin$", "r", stdin);
        freopen("conout$", "w", stdout);
        freopen("conout$", "w", stderr);
    }

    WNDCLASS WindowClass = {};
    WindowClass.lpfnWndProc = WindowProcedure;
    WindowClass.lpszClassName = "Window Class Name";
    WindowClass.hInstance = (HINSTANCE) GetModuleHandle(0);
    RegisterClass(&WindowClass);

    HWND WindowHandle = CreateWindow(WindowClass.lpszClassName, 0, WS_POPUP, 0, 0, ScreenWidth, ScreenHeight, 0, 0, WindowClass.hInstance, 0);

    RAWINPUTDEVICE RawInputDevice[2];

    RawInputDevice[0].usUsagePage = 0x01;
    RawInputDevice[0].usUsage = 0x02;
    RawInputDevice[0].dwFlags = RIDEV_NOLEGACY;
    RawInputDevice[0].hwndTarget = WindowHandle;

    RawInputDevice[1].usUsagePage = 0x01;
    RawInputDevice[1].usUsage = 0x06;
    RawInputDevice[1].dwFlags = RIDEV_NOLEGACY;
    RawInputDevice[1].hwndTarget = WindowHandle;

    RegisterRawInputDevices(RawInputDevice, 2, sizeof(RAWINPUTDEVICE));

    ShowWindow(WindowHandle, 1);
    SetWindowPos(WindowHandle, HWND_TOP, 0, 0, ScreenWidth, ScreenHeight, SWP_SHOWWINDOW);
    ShowCursor(false);

    Running = true;
    while(Running){
        MSG Message = {};
        while(PeekMessage(&Message, 0, 0, 0, PM_REMOVE)){
            TranslateMessage(&Message);
            DispatchMessage(&Message);
        }
        UpdateScreenBitmap();
        SetDIBitsToDevice(GetDC(WindowHandle), 0, 0, ScreenWidth, ScreenHeight, 0, 0, 0, ScreenHeight, ScreenBitmap, &BitmapInfo, DIB_RGB_COLORS);
    }

    return 0;
}

自我排查

推测问题可能是消息队列因未处理消息堆积导致,但WM_INPUT分支中的处理逻辑极少。查阅文档及相关资料均未找到解释,尝试在SDL源码中寻找线索也未成功。

内容的提问来源于stack exchange,提问作者Prateek Bana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 16:05:53