第七章 输入输出系统之键盘
来源:互联网 发布:ajax json提交数据 编辑:程序博客网 时间:2024/05/16 00:27
一、键盘的基础知识
1.键盘种类
XT 很悠久了
AT
PS/2
USB 现在用的
1.总共有3套扫描码
XT键盘Scan code set1
现在AT和ps/2是Scan code set2
如果是set2最终还是会转换成set1的为了兼容,所以我们管好set1就好了
Keyboard Scan Codes: Set 1
*Alle Angaben Hexadezimal
101-, 102-, and 104-key keyboards:
KEY
MAKE
BREAK
KEY
MAKE
BREAK
KEY
MAKE
BREAK
A
1E
9E
9
0A
8A
[
1A
9A
B
30
B0
`
29
89
INSERT
E0,52
E0,D2
C
2E
AE
-
0C
8C
HOME
E0,47
E0,97
D
20
A0
=
0D
8D
PG UP
E0,49
E0,C9
E
12
92
\
2B
AB
DELETE
E0,53
E0,D3
F
21
A1
BKSP
0E
8E
END
E0,4F
E0,CF
G
22
A2
SPACE
39
B9
PG DN
E0,51
E0,D1
H
23
A3
TAB
0F
8F
U ARROW
E0,48
E0,C8
I
17
97
CAPS
3A
BA
L ARROW
E0,4B
E0,CB
J
24
A4
L SHFT
2A
AA
D ARROW
E0,50
E0,D0
K
25
A5
L CTRL
1D
9D
R ARROW
E0,4D
E0,CD
L
26
A6
L GUI
E0,5B
E0,DB
NUM
45
C5
M
32
B2
L ALT
38
B8
KP /
E0,35
E0,B5
N
31
B1
R SHFT
36
B6
KP *
37
B7
O
18
98
R CTRL
E0,1D
E0,9D
KP -
4A
CA
P
19
99
R GUI
E0,5C
E0,DC
KP +
4E
CE
Q
10
90
R ALT
E0,38
E0,B8
KP EN
E0,1C
E0,9C
R
13
93
APPS
E0,5D
E0,DD
KP .
53
D3
S
1F
9F
ENTER
1C
9C
KP 0
52
D2
T
14
94
ESC
01
81
KP 1
4F
CF
U
16
96
F1
3B
BB
KP 2
50
D0
V
2F
AF
F2
3C
BC
KP 3
51
D1
W
11
91
F3
3D
BD
KP 4
4B
CB
X
2D
AD
F4
3E
BE
KP 5
4C
CC
Y
15
95
F5
3F
BF
KP 6
4D
CD
Z
2C
AC
F6
40
C0
KP 7
47
C7
0
0B
8B
F7
41
C1
KP 8
48
C8
1
02
82
F8
42
C2
KP 9
49
C9
2
03
83
F9
43
C3
]
1B
9B
3
04
84
F10
44
C4
;
27
A7
4
05
85
F11
57
D7
'
28
A8
5
06
86
F12
58
D8
,
33
B3
6
07
87
PRNT
SCRN
E0,2A,
E0,37
E0,B7,
E0,AA
.
34
B4
7
08
88
SCROLL
46
C6
/
35
B5
8
09
89
PAUSE
E1,1D,45
E1,9D,C5
-NONE-
ACPI Scan Codes:
Key
Make Code
Break Code
Power
E0, 5E
E0, DE
Sleep
E0, 5F
E0, DF
Wake
E0, 63
E0, E3
Windows Multimedia Scan Codes:
Key
Make Code
Break Code
Next Track
E0, 19
E0, 99
Previous Track
E0, 10
E0, 90
Stop
E0, 24
E0, A4
Play/Pause
E0, 22
E0, A2
Mute
E0, 20
E0, A0
Volume Up
E0, 30
E0, B0
Volume Down
E0, 2E
E0, AE
Media Select
E0, 6D
E0, ED
E0, 6C
E0, EC
Calculator
E0, 21
E0, A1
My Computer
E0, 6B
E0, EB
WWW Search
E0, 65
E0, E5
WWW Home
E0, 32
E0, B2
WWW Back
E0, 6A
E0, EA
WWW Forward
E0, 69
E0, E9
WWW Stop
E0, 68
E0, E8
WWW Refresh
E0, 67
E0, E7
WWW Favorites
E0, 66
E0, E6
2.在键盘中存在着一个Intel 8048(键盘编码器)的芯片监控输入
寄存器
从8048种获取数据
t_8 scan_code =in_byte(KB_DATA)// KB_DATA=0x60
in_byte:
mov edx,[esp + 4] ; port
xor eax,eax
in al, dx //其实就是in al,0x60
nop ;一点延迟
nop
ret
二、程序B处理键盘输入打印出来
1.按键的产生
当按键和保持按下时产生Make Code,当弹起产生Break Code
8048检测到按键然后把按键信息发送给8042
8042将按键信息转换成Scan code set1扫描码,把他存入自己的缓冲区中,缓冲区不清空将不再接受8048
8042告诉8259A产生中断IRQ1
2.增加的代码
[1]Kernel/main.c的tinix_main函数
[2]\kernel\keyboard.cinit_keyboard函数
/*======================================================================*
init_keyboard
*======================================================================*/
PUBLIC void init_keyboard()
{
kb_in.count= 0;
kb_in.p_head= kb_in.p_tail = kb_in.buf;
put_irq_handler(KEYBOARD_IRQ, keyboard_handler); /*设定键盘中断处理程序 */ // KEYBOARD_IRQ=0x1
enable_irq(KEYBOARD_IRQ); /* 开键盘中断 */
}
[4]
\kernel\i8259.c
PUBLIC void put_irq_handler(int irq, t_pf_irq_handlerhandler)
{
disable_irq(irq); // disable_irq(1)
irq_table[irq]= handler; irq_table[1] // extern t_pf_irq_handler irq_table[];//typedef void (*t_pf_irq_handler) (int irq)
}
[5]kernel\kernel.asm
%macro hwint_master 1
call save
in al, INT_M_CTLMASK ; ┓
or al, (1 << %1) ; ┣屏蔽当前中断
out INT_M_CTLMASK, al ; ┛
mov al, EOI ;┓置EOI位
out INT_M_CTL, al ;┛
sti ; CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断
push %1 ;┓
call [irq_table + 4 *%1] ; ┣中断处理程序
pop ecx ;┛
cli
in al, INT_M_CTLMASK ; ┓
and al, ~(1 << %1) ; ┣恢复接受当前中断
out INT_M_CTLMASK, al ; ┛
ret
%endmacro
这样每次当按键键盘触发8259A产生IRQ1中断都会调用irq_table[1],也就是函数keyboard_handler
[6] keyboard_handler这个函数每次都把获得的Break Code和Make Code放到一个链表里面
\kernel\keyboard.c
PUBLIC void keyboard_handler(int irq)
{
t_8scan_code = in_byte(KB_DATA); //读取缓冲区内容
if(kb_in.count < KB_IN_BYTES)// KB_IN_BYTES=32,链表最大长度32
{
*(kb_in.p_head)= scan_code;
kb_in.p_head++;
if(kb_in.p_head == kb_in.buf + KB_IN_BYTES) {
kb_in.p_head= kb_in.buf;
}
kb_in.count++;
}
}
链表结构\include\keyboard.h
typedef struct s_kb {
char* p_head; /*指向缓冲区中下一个空闲位置 */
char* p_tail; /*指向键盘任务应处理的字节 */
int count; /* 缓冲区中共有多少字节 */
char buf[KB_IN_BYTES]; /* 缓冲区 */
}KB_INPUT;
[1] kernel\global.c中有,多了一个进程执行函数task_tty
PUBLIC TASK task_table[NR_TASKS]= {{task_tty, STACK_SIZE_TTY, "tty"},
{TestA,STACK_SIZE_TESTA, "TestA"},
{TestB,STACK_SIZE_TESTB, "TestB"},
{TestC,STACK_SIZE_TESTC, "TestC"}};
[2] \kernel\main.c中有,这样每次这个进程切换到tty进程都会执行函数task_tty
[3] task_tty进程负责调用keyboard_read()
kernel\tty.c
PUBLIC void task_tty()
{
while(1) {/* forever. yes, forever, there's something which is some kind offorever... */
keyboard_read();
}
}
[4]我们要关注的重点函数,从键盘缓冲区中读取内容
\kernel\keyboard.c
/*======================================================================*
keyboard_read
*======================================================================*/
PUBLIC voidkeyboard_read()
{
t_8 scan_code;
t_bool make; /*TRUE : make */
/*FALSE: break */
t_32 key = 0;/* 用一个整型来表示一个键。 */
/*比如,如果 Home 被按下,则 key 值将为定义在 keyboard.h 中的 'HOME'。*/
t_32* keyrow; /*指向 keymap[] 的某一行 */
if(kb_in.count> 0)
{
code_with_E0= FALSE;
scan_code= get_byte_from_kb_buf();
/*下面开始解析扫描码 */
if(scan_code == 0xE1) //解析PAUSE键,此键只有按下6个0xE1,0x1D,0x45,0xE1,0x9D,0xC5
{
inti;
t_8pausebreak_scan_code[] = {0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5};
t_boolis_pausebreak = TRUE;
for(i=1;i<6;i++){
if(get_byte_from_kb_buf() != pausebreak_scan_code[i]) {
is_pausebreak= FALSE;
break;
}
}
if(is_pausebreak) {
key= PAUSEBREAK;
}
}
elseif (scan_code == 0xE0)
{
scan_code= get_byte_from_kb_buf();
/*PrintScreen 被按下 */
if(scan_code == 0x2A)
{
if(get_byte_from_kb_buf() == 0xE0)
{
if(get_byte_from_kb_buf() == 0x37)
{
key= PRINTSCREEN;
make= TRUE;
}
}
}
/*PrintScreen 被释放 */
if(scan_code == 0xB7)
{
if(get_byte_from_kb_buf() == 0xE0)
{
if(get_byte_from_kb_buf() == 0xAA)
{
key= PRINTSCREEN;
make= FALSE;
}
}
}
/*不是 PrintScreen。此时 scan_code 为 0xE0 紧跟的那个值。 */
if(key == 0) {
code_with_E0= TRUE;
}
}
if((key != PAUSEBREAK) && (key != PRINTSCREEN))
{
/*首先判断Make Code 还是 Break Code */
//#defineFLAG_BREAK 0x0080
//A按下1E&0x80=0x00
//A释放9E&0x80=0x80
make= (scan_code & FLAG_BREAK ? FALSE : TRUE);
//0x1E&0x7F=0x1E
//MAP_COLS=3
/* 先定位到 keymap 中的行 */
keyrow= &keymap[(scan_code & 0x7F) * MAP_COLS];
column= 0;
if(shift_l || shift_r) //如果按下左边的shift和右边的shift就是第二行
{
column= 1;
}
if(code_with_E0) //其它键入ctrl和alt等,就是第二行
{
column= 2;
}
key= keyrow[column];
switch(key){
caseSHIFT_L:
shift_l = make;
break;
caseSHIFT_R:
shift_r = make;
break;
caseCTRL_L:
ctrl_l = make;
break;
caseCTRL_R:
ctrl_r = make;
break;
caseALT_L:
alt_l = make;
break;
caseALT_R:
alt_l = make;
break;
default:
break;
}
}
if(make){/* 忽略 Break Code */
key|= shift_l ? FLAG_SHIFT_L : 0;
key|= shift_r ? FLAG_SHIFT_R : 0;
key|= ctrl_l ? FLAG_CTRL_L : 0;
key|= ctrl_r ? FLAG_CTRL_R : 0;
key|= alt_l ? FLAG_ALT_L : 0;
key|= alt_r ? FLAG_ALT_R : 0;
in_process(key);
}
}
}
/*======================================================================*
get_byte_from_kb_buf
*======================================================================*/
PRIVATE t_8get_byte_from_kb_buf() /* 从键盘缓冲区中读取下一个字节 */
{
t_8 scan_code;
while(kb_in.count <= 0) {} /* 等待下一个字节到来 */
disable_int();
scan_code= *(kb_in.p_tail);
kb_in.p_tail++;
if(kb_in.p_tail == kb_in.buf + KB_IN_BYTES) {
kb_in.p_tail= kb_in.buf;
}
kb_in.count--;
enable_int();
returnscan_code;
}
[5] 最终键盘处理
Kernel
PUBLIC voidin_process(t_32 key)
{
char output[2] = {'\0', '\0'};
if(!(key & FLAG_EXT)) {
output[0]= key & 0xFF;
disp_str(output);
}
}
三、奇怪,我按小写键盘不能可是于渊已经处理了
可能他的键盘跟我们有点区别吧,还是粗心,咳咳,我改成如下
Keymap.h文件
/*0x47 - Home */ PAD_HOME, '7', HOME,
/*0x48 - CurUp */ PAD_UP, '8', UP,
/*0x49 - PgUp */ PAD_PAGEUP, '9', PAGEUP,
/*0x4A - '-' */ PAD_MINUS, '-', 0,
/*0x4B - Left */ PAD_LEFT, '4', LEFT,
/*0x4C - MID */ PAD_MID, '5', 0,
/*0x4D - Right */ PAD_RIGHT, '6', RIGHT,
/*0x4E - '+' */ PAD_PLUS, '+', 0,
/*0x4F - End */ PAD_END, '1', END,
/*0x50 - Down */ PAD_DOWN, '2', DOWN,
/*0x51 - PgDown */ PAD_PAGEDOWN, '3', PAGEDOWN,
/*0x52 - Insert */ PAD_INS, '0', INSERT,
/*0x53 - Delete */ PAD_DOT, '.', DELETE,
改成
/* 0x47 - Home */ '7', PAD_HOME, HOME,
/* 0x48 - CurUp */ '8', PAD_UP, UP,
/* 0x49 - PgUp */ '9', PAD_PAGEUP, PAGEUP,
/* 0x4A - '-' */ '-', PAD_MINUS, 0,
/* 0x4B - Left */ '4', PAD_LEFT, LEFT,
/* 0x4C - MID */ '5', PAD_MID, 0,
/* 0x4D - Right */ '6', PAD_RIGHT, RIGHT,
/* 0x4E - '+' */ '+', PAD_PLUS, 0,
/* 0x4F - End */ '1', PAD_END, END,
/* 0x50 - Down */ '2', PAD_DOWN, DOWN,
/* 0x51 - PgDown */ '3', PAD_PAGEDOWN, PAGEDOWN,
/* 0x52 - Insert */ '0', PAD_INS, INSERT,
/* 0x53 - Delete */ '.', PAD_DOT, DELETE,
Ok可以正常按了
附录
查看完整的三套扫描码
http://www.computer-engineering.org/chinese.pdf 第52页
或者
https://www.marjorie.de/ps2/scancode-set1.htm
- 第七章 输入输出系统之键盘
- 第七章 输入输出系统之显示器和TTY
- 谭浩强版c++实例 第七章 输入输出流
- 第六章、输入输出系统
- 第五章 输入输出系统
- 第七章 使用文本、键盘和按钮
- 第七章:系统框架
- Python之《机器学习系统设计》第七章
- 第5章 输入输出系统
- 基本输入输出-键盘
- 操作系统之——输入输出系统
- [置顶] Android输入输出系统之TouchEvent流程
- [python3教程]第七章.输入输出(Input and Output)
- 输入输出系统
- 输入输出系统
- 输入输出系统
- 输入输出系统
- 系统输入输出
- 浅谈TRUNCATE TABLE
- 如何在springMVC 中对REST服务使用mockmvc 做测试
- 产品与运营之产品生产曲线
- Swift-指定构造方法和便利构造方法
- windows 64为安装redis
- 第七章 输入输出系统之键盘
- 算法基本名词
- 33. Search in Rotated Sorted Array AND 81. Search in Rotated Sorted Array II
- 2017.01.06
- 朴素贝叶斯分类-NB算法
- SQL 查询
- jquery post时content-type的几种取值详解
- 安卓基础DAY07 笔记
- 常见的数据寻址方式