c語言打字小程序

借鑑了大佬的成果
https://blog.csdn.net/aiwangtingyun/article/details/79623643

大佬已經實現了基本功能,這裏主要增加隨機生成字符,記錄時間的功能,目前還不夠完善。
效果圖

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <termios.h>

/* 按鍵輸入枚舉 */
enum input_e {
    BACK,       // 退格
    LEFT,       // 左鍵
    RIGHT,      // 右鍵
    NOMAL,      // 普通字符
    UNKNOW,     // 特殊功能按鍵
};

/* 全局變量 */
struct timeval tv;      // 時間
long int start, finish; // 開始結束時間
int flag = 0;           // 計時標記
int err;                // 錯誤個數
int length;             // 當前長度

/* 功能函數聲明 */
char mygetch();
int  getInput(char *dest, int *idx);
void showChar(char const *src, char *dest, int idx);
void deleteChar(char *dest, int *idx);

/*
 * 程序從主函數開始
 * 思路:
 *   1.關閉系統默認的獲取輸入通道
 *   2.使用字符數組保存用戶輸入的字符
 *   3.打印字符並檢查輸入字符輸入情況
*/
int main(void)
{
    char* src;             // 用於對照的字符串 
    char* dest;            // 存儲用戶的字符
    int idx = 0;           // 光標位置 
    int key;               // 用戶輸入
    double duration;       // 耗時
    int n, i;              // 字符長度
    
    srand(time(NULL));
    while(1)
    {
        idx = 0;
        flag = 0;
        length = 0;
        src = NULL;
        dest = NULL;

        system("clear");        // 清屏
        fprintf(stdout, "設置字符長度\n");
        fscanf(stdin, "%d", &n);
        
        fprintf(stdout, "正在生成");
        src = (char*) malloc( (n+1)*sizeof(char) );
        dest = (char*) malloc( (n+1)*sizeof(char) );

        for(i = 0; i < n; i++)
        {
            if(rand()%2)
            {
                src[i] = rand()%26 +  'a';
            }
            else
            {
                src[i] = rand()%26 +  'A';
            }
            fputc('.', stdout);
        }
        src[n] = '\0';
        fputc('\n', stdout);    // 清空緩存


        system("clear");        // 清屏 
        
        /* 顯示對照字符串 */
        fprintf(stdout, "%s\n", src);
        mygetch();             //獲取多餘回車

        /* 進入打字程序 */
        while (1)
        {
            /* 獲取輸入 */
            key = getInput(dest,&idx);

            /* 根據不同輸入進行不同操作 */
            switch (key)
            {
                case BACK : deleteChar(dest,&idx);         break;
                case LEFT : if (idx > 0) idx--;            break;
                case RIGHT: if (idx < strlen(dest)) idx++; break;
                default   : break;
            }
            dest[length] = '\0';
            
            /* 顯示結果 */
            printf("\033[1;1H");  /* 定位到開頭 */
            fprintf(stdout, "%s\n", src);
            err = 0;
            showChar(src,dest,idx);
            
            /* 打字結束 */
            if (idx == n)
            {
                gettimeofday(&tv,NULL);
                finish = tv.tv_sec*1000 + tv.tv_usec/1000;
                flag = 0;
                break;
            }
        }

        fputc('\n', stdout);

        duration = (finish-start)*1./1000;
        fprintf(stdout, "正確率%d%% 耗時%fs 速度%.2fkps\n",  (n-err)*100/n, duration, (n/duration));
        free(src);
        free(dest);
        fprintf(stdout, "輸入esc退出,輸入任意鍵繼續\n");
        if(27 == mygetch())
        {
            break;
        }
    }
    return 0;
}

/*
 * 函數名: getInput()
 * 函數功能: 獲取用戶輸入,普通字符保存在目標數組中
 *           同時處理其它特殊字符:退格,回車,方向鍵
 * 參數: 1.需要保存字符的目標數組; 2.光標位置
 * 返回值: 返回用戶輸入對應的鍵值
*/
int getInput(char *dest, int *idx)
{
    int key, i;
    int len = strlen(dest);
    char ch;

    ch = mygetch();
    
    
    if(!flag)
    {
        gettimeofday(&tv,NULL);
        fprintf(stdout, "no\n");
        start = tv.tv_sec*1000 + tv.tv_usec/1000;
        flag = 1;
    }
    

    /* 方向鍵 */
    if (ch == '\033' && mygetch() == '[')
    {
        ch = mygetch();
        switch (ch)
        {
            case 'C': key = RIGHT;  break; // 左鍵
            case 'D': key = LEFT;   break; // 右鍵
            default : key = UNKNOW; break;
        }
    }

    /* 退格鍵 */
    else if (ch == 127)  
    {
       key = BACK;
    }

    /* 回車鍵 */
    else if (ch == '\n') 
    {
        key = UNKNOW;
    }

    /* 普通字符則需要保存 */
    else 
    {
        /* 先移動字符,後插入新字符實現字符輸入 */
        for (i = len; i > *idx; i--)
        {
            dest[i] = dest[i-1];
        }

        dest[*idx] = ch;  // 光標處插入字符
        (*idx)++;         // 光標右移
        length++;
        key = NOMAL;
    }

    return key;
}

/*
 * 函數名: showChar()
 * 函數功能: 顯示源字符和用戶輸入的目標字符
 *           並進行校對
 * 參數: 1.源字符數組; 2.用戶輸入的目標字符數組
 *       3.光標位置
 * 返回值: 無
*/
void showChar(char const *src, char *dest, int idx)
{
    int i;

    printf("\033[1;1H");  /* 定位到開頭 */

    /* 打印用戶的輸入 */
    for (i = 0; dest[i] != '\0'; i++)
    {
        /* 字符匹配顯示綠色 */
        if (dest[i] == src[i])
        {
            printf("\033[32m%c\033[0m", dest[i]);
        }

        /* 字符不匹配顯示紅色 */
        else
        {
            printf("\033[31m%c\033[0m", dest[i]);
            err++;
        }
    }

    /* 光標定位到索引要處 */
    printf("\033[1;%dH", idx+1);
}

/*
 * 函數名: deleteChar()
 * 函數功能: 刪除光標所在位置的前一個字符
 * 參數: 1.用戶輸入的目標字符數組; 
 *       2.光標所在位置
 * 返回值: 無
*/
void deleteChar(char *dest, int *idx)
{
    int i;

    if (*idx > 0)
    {
        /* 通過移動覆蓋實現刪除 */
        for (i = *idx; dest[i] != 0; i++)
        {
            dest[i-1] = dest[i];
        }

        dest[i-1] = '\0'; // 最後一個字符補0

        (*idx)--;         // 光標左移
        length--;
    }
}

/***
* Linux 無回顯和緩存輸入
***/
char mygetch()
{
    struct termios oldt, newt;
    char ch;
    tcgetattr( STDIN_FILENO, &oldt );
    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
    return ch;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章