借鑑了大佬的成果
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;
}