我試圖涉足低層次的編程。我的目標是讓用戶在終端中鍵入一個密鑰,捕獲並輸出另一個密鑰。例如,如果用戶鍵入「a」,我會輸入「b」,如果他輸入「b」,我輸出「c」等。Linux內核:如何捕獲按鍵並將其替換爲另一個鍵?
這樣做的步驟是什麼?我已經很熟悉如何訪問Linux內核源代碼,編譯它並使用它。
謝謝。
我試圖涉足低層次的編程。我的目標是讓用戶在終端中鍵入一個密鑰,捕獲並輸出另一個密鑰。例如,如果用戶鍵入「a」,我會輸入「b」,如果他輸入「b」,我輸出「c」等。Linux內核:如何捕獲按鍵並將其替換爲另一個鍵?
這樣做的步驟是什麼?我已經很熟悉如何訪問Linux內核源代碼,編譯它並使用它。
謝謝。
考慮下一個簡單的內核模塊:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#define KBD_IRQ 1 /* IRQ number for keyboard (i8042) */
#define KBD_DATA_REG 0x60 /* I/O port for keyboard data */
#define KBD_SCANCODE_MASK 0x7f
#define KBD_STATUS_MASK 0x80
static irqreturn_t kbd2_isr(int irq, void *dev_id)
{
char scancode;
scancode = inb(KBD_DATA_REG);
/* NOTE: i/o ops take a lot of time thus must be avoided in HW ISRs */
pr_info("Scan Code %x %s\n",
scancode & KBD_SCANCODE_MASK,
scancode & KBD_STATUS_MASK ? "Released" : "Pressed");
return IRQ_HANDLED;
}
static int __init kbd2_init(void)
{
return request_irq(KBD_IRQ, kbd2_isr, IRQF_SHARED, "kbd2", (void *)kbd2_isr);
}
static void __exit kbd2_exit(void)
{
free_irq(KBD_IRQ, (void *)kbd2_isr);
}
module_init(kbd2_init);
module_exit(kbd2_exit);
MODULE_LICENSE("GPL");
這是最起碼的和原始key-logger。它可以很容易地重新替換scan code。
inb()
功能)pr_info()
),應該避免此操作(理想情況下應使用threaded IRQs))。但我認爲這是很好的教育目的 - 它真的很小,證明這個想法相當不錯(不與API搞亂像input_dev
,input_register_device()
,serio_write()
,input_event()
,input_report_key()
等)。
真實的中斷處理程序(在keyboard driver)要求爲中斷共享,這讓我們也請求中斷,因此處理它也是我們ISR(除ISR在原來的鍵盤驅動程序)。中斷請求在kbd2_init()
中完成。
該模塊的工作原理如下:
kbd2_isr()
被調用用於每個鍵按壓事件)inb()
功能)pr_info()
打印它現在,您要替換該掃描代碼。我相信你可以使用outb()
這個函數(在x86上)。所以我把它留給你。
如果你想知道爲什麼我們用數字1請求IRQ,請參閱drivers/input/serio/i8042-io.h:
#else
# define I8042_KBD_IRQ 1
此外,一定要檢查該IRQ在drivers/input/serio/i8042.c共享:
error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
"i8042", i8042_platform_device);
這裏是文檔對於i8042鍵盤控制器:AT keyboard controller。
爲了避免magic numbers,您可以使用下一個定義。
從drivers/input/serio/i8042-io.h:
/*
* Register numbers.
*/
#define I8042_COMMAND_REG 0x64
#define I8042_STATUS_REG 0x64
#define I8042_DATA_REG 0x60
/*
* Status register bits.
*/
#define I8042_STR_PARITY 0x80
#define I8042_STR_TIMEOUT 0x40
#define I8042_STR_AUXDATA 0x20
#define I8042_STR_KEYLOCK 0x10
#define I8042_STR_CMDDAT 0x08
#define I8042_STR_MUXERR 0x04
#define I8042_STR_IBF 0x02
#define I8042_STR_OBF 0x01
非常感謝你,你讓我走在正確的道路上。 – StackPWRequirmentsAreCrazy
據我所知,您可以在IO端口上使用'readb()',在現代x86 CPU上使用相同的結果(好吧,現代就像從486開始?)。 – 0andriy
@ 0andriy坦率地說,我只是用'drivers/input/serio/i8042-io.h'中的方法。無論如何,'readb()'比'inb()'有什麼好處? –
是使用X11用戶,例如通過像Gnome,XFCE,KDE這樣的桌面?您可能不需要更改內核代碼(僅用於加載一些新的鍵盤映射) –
我相信他爲了教育目的正在這樣做,試圖更好地理解內核開發。 –