linux中c语言kbhit函数用法,检测按键(Linux中kbhit()函数的实现)
編寫過MS-DOS程序的人通常都會查找Linux下等同于kbhit的函數(shù),這個函數(shù)會檢測一個按鍵是否被按下而并不實際的讀取。不幸的是他們并沒有找到這樣的函數(shù),因為并沒有直接等同的函數(shù)。Unix程序員并不會注意到這個遺漏,因為Unix的編程方式通常為程序應準備好等待事件的發(fā)生。因為這就是通常的kbhit的用法,所以Unix和Linux將其忽略了。
然而,當我們要由MS-DOS移植程序時,通常需要模擬kbhit,此時我們可以用非正規(guī)輸入模式來做到。
試驗--我們自己的kbhit
1 首先我們需要定義標準的頭文件并且為終端設置聲明了一個結構。peek_character用于測試一個按鍵是否被按下。然后我們定義了我們將會用到的函數(shù)的原型。
#include
#include
#include
#include
#include
static struct termios initial_settings, new_settings;
static int peek_character = -1;
void init_keyboard();
void close_keyboard();
int kbhit();
int readch();
2 main函數(shù)調(diào)用init_keyboard函數(shù)來配置終端,然后一秒循環(huán)一次,調(diào)用kbhit函數(shù)。如果按鍵檢測為q,close_keyboard函數(shù)會返回正常行為并且退出程序。
int main()
{
int ch = 0;
init_keyboard();
while(ch != 'q') {
printf("looping\n");
sleep(1);
if(kbhit()) {
ch = readch();
printf("you hit %c\n",ch);
}
}
close_keyboard();
exit(0);
}
3 init_keyboard與close_keyboard在程序的開始和結束配置終端。
void init_keyboard()
{
tcgetattr(0,&initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
new_settings.c_lflag &= ~ISIG;
new_settings.c_cc[VMIN] = 1;
new_settings.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &new_settings);
}
void close_keyboard()
{
tcsetattr(0, TCSANOW, &initial_settings);
}
4 下面是檢測鍵盤按鍵的函數(shù):
int kbhit()
{
char ch;
int nread;
if(peek_character != -1)
return 1;
new_settings.c_cc[VMIN]=0;
tcsetattr(0, TCSANOW, &new_settings);
nread = read(0,&ch,1);
new_settings.c_cc[VMIN]=1;
tcsetattr(0, TCSANOW, &new_settings);
if(nread == 1) {
peek_character = ch;
return 1;
}
return 0;
}
5 按下的按鍵是由下一個函數(shù),readch,讀取的,然后將peek_character為下一次循環(huán)設置為-1。
int readch()
{
char ch;
if(peek_character != -1) {
ch = peek_character;
peek_character = -1;
return ch;
}
read(0,&ch,1);
return ch;
}
當我們運行這個程序時,我們會得到下面的輸出:
$ ./kbhit
looping
looping
looping
you hit h
looping
looping
looping
you hit d
looping
you hit q
$
工作原理
在init_keyboard中配置終端在返回之前(MIN=1,TIME=0)讀取一個字符。kbhit將其改變?yōu)闄z測輸入并且立即返回(MIN=0,TIME=0),然后在程序退出前恢復原始設置。
注意,我們必須讀取被按下的鍵,但是卻是在局部存儲,從而可以在需要的時候返回。
虛擬控制臺
Linux提供了一個稱之為虛擬控制臺的特性。有許多的終端設備可用,所有的設備都共享PC的屏幕,鍵盤以及鼠標。通常,一個Linux的安裝配置12個這樣的虛擬控制臺。
虛擬控制臺是通過字符設備/dev/ttyN來訪問的,在這里N是一個數(shù)字,由1開始。
如果我們的Linux系統(tǒng)使用文本登陸,那么在Linux啟動運行時我們就會得到一個登陸提示。然后我們可以使用用戶名與密碼進行登陸。此時我們使用的設備就是第一個虛擬控制臺,終端設備/dev/tty1。
使用who與ps命令,我們可以看到登陸的用戶,shell與在這個虛擬控制臺上正運行的程序:
$ who
neil????? tty1??? Mar?? 8 18:27
$ ps -e
PID TTY????????? TIME CMD
1092 tty1???? 00:00:00 login
1414 tty1???? 00:00:00 bash
1431 tty1???? 00:00:00 emacs
從這里我們可以看出登陸的用戶為neil,并且在控制臺設備/dev/tty1上運行Emacs。
Linux通常啟動一個getty進程運行在前六個虛擬控制臺上,這樣就可以使用相同的屏幕,鍵盤與鼠標登陸六次。我們可以使用ps看到這些進程:
$ ps -e
PID TTY????? TIME CMD
1092 tty1 00:00:00 login
1093 tty2 00:00:00 mingetty
1094 tty3 00:00:00 mingetty
1095 tty4 00:00:00 mingetty
1096 tty5 00:00:00 mingetty
1097 tty6 00:00:00 mingetty
在這里我們可以看到SuSE默認的getty程序,mingetty,運行在另外五個虛擬控制臺上,等待用戶登陸。
我們可以使用一個特殊的按鍵組合Ctrl+Alt+F來在虛擬控制臺之間進行切換,在這里N為我們要切換到的虛擬控制臺號。所以要切換到第2個虛擬控制臺,我們需要按下Alt+Ctrl+F2,而Ctrl+Alt+F1會返回到第一個控制臺。(當由字符登陸而不是圖形登陸切換時,Ctrl+F組合也可以起作用)
如果Linux啟動一個圖形登陸,或者是通過startx或者是通過一個顯示管理器,例如xdm,X Window系統(tǒng)將會使用第一個空閑的虛擬控制臺來啟動登陸,通常為/dev/tty7。當使用X Window系統(tǒng)時,我們可以使用Ctrl+Alt+F切換到文本控制臺,并使用Ctrl+Alt+F7返回到圖形控制臺。
通常在Linux上會運行多個會活。如果我們這樣做,例如,使用命令
$ startx - :1
Linux會在下一個空閑的虛擬控制臺上啟動X服務器,在這種情況下,通常為/dev/tty8,然后我們可以使用Ctrl+Alt+F8與Ctrl+Alt+F7在他們之間進行切換。
在所有其他方面,虛擬控制臺的行為與終端類似,正如我們在這一章所描述的。如果一個進程具有正確的權限,虛擬控制臺可以使用與通常的終端相的方式執(zhí)行打開,讀取與寫入等操作。
偽終端
許類Unix系統(tǒng),包括Linux,具有一個名為偽終端的特性。這些設備的行為與我們在這一章所使用的終端相類似,所不同的是他們并沒有與其相關聯(lián)的硬件。他們可以用來為其他的程序提供一個類終端接口。
例如,使用兩個偽終端就可以使得兩個象棋程序彼此交戰(zhàn),盡管程序本身是設置用來與人在終端進行交互的。作為中介的程序?qū)⒁粋€程序的動作傳遞給另一個??梢允沟脗谓K端可以使得程序在不提供終端的情況下像通常一樣運行。
偽終端曾經(jīng)是以特定系統(tǒng)的方式實現(xiàn)的?,F(xiàn)在他們已經(jīng)進入Single Unix規(guī)范的Unix98偽終或是PTY標準中。
總結
在這一章,我們了解了控制終端的三個不同方面。在這一章的第一部分,我們了解了重定向檢測以及如何與一個終端交互,盡管標準的文件描述符已經(jīng)進行重定向。我們討論的硬件模型及其歷史。然后我們了解了通用終端接口以及在Linux終端處理上提供詳細控制的termios結構。我們也看到了如何使用termios數(shù)據(jù)庫以及以獨立于終端的方式管理屏幕的相關函數(shù),同時我們也了解了立即檢測按鍵。最后,我們討論了Linux虛擬控制臺以及偽終端。
總結
以上是生活随笔為你收集整理的linux中c语言kbhit函数用法,检测按键(Linux中kbhit()函数的实现)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uni-app实现微信小程序长按拍视频的
- 下一篇: linux 看usb 存储设备,找到哪个