當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]基于Linux內(nèi)核的鍵盤模擬實(shí)現(xiàn)

1  引言

當(dāng)前,由于Linux資源完全公開,使得Linux的發(fā)展日益廣泛快速?;贚inux的各種應(yīng)用已逐漸深入日常生活的方方面面,尤其是在嵌入式領(lǐng)域,由于內(nèi)核可裁減定制,因此可隨意地根據(jù)用戶需求進(jìn)行整個(gè)系統(tǒng)的定制與重構(gòu)。其中,我們可以通過對各種標(biāo)準(zhǔn)外部設(shè)備的驅(qū)動(dòng)進(jìn)行改造,從而實(shí)現(xiàn)用戶對標(biāo)準(zhǔn)設(shè)備的特定需求,例如可以通過對鍵盤模擬來實(shí)現(xiàn)操作的自動(dòng)化,從而可以避免重復(fù)的鍵盤操作。

2  Linux內(nèi)核支持的外部調(diào)用接口

由于Linux內(nèi)核作為系統(tǒng)最深層次的核心,因此外部的開發(fā)人員并不能直接對內(nèi)核進(jìn)行操作。然而在一些應(yīng)用程序的開發(fā)過程中,又不得不使用內(nèi)核的某些功能,因此就提供了一些外部接口供開發(fā)人員直接與底層內(nèi)核打交道。

2.1  中斷

在Linux 下,硬件中斷叫做IRQ(Interrupt Requests)。有兩種IRQ,短類型和長類型。短IRQ需要很短的時(shí)間,在此期間機(jī)器的其他部分被鎖定,而且沒有其他中斷被處理。一個(gè)長IRQ需要較長的時(shí)間,在此期間可能發(fā)生其他中斷(但不是發(fā)自同一個(gè)設(shè)備)。如果可能的話,最好把一個(gè)中段聲明為長類型。如果CPU接到一個(gè)中斷,它就會停止一切工作(除非它正在處理一個(gè)更重要的中斷,在這種情況下要等到更重要的中斷處理結(jié)束后才會處理這個(gè)中斷),把相關(guān)的參數(shù)存儲到棧里,然后調(diào)用中斷處理程序。這意味著在中斷處理程序本身中有些事情是不允許的,因?yàn)檫@時(shí)系統(tǒng)處在一個(gè)未知狀態(tài)。解決這個(gè)問題的方法是讓中斷處理程序做需要馬上做的事,通常是從硬件讀取信息或給硬件發(fā)送信息,然后把對新信息的處理調(diào)度到以后去做。

實(shí)現(xiàn)的方法是在接到相關(guān)的IRQ(在Intel平臺上有16個(gè)IRQ)時(shí)調(diào)用中斷處理程序。這個(gè)函數(shù)接到IRQ號碼、函數(shù)名、標(biāo)志、一個(gè)/proc/interrupts的名字和傳給中斷處理程序的一個(gè)參數(shù)。標(biāo)志中可以包括 SA_SHIRQ來表明你希望和其他處理程序共享此IRQ(通常很多設(shè)備公用一個(gè)IRQ),或者一個(gè)SA_INTERRUPT表明這是一個(gè)緊急中斷。這個(gè)函數(shù)僅在此IRQ沒有其他處理程序或需要共享所有處理程序時(shí)才會成功運(yùn)行。

2.2  系統(tǒng)調(diào)用

系統(tǒng)調(diào)用發(fā)生在用戶進(jìn)程,通過一些特殊的函數(shù)來請求內(nèi)核提供服務(wù)。這時(shí),用戶進(jìn)程被掛起,內(nèi)核驗(yàn)證用戶請求,嘗試執(zhí)行并把結(jié)果反饋給用戶進(jìn)程,接著用戶進(jìn)程重新啟動(dòng)。一般當(dāng)前系統(tǒng)的系統(tǒng)調(diào)用作為一張表sys_call_table進(jìn)行定義的,是由指向?qū)崿F(xiàn)各種系統(tǒng)調(diào)用的內(nèi)核函數(shù)的函數(shù)指針組成的表。具體參數(shù)參見Linux內(nèi)核源代碼arch/i386/kernel/entry.S文件中:

ENTRY(sys_call_table)

l long SYMBOL_NAME(sys_ni_syscall)

/* 0 - old "setup()" system call*/

l long SYMBOL_NAME(sys_exit)

l long SYMBOL_NAME(sys_ni_syscall)

/* streams2 */

l long SYMBOL_NAME(sys_vfork)

/* 190 */

2.3  鉤子函數(shù)

鉤子(HOOK)是Linux系統(tǒng)中非常重要的系統(tǒng)接口,用它可以截獲并處理送給其他應(yīng)用程序的消息,來完成普通應(yīng)用程序難以實(shí)現(xiàn)的功能。鉤子可以監(jiān)視系統(tǒng)或進(jìn)程中的各種事件消息,截獲發(fā)往目標(biāo)的消息并進(jìn)行處理。這樣就可以在系統(tǒng)中安裝自定義的鉤子,監(jiān)視系統(tǒng)中特定事件的發(fā)生,完成特定的功能,比如截獲鍵盤、鼠標(biāo)的輸入,屏幕取詞,日志監(jiān)視等等??梢?,利用鉤子可以實(shí)現(xiàn)許多特殊而有用的功能。

3  鍵盤工作機(jī)理

CPU對外部設(shè)備的管理是通過中斷程序進(jìn)行的,鍵盤也是一種外部設(shè)備,因此,CPU對鍵盤的管理也是通過中斷進(jìn)行的。當(dāng)你擊打鍵盤的時(shí)候,鍵盤控制器會向CPU提出中斷申請,CPU響應(yīng)此中斷進(jìn)行處理,這就完成了一次很簡單與人之間通過鍵盤進(jìn)行的交互。

首先,當(dāng)輸入一個(gè)鍵盤值的時(shí)候,鍵盤將會發(fā)送相應(yīng)的scancodes給鍵盤驅(qū)動(dòng)。一個(gè)獨(dú)立的擊鍵可以產(chǎn)生一個(gè)六個(gè)scancodes的隊(duì)列。鍵盤驅(qū)動(dòng)中的 handle_ scancode()函數(shù)解析scancodes流并通過kdb_translate()函數(shù)里的轉(zhuǎn)換表(translation-table)將擊鍵事件和鍵的釋放事件(key release events)轉(zhuǎn)換成連續(xù)的keycode。例如,'a'的keycode是30。擊鍵'a'的時(shí)候便會產(chǎn)生keycode 30。釋放a鍵的時(shí)候會產(chǎn)生keycode 158(128+30)。

然后,這些keycode通過對keymap的查詢被轉(zhuǎn)換成相應(yīng)key符號。獲得的字符被送入raw tty隊(duì)列—tty_flip_buffer。receive_buf()函數(shù)周期性的從tty_flip_buffer中獲得字符,然后把這些字符送入 tty read隊(duì)列。

當(dāng)用戶進(jìn)程需要得到用戶的輸入的時(shí)候,它會在進(jìn)程的標(biāo)準(zhǔn)輸入(stdin)調(diào)用read()函數(shù)。sys_read()函數(shù)調(diào)用定義在相應(yīng)的tty設(shè)備(如/dev/tty0)的file_operations結(jié)構(gòu)中指向tty_read的read()函數(shù)來讀取字符并且返回給用戶進(jìn)程。

4  鍵盤模擬的實(shí)現(xiàn)

通常情況下,對鍵盤模擬的實(shí)現(xiàn)一般是通過寫一個(gè)自己的鍵盤中斷句柄來實(shí)現(xiàn),但這種方法容易導(dǎo)致系統(tǒng)崩潰。因此,在這種方法的基礎(chǔ)上可以利用勾子函數(shù)來實(shí)現(xiàn)。

如附圖所示,這里主要用到的勾子函數(shù)包括handle_ scancode(),put_queue(),receive_buf(),tty_read()和sys_read()等函數(shù)。

4.1  handle_scancode函數(shù)

handle_scancode函數(shù)是鍵盤驅(qū)動(dòng)程序中的一個(gè)入口函數(shù)(參見文件/usr/src/linux/drives/char/keyboard.c):

void handle_scancode(unsigned char scancode, int down);

這里通過替換原始的handle_scancode()函數(shù)來實(shí)現(xiàn)紀(jì)錄所有的scancode。即將原始的值保存,把新的值注冊進(jìn)去,從而實(shí)現(xiàn)所需要的功能,最后再調(diào)用回到原始值的情況下。當(dāng)此新的功能函數(shù)完成后,我們就可以記錄下鍵盤上的正確的擊鍵行為了(其中可以包括一些特殊的key,如ctrl, alt,shift,print screen等等)。

4.2  put_queue函數(shù)

handle_scancode()函數(shù)會調(diào)用put_queue函數(shù),用來將字符放入tty_queue。

put_queue函數(shù)在內(nèi)核中定義如下:

void put_queue(int ch)

{

wake_up(&keypress_wait);

if (tty) {

tty_insert_flip_char(tty, ch, 0);

con_schedule_flip(tty);    }}

4.3  receive_buf函數(shù)

[!--empirenews.page--]

底層tty驅(qū)動(dòng)調(diào)用receive_buf()這個(gè)函數(shù)用來發(fā)送硬件設(shè)備接收處理的字符。參見/usr/src/linux/drivers/char/n_tty.c:

static void n_tty_receive_buf(struct tty_struct *tty, const

unsigned char *cp, char *fp, int count)

參數(shù)cp是一個(gè)指向設(shè)備接收的輸入字符的buffer的指針。參數(shù)fp是一個(gè)指向一個(gè)標(biāo)記字節(jié)指針的指針。在具體的實(shí)現(xiàn)中,先保存原始的tty receive_buf()函數(shù),然后重置ldisc.receive_buf到自定義的new_receive_buf()函數(shù)來記錄用戶的輸入。

例如:要記錄在終端tty1設(shè)備上的輸入。

int fd = open("/dev/tty1", O_RDONLY, 0);

struct file *file = fget(fd);

struct tty_struct *tty = file->private_data;

//保存原始的receive_buf()函數(shù)

old_receive_buf = tty->ldisc.receive_buf;

//替換成新的new_receive_buf函數(shù)

tty->ldisc.receive_buf = new_receive_buf;

//新的new_receive_buf函數(shù)

void new_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)

{

logging(tty, cp, count);

//紀(jì)錄用戶擊鍵

/* 調(diào)用回原來的receive_buf */

(*old_receive_buf)(tty, cp, fp, count);

}

4.4  tty_read函數(shù)

當(dāng)一個(gè)進(jìn)程需要通過sys_read()函數(shù)來讀取一個(gè)tty終端的輸入字符時(shí),tty_read函數(shù)就會被調(diào)用。參見文件/usr/src/linux/drives/char/tty_io.c:

static ssize_t tty_read(struct file * file, char * buf, size_t count,

loff_t *ppos)

5  結(jié)束語

目前,利用勾子函數(shù)實(shí)現(xiàn)基于Linux內(nèi)核的鍵盤模擬的這種方法使用非常靈活,同時(shí)也可以跨平臺進(jìn)行移植,可通過tty和pts來記錄下本地和遠(yuǎn)程會話的所有擊鍵動(dòng)作,并且也支持一些特殊的按鍵。當(dāng)然,要使鍵盤模擬更靈活,下一步還需要更多的改進(jìn),例如增加多種不同日志記錄模式的支持等。

更多計(jì)算機(jī)與外設(shè)信息請關(guān)注21ic計(jì)算機(jī)與外設(shè)頻道

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉