当前位置: 首页 > 面试题库 >

Linux内核:如何捕获按键并用另一个按键代替?

阎昌勋
2023-03-14
问题内容

我试图涉足低级编程。我的目标是让用户在终端中键入密钥,捕获该密钥并输出另一个密钥。因此,例如,如果用户键入“ a”,我将键入“ b”,如果用户键入“
b”,我将输出“ c”,依此类推。

这样做的步骤是什么?我已经熟悉如何访问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");

这是最小的和原始的键记录器。可以很容易地将其重新制作以替换扫描代码。

  • 该模块不是跨平台的(仅在x86架构上可用,因为它正在使用inb()功能
  • 我相信它仅适用于PS / 2键盘(不适用于USB键盘)
  • pr_info()在硬件IRQ处理程序中执行缓慢的I / O操作(我的意思是),应避免这种情况(应使用理想的线程IRQ)。

但我认为这是很好的教育目的-它真的很小,证明这个想法相当不错(不与API搞乱像input_dev
input_register_device()serio_write()input_event()input_report_key(),等)。

细节

实际的中断处理程序(在键盘驱动程序中)请求为 共享中断
,这使我们还可以请求该中断,从而在我们的ISR中(除了原始键盘驱动程序中的ISR之外)也可以处理该中断。中断请求在中完成kbd2_init()

该模块的工作原理如下:

  1. 捕获按键事件(kbd2_isr()每个按键事件都会调用硬件中断处理程序)
  2. 读取按键扫描代码(通过inb()功能)
  3. 并通过打印 pr_info()

现在,您要替换该扫描代码。我相信您可以outb()为此使用功能(在x86上)。所以我留给你。

如果您想知道为什么我们请求编号为1的IRQ,请参阅drivers / input / serio /
i8042-io.h:

#else
# define I8042_KBD_IRQ  1

另外,还要确保在驱动程序/input/serio/i8042.c中共享此IRQ :

error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
                    "i8042", i8042_platform_device);

这是i8042键盘控制器的文档:AT键盘控制器。

有用的常数

为了避免幻数,可以使用下一个定义。

从driver / input / serio / i8042-io.h:

/*
 * Register numbers.
 */

#define I8042_COMMAND_REG       0x64
#define I8042_STATUS_REG        0x64
#define I8042_DATA_REG          0x60

从include / linux / i8042.h:

/*
 * 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


 类似资料:
  • 问题内容: 我想在我的小应用程序中捕获关键事件。 我做了什么: 怎么了: 按下键时,会播放声音效果。 我看过很多帖子,都在谈论这是如何属于和没有访问权限的委托。但是函数自动完成的类类型使我相信这是错误的。 问题答案: Xcode 8.2.1•Swift 3.0.2 要消除按字符键时发出的刺耳的声音,您需要对视图进行子类化,重写方法performKeyEquivalent并返回true。 样例项目

  • 问题内容: 我用Java制作了一个简单的媒体播放器,但是我 想记录诸如+的全局按键,以暂停/恢复当前正在播放的音乐, 而JFrame没有聚焦, 但是由于JVM安全问题,似乎无法实现。 我遇到了JNativeHook,但是我只想为Windows实现我自己的方法。请建议如何做以及从哪里开始? 问题答案: Jintellitype是一个比较简单的解决方案。 https://code.google.com

  • 我需要捕获Android中的电源键按下。我尝试了以下方法 但使用此代码按下电源键控制不进入onKeyDown方法。 长按电源键时,会调用此方法。但我需要的是,我需要在单次按压时捕捉到这一事件 有人能帮忙吗?

  • 所以最基本的,我想做的是使用LWJGL让我的球员在比赛中移动。玩家当前正在移动,但当你按住按钮时,他没有继续移动。 更新的代码: 我的代码仍然有同样的问题,我开始认为是Keyboard.next()阻止了我按住按钮,而播放器仍然在移动。

  • 我使用以下代码从URL下载JSON文件: 这正确地获取了代码,但是我在获取第一级数据时遇到了问题,我可以使用并按预期工作,但我无法执行。 JSON文件可以在这里找到。 这里是JSON美化。 我想随机得到一个我不知道孩子数量的孩子。类似于 编辑: 我真的需要一个简单的解决方案,从一个随机的孩子那里得到一些参数。 我需要得到JSON- 有人能给我看一个基本的工作例子,给我一个我可以修改的最终值吗?

  • 问题内容: 我想按一下软键盘上的任何键。我不想在Activity中使用EditView或TextView,必须从Activity内部的扩展View处理该事件。 我只是试过这个: 1)覆盖活动方法。该功能不适用于软键盘,只能捕获很少的硬键盘。 2)创建我的并在我的视图中注册该视图,其中包含已注册并正在运行的。这对于软键盘根本不起作用。 3)覆盖View方法。如果我设置我的OnKeyListener或