| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 651 人关注过本帖
标题:按键侦测遇到BUG
只看楼主 加入收藏
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
结帖率:100%
收藏
已结贴  问题点数:13 回复次数:8 
按键侦测遇到BUG
该程式在执行时会侦测按键是否按下与纪录按键之间的间隔时间
遇到的问题是该段标注区域会多一次的纪录,不知道是什么地方出问题。
程式码与图片如下#

图片附件: 游客没有浏览图片的权限,请 登录注册


程序代码:
#include <stdio.h>
#include <windows.h>

#define MAX_KEYS 30
#define MAX_KEYSB 30
#define MAX_INTERVALS (MAX_KEYS - 1)
#define MAX_INTERVALSB (MAX_KEYSB - 1)// 設定驗證密碼紀錄的間隔數比輸入按鍵少一 

int main()
{
    INPUT_RECORD input_record;
    HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
    DWORD events_read; // DWORD變量: 事件讀取(記錄按鍵按下的時間和釋放的時間) 
    LARGE_INTEGER start_time, end_time, frequency;
    BOOL last_event_was_release = FALSE;
    LARGE_INTEGER last_release_time;
    int key_count = 0;
    double sum, avg;


    char keys[MAX_KEYS] = { 0 };
    char keysB[MAX_KEYSB] = { 0 };
    double intervals[MAX_INTERVALS - 1] = { 0 };
    double intervalsB[MAX_INTERVALSB - 1] = { 0 };// 設定陣列紀錄間隔數組 
    double intervaldifferent;

    char input[20]; // 儲存使用者輸入的字串
    char target[] = "password"; // 設定目標字串
    int flag = 1;

    QueryPerformanceFrequency(&frequency);

    printf("請設定節拍密碼\n\n");
    while (1) {
        if (ReadConsoleInput(console, &input_record, 1, &events_read)) { //讀取控制台輸入(console是正在讀取的控制台輸入緩衝區的句柄,&input_record是指向緩衝區的指針,該緩衝區接收讀取的輸入記錄,1是要讀取的輸入記錄數,&events_read是一個指向變量的指針,該變量接收實際讀取的輸入記錄數)
            if (input_record.EventType == KEY_EVENT) { //檢查輸入記錄的事件類型是否為鍵盤事件
                if (input_record.Event.KeyEvent.bKeyDown) { //檢查鍵是否被按下。如果此條件為真,代碼將執行 if 語句內的代碼塊
                    if (last_event_was_release && input_record.Event.KeyEvent.wVirtualKeyCode != VK_RETURN) { //檢查上一個事件是否為按鍵釋放以及當前事件是否為按鍵(不包括回車鍵)
                        LARGE_INTEGER press_time;
                        QueryPerformanceCounter(&press_time); //記錄按鍵事件的時間
                        double intervalA = (double)(press_time.QuadPart - last_release_time.QuadPart) / frequency.QuadPart * 1.0; //併計算按鍵與最後一次按鍵釋放事件之間的間隔
                        intervals[key_count - 1] = intervalA; // 將間隔存儲在適當索引 (key_count - 1) 的間隔數組中 
                        printf("上下按鍵的時間間隔(節奏): %.3fs\n", (double)(press_time.QuadPart - last_release_time.QuadPart) / frequency.QuadPart * 1.0); //將間隔打印到控制台。打印的消息包括按鍵和最後一次按鍵釋放事件之間的時間間隔(以秒為單位)
                    }
                    QueryPerformanceCounter(&start_time); //用於獲取性能計數器的值,該值存儲在start_time變量中,然後用於計算按鍵按下和按鍵釋放之間經過的時間。
                    last_event_was_release = FALSE; //設置FALSE為表示最後一個事件是按鍵,這是計算節奏中按鍵之間的間隔所需要的。

                    if (key_count < MAX_KEYS) {
                        keys[key_count++] = input_record.Event.KeyEvent.uChar.AsciiChar;
                    }
                }
                else {
                    LARGE_INTEGER release_time;
                    QueryPerformanceCounter(&release_time);
                    last_release_time = release_time;
                    last_event_was_release = TRUE;
                    if (input_record.Event.KeyEvent.uChar.AsciiChar != '\0') {
                        printf("'%c'\n", input_record.Event.KeyEvent.uChar.AsciiChar);
                    }
                    else {
                        printf("Key pressed for %.3f s\n", (release_time.QuadPart - start_time.QuadPart) / frequency.QuadPart * 1.0);
                    }
                }
            }
        }



        // 如果Enter鍵被按下,跳出設定密碼 
        if (GetAsyncKeyState(VK_RETURN) & 1) {

            printf("\n==============================================================================\n");
            printf("再輸入一次節拍密碼\n\n");
            int key_countB = 0;

            while (2) {
                if (ReadConsoleInput(console, &input_record, 1, &events_read)) { //讀取控制台輸入(console是正在讀取的控制台輸入緩衝區的句柄,&input_record是指向緩衝區的指針,該緩衝區接收讀取的輸入記錄,1是要讀取的輸入記錄數,&events_read是一個指向變量的指針,該變量接收實際讀取的輸入記錄數)
                    if (input_record.EventType == KEY_EVENT) { //檢查輸入記錄的事件類型是否為鍵盤事件
                        if (input_record.Event.KeyEvent.bKeyDown) { //檢查鍵是否被按下。如果此條件為真,代碼將執行 if 語句內的代碼塊
                            if (last_event_was_release && input_record.Event.KeyEvent.wVirtualKeyCode != VK_RETURN) { //檢查上一個事件是否為按鍵釋放以及當前事件是否為按鍵(不包括回車鍵)
                                LARGE_INTEGER press_time;
                                QueryPerformanceCounter(&press_time); //記錄按鍵事件的時間
                                double intervalA = (double)(press_time.QuadPart - last_release_time.QuadPart) / frequency.QuadPart * 1.0; //併計算按鍵與最後一次按鍵釋放事件之間的間隔
                                intervalsB[key_countB - 1] = intervalA; // 將間隔存儲在適當索引 (key_count - 1) 的間隔數組中 
                                printf("上下按鍵的時間間隔(節奏): %.3fs\n", (double)(press_time.QuadPart - last_release_time.QuadPart) / frequency.QuadPart * 1.0); //將間隔打印到控制台。打印的消息包括按鍵和最後一次按鍵釋放事件之間的時間間隔(以秒為單位)
                            }
                            QueryPerformanceCounter(&start_time); //用於獲取性能計數器的值,該值存儲在start_time變量中,然後用於計算按鍵按下和按鍵釋放之間經過的時間。
                            last_event_was_release = FALSE; //設置FALSE為表示最後一個事件是按鍵,這是計算節奏中按鍵之間的間隔所需要的。

                            if (key_countB < MAX_KEYS) {
                                keysB[key_countB++] = input_record.Event.KeyEvent.uChar.AsciiChar;
                            }
                        }
                        else {
                            LARGE_INTEGER release_time;
                            QueryPerformanceCounter(&release_time);
                            last_release_time = release_time;
                            last_event_was_release = TRUE;
                            if (input_record.Event.KeyEvent.uChar.AsciiChar != '\0') {
                                printf("'%c' 鍵被按下\n", input_record.Event.KeyEvent.uChar.AsciiChar);
                            }
                            else {
                                printf("Key pressed for %.3f s\n", (release_time.QuadPart - start_time.QuadPart) / frequency.QuadPart * 1.0);
                            }
                        }
                    }
                }
                // 如果Enter鍵被按下,跳出設定密碼 
                if (GetAsyncKeyState(VK_RETURN) & 1) {



                    int i = 0;
                    for (int i = 0; i < key_count; i++) {
                        if (keys[i] != keysB[i])
                        {
                            printf("密碼數字設定錯誤\n");
                        }
                        else {
                            printf("密碼數字設定正確\n");
                        }
                    }


                    for (int i = 0; i < key_count - 1; i++) {
                        intervaldifferent = intervals[i] - intervalsB[i];
                        if (intervaldifferent < 0) {
                            intervaldifferent = intervaldifferent * (-1);
                        }
                        if (intervaldifferent > 0.25 * intervals[i])
                        {
                            printf("密碼數字間隔錯誤\n");
                        }
                        else {
                            printf("密碼數字間隔正確\n");
                        }
                    }


                    break;
                }
            }

            break;

        }

    }
    return 0;
}

/*

*/
搜索更多相关主题的帖子: printf 按键 double int Event 
2023-04-23 15:48
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
试试先 FlushConsoleInputBuffer
2023-04-23 17:17
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
收藏
得分:0 
以下是引用吹水佬在2023-4-23 17:17:32的发言:

试试先 FlushConsoleInputBuffer


貌似没有效
2023-04-23 18:53
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
收藏
得分:0 
回复 2楼 吹水佬
有可能是我回圈中哪一部份的值设定不正确吗?
2023-04-23 19:23
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
缓冲有东西,刷新无效就都取出丢掉
ReadConsoleInput
2023-04-23 19:58
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
收藏
得分:0 
回复 5楼 吹水佬
我的想法是第一次輸入完之後,資料記錄到A陣列中,在清除原本的緩衝區
再繼續輸入第二次的資料,記錄到B陣列。
但這樣的話我的ReadConsoleInput應該放在哪個部份呢?
2023-04-23 21:48
东海ECS
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:Python
等 级:版主
威 望:32
帖 子:412
专家分:1646
注 册:2023-1-24
收藏
得分:5 
可能是因为在按下非字母按键时也会执行到纪录间隔的代码,导致间隔纪录的数量不对。可以将纪录间隔的代码放在一个if语句中,只在按下字母键时执行。

代码示例:

while (1) { if (ReadConsoleInput(console, &input_record, 1, &events_read)) { if (input_record.EventType == KEY_EVENT) { if (input_record.Event.KeyEvent.bKeyDown) { if (last_event_was_release && input_record.Event.KeyEvent.wVirtualKeyCode != VK_RETURN) { if (input_record.Event.KeyEvent.uChar.AsciiChar >= 'a' && input_record.Event.KeyEvent.uChar.AsciiChar <= 'z') { // 只在按下字母键时记录间隔 LARGE_INTEGER press_time; QueryPerformanceCounter(&press_time); double intervalA = (double)(press_time.QuadPart - last_release_time.QuadPart) / frequency.QuadPart * 1.0; intervals[key_count - 1] = intervalA; printf("上下按鍵的時間間隔(節奏): %.3fs\n", intervalA); } } QueryPerformanceCounter(&start_time); last_event_was_release = FALSE; if (key_count < MAX_KEYS) { keys[key_count++] = input_record.Event.KeyEvent.uChar.AsciiChar; } } else { LARGE_INTEGER release_time; QueryPerformanceCounter(&release_time); last_release_time = release_time; last_event_was_release = TRUE; if (input_record.Event.KeyEvent.uChar.AsciiChar != '\0') { printf("'%c'\n", input_record.Event.KeyEvent.uChar.AsciiChar); } else { printf("Key pressed for %.3f s\n", (release_time.QuadPart - start_time.QuadPart) / frequency.QuadPart * 1.0); } } } } }

会当凌绝顶,一览众山小.
2023-04-23 22:12
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
收藏
得分:0 
回复 7楼 东海ECS
图片附件: 游客没有浏览图片的权限,请 登录注册


谢谢您提供这个思路
但其实在原程式码中我在输入字母或着数字功能都是一样的,所以有排除掉这个可能性

在图片中其实是一个输入与重复验证的过程(用=====上下部份表示),第一次我输入3个数字,很标准的确实有3个数字与2个间隔时间,这部分是没问题的,在我按下回车键之后(用=====下部份),就是红框内的地方,而红框第一行的[' 键被按下],我判断是程式记录了我的回车键并输出出来了,但不知道怎么修掉这个地方。
红框第二行是我在第二次重复验证按下"1"时,系统记录到我前一个回车键的时间,并与"1"键输出两者的间隔时间。
2023-04-23 23:25
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:8 
            ReadConsoleInput(console, &input_record, 1, &events_read);
            while (2) {
                if (ReadConsoleInput(console, &input_record, 1, &events_read))
2023-04-24 09:15
快速回复:按键侦测遇到BUG
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.033168 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved