reactos操作系统实现(99)

下面来分析键盘的中断处理函数的实现,如下:

#001 BOOLEAN NTAPI

#002 i8042KbdInterruptService(

#003 IN PKINTERRUPT Interrupt,

#004 PVOID Context)

#005 {

#006 PI8042_KEYBOARD_EXTENSION DeviceExtension;

#007 PPORT_DEVICE_EXTENSION PortDeviceExtension;

#008 PKEYBOARD_INPUT_DATA InputData;

#009 ULONG Counter;

#010 UCHAR PortStatus,Output;

#011 BOOLEAN ToReturn = FALSE;

#012 NTSTATUS Status;

#013

这个上下文参数,其实就是设备驱动程序里的设备扩展对象。

#014 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;

这里获取端口扩展属性

#015 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;

计算缓冲区里放入新按键位置。

#016 InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer;

读取端口轮询的最大次数

#017 Counter = PortDeviceExtension->Settings.PollStatusIterations;

#018

#019 while (Counter)

#020 {

通过键盘端口读取状态。

#021 Status = i8042ReadStatus(PortDeviceExtension,&PortStatus);

#022 if (!NT_SUCCESS(Status))

#023 {

#024 WARN_(I8042PRT,"i8042ReadStatus() Failed with status 0x%08lx/n",Status);

#025 return FALSE;

#026 }

读取键盘输入的数据。

#027 Status = i8042ReadKeyboardData(PortDeviceExtension,&Output);

#028 if (NT_SUCCESS(Status))

#029 break;

暂停一会再进入下一次尝试读取。

#030 KeStallExecutionProcessor(1);

#031 Counter--;

#032 }

轮询次数计数为0,那么说明读取键盘硬件失败。

#033 if (Counter == 0)

#034 {

#035 WARN_(I8042PRT,"SpurIoUs i8042 keyboard interrupt/n");

#036 return FALSE;

#037 }

#038

#039 INFO_(I8042PRT,"Got: 0x%02x/n",Output);

#040

判断是否是CTRL + SCROLL组合键。

#041 if (PortDeviceExtension->Settings.CrashOnCtrlScroll)

#042 {

#043 /* Test for CTRL + SCROLL LOCK twice */

#044 static const UCHAR ScanCodes[] = { 0xe0,0x1d,0x46,0xc6,0 };

#045

#046 if (Output == ScanCodes[DeviceExtension->ComboPosition])

#047 {

#048 DeviceExtension->ComboPosition++;

#049 if (ScanCodes[DeviceExtension->ComboPosition] == 0)

#050 KeBugCheck(MANUALLY_INITIATED_CRASH);

#051 }

#052 else if (Output == ScanCodes[0])

#053 DeviceExtension->ComboPosition = 1;

#054 else

#055 DeviceExtension->ComboPosition = 0;

#056 }

#057

调用ISR的回调函数,如果已经处理这个按键就返回。

#058 if (i8042KbdCallIsrHook(DeviceExtension,PortStatus,Output,&ToReturn))

#059 return ToReturn;

#060

处理键盘的数据是否需要重新输出键盘

#061 if (i8042PacketIsr(PortDeviceExtension,Output))

#062 {

#063 if (PortDeviceExtension->PacketComplete)

#064 {

#065 TRACE_(I8042PRT,"Packet complete/n");

#066 KeInsertQueueDpc(&DeviceExtension->DpcKeyboard,NULL,NULL);

#067 }

#068 TRACE_(I8042PRT,"Irq eaten by packet/n");

#069 return TRUE;

#070 }

#071

#072 TRACE_(I8042PRT,"Irq is keyboard input/n");

#073

到这里,已经说明是键盘输入数据。

#074 if (DeviceExtension->KeyboardScanState == normal)

#075 {

判断扫描码是E0,还是E1

#076 switch (Output)

#077 {

#078 case 0xe0:

#079 DeviceExtension->KeyboardScanState = GotE0;

#080 return TRUE;

#081 case 0xe1:

#082 DeviceExtension->KeyboardScanState = GotE1;

#083 return TRUE;

#084 default:

#085 break;

#086 }

#087 }

#088

更新输入的数据。

#089 /* Update InputData */

#090 InputData->Flags = 0;

置位是E0,还是E1

#091 switch (DeviceExtension->KeyboardScanState)

#092 {

#093 case GotE0:

#094 InputData->Flags |= KEY_E0;

#095 break;

#096 case GotE1:

#097 InputData->Flags |= KEY_E1;

#098 break;

#099 default:

#100 break;

#101 }

设置按键是按下码,还是弹起码。

键盘上有键被按下,松开,按住,键盘将产生扫描码( Scan Code ),这些扫描码将被 i8048 直接得到。扫描码有两种,Make Code Break Code。当一个键被按下或按住时产生的是 Make Code ,当一个键被松开产生的是 Break Code。每个键被分配了唯一的 Make Code Break Code ,这样主机通过扫描码就可以知道是哪一个键。简单的说就是按下键,产生一个 Make Code。松开键,产生一个 Break Code

#102 DeviceExtension->KeyboardScanState = normal;

#103 if (Output & 0x80)

#104 InputData->Flags |= KEY_BREAK;

#105 else

#106 InputData->Flags |= KEY_MAKE;

只需要保存低7F值。

#107 InputData->MakeCode = Output & 0x7f;

#108 InputData->Reserved = 0;

#109

调用键盘队列返回包。其实这个函数是把数据放到环形缓冲区里,然后插入一个事件到DPC队列里,再由DPC队列来完成每个IRP包。

#110 DeviceExtension->KeyboardHook.QueueKeyboardPacket(DeviceExtension->KeyboardHook.CallContext);

#111

#112 return TRUE;

#113 }

#114

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom