c - 我希望键“A”至少保持三秒钟而不会中断。确保是这种情况
问题描述
我希望按键A
至少保持三秒钟而不会中断。如果按键中断,则应再次应用三秒时间。这是我以前的程序。不幸的是,当timer()
程序运行时,程序没有注意到按钮释放或再次按下的任何信息。
我的问题是:我能做什么?
我想留在C。
我的 IDE 是 Microsoft Visual Studio Community 2019,版本 16.11.2。
我使用 Windows 10。
#pragma warning(disable : 4996) // Visual Studio doesn't want to see old functions like ‘scanf’.
#include <stdio.h>
#include <Windows.h>
#include <cstdint>
#include <time.h>
bool supposed_to_run = true;
VOID KeyEventProc(KEY_EVENT_RECORD);
long long waited = 0ll;
time_t Time_of_the_keydown_event;
bool triggered = false;
void timer()
{
Time_of_the_keydown_event;
time_t _to = time(&_to) + 3ll;
do
{
Time_of_the_keydown_event = time(&Time_of_the_keydown_event);
} while (Time_of_the_keydown_event < _to && triggered);
}
void Logic(INPUT_RECORD rec)
{
if (rec.Event.KeyEvent.wVirtualKeyCode == 0)
{
return;
}
if (!rec.Event.KeyEvent.bKeyDown)
{
triggered = false;
return;
}
switch (rec.Event.KeyEvent.wVirtualKeyCode)
{
case VK_SHIFT:
break;
case VK_CONTROL:
break;
case VK_SPACE:
break;
case VK_LEFT:
break;
case VK_UP:
break;
case VK_RIGHT:
break;
case VK_DOWN:
break;
case 0x41: /*A*/
triggered = true;
timer();
printf("A\n");
break;
case 0x51: /*Q*/
break;
case 0x5A: /*Z*/
supposed_to_run = false;
break;
default:
break;
}
}
int main(void)
{
INPUT_RECORD rec{};
HANDLE hConInp = GetStdHandle(STD_INPUT_HANDLE);
DWORD ReadCount = 0;
//Change_size_position_and_color();
while (supposed_to_run)
{
ReadConsoleInput(hConInp, &rec, 1, &ReadCount);
Logic(rec);
}
// end program
printf("\nProgramm wird beendet. Dr\x81 \bcken Sie eine Taste und \x27 \bEnter\x27 \b.\n");
getchar();
return 0;
}
解决方案
我建议您使用该功能WaitForSingleObject
。该功能允许您等待新的控制台输入可用,还允许您指定超时,在您的情况下应该是 3 秒。
根据该函数的返回值,您将知道是否发生了新的控制台输入或超时是否已过期。
switch ( WaitForSingleObject( hConInp, 3000 ) )
{
case WAIT_OBJECT_0:
//handle new console input
//ReadConsoleInput will not block if called now
break;
case WAIT_TIMEOUT:
//handle timeout
break;
default:
//handle error
}
然而,该解决方案存在一个问题。按住按键时,按键会自动重复,生成新的输入事件。因此,3 秒的超时可能永远不会过期(除非您已将操作系统配置为具有很长的重复延迟)。
因此,您将不得不忽略这些按键事件并WaitForSingleObject
再次调用,但这次不是再次超时 3 秒。相反,新的超时时间应该是原来的 3 秒的剩余时间。
在您的代码中,您使用的是 ISO C 函数time
。但是,这个函数的精度只有一秒,可能不够准确。因此,您可能希望改用特定于平台的功能GetTickCount
。
我相信通过进行上述更改,我能够使您的程序正常工作。这是我的代码:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
bool supposed_to_run = true;
bool triggered = false;
bool require_release = false;
DWORD remaining_timeout;
void Logic(INPUT_RECORD rec)
{
if (rec.Event.KeyEvent.wVirtualKeyCode == 0)
{
return;
}
if (!rec.Event.KeyEvent.bKeyDown)
{
if ( triggered )
{
printf( "removing trigger\n" );
triggered = false;
}
else if ( require_release && rec.Event.KeyEvent.wVirtualKeyCode == 0x41 )
{
printf( "key has been released and timeout may now be triggered again\n" );
require_release = false;
}
return;
}
switch (rec.Event.KeyEvent.wVirtualKeyCode)
{
case VK_SHIFT:
break;
case VK_CONTROL:
break;
case VK_SPACE:
break;
case VK_LEFT:
break;
case VK_UP:
break;
case VK_RIGHT:
break;
case VK_DOWN:
break;
case 0x41: /*A*/
if ( !triggered && !require_release )
{
printf( "triggering timeout\n" );
triggered = true;
remaining_timeout = 3000;
}
break;
case 0x51: /*Q*/
break;
case 0x5A: /*Z*/
supposed_to_run = false;
break;
default:
break;
}
}
int main(void)
{
INPUT_RECORD rec = {0};
HANDLE hConInp = GetStdHandle(STD_INPUT_HANDLE);
DWORD ReadCount;
while (supposed_to_run)
{
if ( triggered )
{
bool timeout_expired = false;
DWORD start_time = GetTickCount();
switch ( WaitForSingleObject( hConInp, remaining_timeout ) )
{
case WAIT_OBJECT_0:
break;
case WAIT_TIMEOUT:
timeout_expired = true;
break;
default:
fprintf( stderr, "unexpected error!" );
exit( EXIT_FAILURE );
}
DWORD time_expired = GetTickCount() - start_time;
if ( !timeout_expired )
{
//It is possible that WaitForSingleObject did not report
//a timeout, but that GetTickCount now reports that the
//timeout expired. We should consider this also a timeout.
if ( time_expired >= remaining_timeout )
timeout_expired = true;
}
if ( timeout_expired )
{
triggered = false;
require_release = true;
printf("A\n");
continue;
}
else
{
remaining_timeout -= time_expired;
}
}
ReadConsoleInput(hConInp, &rec, 1, &ReadCount);
Logic(rec);
}
return 0;
}
用户按住该键A三秒钟后,它将在屏幕上显示该字符。之后,直到用户释放键然后再次按下它才会触发新的超时。
推荐阅读
- c - C中的延迟函数不延迟
- azure - 服务错误 Bot 应该使用自己的存储
- c# - C#与arduino通信(arduino不断发送数据)
- r - 如何在 r 中可视化 cox 模型中的交互?
- emacs - 如何通过 ALT-M 在 emacs 中进行编译?
- php - PHP更改行基于
- regex - 如何使用两种格式的正则表达式?
- javascript - 验证表单 hasError AngularJS
- python - openpyxl - 如何使用列号而不是字母?
- sql - 创建命令有什么错误,ErrorORA-00903: invalid table name and the FK reference to pk 是正确的?