| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 706 人关注过本帖
标题:求老师帮忙实现这个主控台流程(二次输入验证的机制)
只看楼主 加入收藏
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
结帖率:100%
收藏
已结贴  问题点数:9 回复次数:3 
求老师帮忙实现这个主控台流程(二次输入验证的机制)
求老师帮忙实现这个主控台流程
======================================
请设定节拍密码(printf)

'3' 键被按下
上下按键的时间间隔(节奏): 0.833s
'2' 键被按下
上下按键的时间间隔(节奏): 0.232s
'1' 键被按下

[Enter键被按下]
======================================
再输入一次节拍密码

'3' 键被按下
上下按键的时间间隔(节奏): 0.856s
'2' 键被按下
上下按键的时间间隔(节奏): 0.294s
'1' 键被按下

[Enter键被按下]

验证输入的密码为 3 2 1
按键的间隔时间(按键释放'放开'到下一个按键按下): 0.833s/0.856s 0.232s/0.294s

密码设定完成
输入"password"并按下回车键输入密码

=====================================
请输入密码

'3' 键被按下
上下按键的时间间隔(节奏): 0.843s
'2' 键被按下
上下按键的时间间隔(节奏): 0.239s
'1' 键被按下

[incorrect 判断] 密码错误且节奏误差超过原间隔时间5~10%
if P1(b)!=P1(a) or P2(b)!=P2(a)...
else if (R1 != (R1+30ms or R1-30ms)) or (R2 != (R2+30ms or R2-30ms))...

[correct 判断] 密码相同且节奏误差在5~10%
P123(a) = P123(b)
R12(a) = R12(b)
=============

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

#define MAX_KEYS 50
#define MAX_INTERVALS (MAX_KEYS - 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;
    char keys[MAX_KEYS] = { 0 };
    double intervals[MAX_INTERVALS - 1] = { 0 }; // 設定陣列紀錄間隔數組 

    QueryPerformanceFrequency(&frequency);

    printf("請設定節拍密碼\n\n");
    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) {
                        LARGE_INTEGER press_time;
                        QueryPerformanceCounter(&press_time);
                        double interval = (double)(press_time.QuadPart - last_release_time.QuadPart) / frequency.QuadPart * 1.0;
                        intervals[key_count - 1] = interval; // 將間隔時間紀錄 
                        printf("上下按鍵的時間間隔(節奏): %.3fs\n", (double)(press_time.QuadPart - last_release_time.QuadPart) / frequency.QuadPart * 1.0);
                    }
                    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);
                    }
                }
            }
        }

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

            printf("\n==============================================================================\n");
            printf("\n 驗證輸入的密碼為 ");
            for (int i = 0; i < key_count; i++) {
                printf("%c ", keys[i]);
            }
            printf("\n");

            // Output the intervals between key presses
            printf(" 按鍵的間隔時間(按鍵釋放'放開'到下一個按鍵按下): ");
            for (int i = 0; i < key_count - 2; i++) {
                printf("%.3fs ", intervals[i]);
            }
            printf("\n");

            break;
        }
    }

    return 0;
}

/*
可以將程式更改為記錄每個按鍵釋放後到下一個按鍵按下時所花的時間,可以按照以下方式進行更改:


1. 宣告一個變數 last_release_time,用於存儲上一個按鍵釋放(放開)時的時間。
2. 將 first_event 變數更改為 last_event_was_release,表示上一個事件是否是按鍵釋放(放開)動作。
3. 如果 last_event_was_release 為 TRUE,則計算並print上一個按鍵釋放(放開)動作到當前動作的時間間隔。
4. 在事件處理代碼的最後,如果當前事件是按鍵釋放事件,則將 last_release_time 設置為當前事件的時間。
5. intervals,用存儲按下每個鍵之間的時間間隔

[備註]
若要加入鍵程時間可以在printf加入(double)(release_time.QuadPart - start_time.QuadPart) / frequency.QuadPart * 1.0),%3.f表示

[紀錄]
QueryPerformanceCounter函數 : 獲取一個高精確住的計數器,可以用於紀錄發生在短時間的事件,並以毫秒(ms)紀錄。
                                    在此程式中,其功能在於紀錄從目前按鍵釋放(放開)到下一個按鍵按下的間隔時間。

請設定節拍密碼(R以ms表示)
P1(a)
--R1=(P2dt-P1ut)ms
P2(a)
--R2=(P3dt-P2ut)ms
P3(a)

[判斷]
if P1(b)!=P1(a) or P2(b)!=P2(a)...
else if (R1 != (R1+30ms or R1-30ms)) or (R2 != (R2+30ms or R2-30ms))...

*/


参考程式码
程序代码:
#include <stdio.h>
#include <math.h>
#include <windows.h>

void InputPassword( size_t maxcount, char keys[], double timepoints[] )
{
    LARGE_INTEGER frequency, start_time;
    QueryPerformanceFrequency( &frequency );
    start_time.QuadPart = 0;

    bool keys_down[128] = { false }; // 紀錄 char 0-127 的按鍵狀態
    HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
    for( size_t i=0; i!=maxcount; )
    {
        INPUT_RECORD input_record;
        DWORD events_read;
        if( !ReadConsoleInput(console,&input_record,1,&events_read) || events_read!=1 || input_record.EventType!=KEY_EVENT ) // 忽略非按鍵訊息
            continue;

        bool bKeyDown = input_record.Event.KeyEvent.bKeyDown!=0;
        char AsciiChar = input_record.Event.KeyEvent.uChar.AsciiChar;
        if( bKeyDown && AsciiChar=='\r' ) // Enter鍵按下後不再紀錄
        {
            keys[i++] = 0;
            break;
        }
        if( AsciiChar<' ' || AsciiChar>=127 ) // 忽略無法映射的字符(對應著locale("C")下的isprint)
            continue;
        AsciiChar = (AsciiChar>='a' && AsciiChar<'z') ? (AsciiChar-'a'+'A') : AsciiChar; // 忽略大小寫(否則要監看Shift鍵和Caps鍵,過於複雜)

        if( bKeyDown && !keys_down[AsciiChar] )
        {
            LARGE_INTEGER timepoint;
            QueryPerformanceCounter( &timepoint );
            if( i == 0 )
                start_time = timepoint;

            keys_down[AsciiChar] = true;
            keys[i] = AsciiChar;
            timepoints[i++] = (timepoint.QuadPart-start_time.QuadPart)/(frequency.QuadPart+0.0);
            putchar( '*' );
        }
        else if( !bKeyDown && keys_down[AsciiChar] )
        {
            LARGE_INTEGER timepoint;
            QueryPerformanceCounter( &timepoint );

            keys_down[AsciiChar] = false;
            keys[i] = AsciiChar;
            timepoints[i++] = (timepoint.QuadPart-start_time.QuadPart)/(frequency.QuadPart+0.0);
        }
    }
    putchar( '\n' );
}

void ShowPassword( size_t maxcount, char keys[], double timepoints[] )
{
    printf( "{\n" );
    bool keys_down[128] = { false };
    for( size_t i=0; i!=maxcount && keys[i]!=0; ++i )
    {
        keys_down[keys[i]] = !keys_down[keys[i]];
        printf( "    '%c' %-4s at %10.6fs\n", keys[i], (keys_down[keys[i]]?"Down":"Up"), timepoints[i] );
    }
    printf( "}\n" );
}

bool ShowDifference( size_t maxcount, char a_keys[], double a_timepoints[], char b_keys[], double b_timepoints[] )
{
    for( size_t i=0; i!=maxcount && a_keys[i]!=0; ++i )
    {
        if( a_keys[i] != b_keys[i] )
        {
            puts( "{ 按鍵順序不一致 }" );
            return false;
        }
    }

    printf( "{\n" );
    double a_keys_down[128] = { 0 };
    double b_keys_down[128] = { 0 };
    for( size_t i=0; i!=maxcount && a_keys[i]!=0; ++i )
    {
        if( a_keys_down[a_keys[i]] == 0 )
        {
            a_keys_down[a_keys[i]] = a_timepoints[i] + 1.0;
            b_keys_down[b_keys[i]] = b_timepoints[i] + 1.0;
            if( i == 0 )
                printf( "    '%c' Down:\n", a_keys[i] );
            else
                printf( "    '%c' Down: 按鍵時間相差 %10.6fs (%4.2f%%)\n", a_keys[i], fabs(a_timepoints[i]-b_timepoints[i]), fabs(a_timepoints[i]-b_timepoints[i])*100/a_timepoints[i] );
        }
        else
        {
            double d1 = fabs( a_timepoints[i]+1.0 - a_keys_down[a_keys[i]] );
            double d2 = fabs( b_timepoints[i]+1.0 - b_keys_down[b_keys[i]] );
            printf( "    '%c' Up  : 按鍵時長相差 %10.6fs (%4.2f%%)\n", a_keys[i], fabs(d1-d2), fabs(d1-d2)*100/d1 );
            a_keys_down[a_keys[i]] = 0;
            b_keys_down[b_keys[i]] = 0;
        }
    }
    printf( "}\n" );

    puts( "如果覺得這個偏差可以接受,就返回true;否則,返回false" );
    return true;
}

int main( void )
{
    char a_keys[50];
    double a_intervals[50];
    InputPassword( 50, a_keys, a_intervals );
    ShowPassword( 50, a_keys, a_intervals );

    char b_keys[50];
    double b_intervals[50];
    InputPassword( 50, b_keys, b_intervals );
    ShowPassword( 50, b_keys, b_intervals );

    ShowDifference( 50, a_keys, a_intervals, b_keys, b_intervals );
}
搜索更多相关主题的帖子: printf FALSE 按键 char double 
2023-04-18 02:33
东海ECS
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:Python
等 级:版主
威 望:32
帖 子:412
专家分:1646
注 册:2023-1-24
收藏
得分:7 
程序代码:
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_LEN 10

// 随机生成一个0~1之间的小数 double random_number() { return (double)rand() / (double)RAND_MAX; }

// 等待指定秒数,节拍时间到 void wait(double seconds) { clock_t endwait; endwait = clock() + seconds * CLOCKS_PER_SEC; while (clock() < endwait) {} }

// 返回两个时间点之间的时间差,单位为秒 double get_time_diff(clock_t start, clock_t end) { return (double)(end - start) / CLOCKS_PER_SEC; }

int main() { // 设定节拍密码 char password[MAX_LEN]; int rhythms[MAX_LEN]; printf("请设定节拍密码:\n"); printf("'3'键被按下\n"); scanf("%d", &rhythms[0]); printf("上下按键的时间间隔(节奏): %.3fs\n", rhythms[0]); printf("'2'键被按下\n"); scanf("%d", &rhythms[1]); printf("上下按键的时间间隔(节奏): %.3fs\n", rhythms[1]); printf("'1'键被按下\n"); scanf("%d", &rhythms[2]);

// 检查密码设定是否正确
printf("\n请再输入一次节拍密码:\n");
for (int i = 0; i < 3; i++) {
    printf("'%d'键被按下\n", 3 - i);
    double rhythm, prev_time = clock() / (double)CLOCKS_PER_SEC, curr_time;
    scanf("%lf", &rhythm);
    curr_time = clock() / (double)CLOCKS_PER_SEC;
    printf("上下按键的时间间隔(节奏): %.3fs\n", rhythm);
    if (abs(rhythm - rhythms[i]) > rhythms[i] * 0.1) { // 节奏误差超过原间隔时间10%
        printf("\n密码设定错误!请重新设定。\n");
        return 0;
    }
    wait(rhythms[i] - get_time_diff(prev_time, curr_time));
}
printf("\n验证输入的密码为 %d %d %d\n", rhythms[0], rhythms[1], rhythms[2]);
printf("按键的间隔时间(按键释放'放开'到下一个按键按下): %.3fs/%.3fs\n", rhythms[0], rhythms[1]);

// 输入密码验证
printf("\n密码设定完成,输入\"password\"并按下回车键输入密码:\n");
char input[MAX_LEN];
scanf("%s", input);
if (strcmp(input, "password") != 0) {
    printf("\n密码错误!\n");
    return 0;
}
printf("\n请输入密码:\n");
for (int i = 0; i < 3; i++) {
    printf("'%d'键被按下\n", 3 - i);
    double rhythm, prev_time = clock() / (double)CLOCKS_PER_SEC, curr_time;
    scanf("%lf", &rhythm);
    curr_time = clock() / (double)CLOCKS_PER_SEC;
    if (abs(rhythm - rhythms[i]) > rhythms[i] * 0.1) { // 节奏误差超过原间隔时间10%
        printf("\n密码错误!\n");
        return 0;
    }
    wait(rhythms[i] - get_time_diff(prev_time, curr_time));
}
printf("\n密码正确!\n");

return 0;
}






会当凌绝顶,一览众山小.
2023-04-18 18:41
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
收藏
得分:0 
回复 2楼 东海ECS
这段程式我用VS2022执行无法编译#(有显示错误与警告)
是我在什么地方没有注意到吗?
2023-04-18 19:02
ianlin1024
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2023-3-11
收藏
得分:0 
回复 2楼 东海ECS
可能我描述得比较不清楚

在您的这段程式
程序代码:
char password[MAX_LEN]; int rhythms[MAX_LEN];
    printf("请设定节拍密码:\n");
    printf("'3'键被按下\n");
    scanf_s("%d", &rhythms[0]);
    printf("上下按键的时间间隔(节奏): %.3fs\n", rhythms[0]);
    printf("'2'键被按下\n"); scanf_s("%d", &rhythms[1]);
    printf("上下按键的时间间隔(节奏): %.3fs\n", rhythms[1]);
    printf("'1'键被按下\n"); scanf_s("%d", &rhythms[2]);


我的意思是指假设我输入一个字元数字或英文(ex. 1,2,3 or a,b,c)
当第二个按键释放时纪录两按键之间的时间差"R1=(P2dt-P1ut)ms"
所以按下字串的会比记录下的间隔时间多1

'3' 键被按下
上下按键的时间间隔(节奏): 0.833s
'2' 键被按下
上下按键的时间间隔(节奏): 0.232s
'1' 键被按下

重复验证就和前面一样的输入方式,但我希望可以用另一组阵列纪录下来
(第一次设定的按键/间隔时间、第二次重复的按键/间隔时间)

在此会有一个判断两组按键/间隔时间是否相符的判断式
两者之间的间隔时间可以有允许5~10%的误差(如1楼文内所述)

前面就像是在注册帐号的感觉,有两次的密码输入,只是加入了节奏当作对比值
在此算是"设定"好密码了

按下回车键之后
显示"密码设定完成"(如1楼文章)

接下来使用者要先输入"password"才可以进行密码输入
正确与否的判断是一样在文章内

如果输入的节奏或按键时中一项不正确,显示密码错误并可以一直重复输入
直到密码正确
2023-04-18 20:53
快速回复:求老师帮忙实现这个主控台流程(二次输入验证的机制)
数据加载中...
 
   



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

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