第六次实验可以算是很简单的一次了,只要知道了0.11如何响应你的键盘事件,一切问题都迎刃而解了。实现这个实验的方法有很多,我的也是仅供参考,其他方法可能还有些是涉及到修改汇编代码的。
首先,要做的就是在linux-0.11\kernel\chr_drv文件夹下的keyboard.S文件中,将第245行的call show_stat注释掉或者删掉都可以。在原来的代码中,按下F12便是调用了keyboard.S的call show_stat,而call show_stat又调用了其他的一些方法,是用来显示进程信息的。
原始的keyboard.S文件,方便大家查找call show_stat的位置。
func:
pushl %eax
pushl %ecx
pushl %edx
call show_stat
popl %edx
popl %ecx
popl %eax
subb $0x3B,%al
jb end_func
cmpb $9,%al
jbe ok_func
subb $18,%al
cmpb $10,%al
jb end_func
cmpb $11,%al
ja end_func
接着,进入正题,我们需要知道操作系统对于F12的按下,所获取的code是什么。为了知道这,我采用了很简单但也很暴力的方法,用printk方法来打印。最后根据打印的信息,我们可以知道F12的按下相当于三个键的按下,分别是21,97和76。在完成了这些准备工作之后,可以进入编写对F12按下的响应捕获事件了。
值得说明的一点是,对于这三个键值的捕获利用到了状态机的思想。虽然当时并不了解状态机,但是确实在编程中使用了这样的思想,也即必须在连续获取21,97和76才认为是F12的按下。
在linux-0.11\kernel\chr_drv文件夹下的tty_io.c文件
首先声明了这些标志位
int flag = -1;
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
int flag4 = 0
在copy_to_cooked函数里实现我们的获取键值为21,97,和76.在获取了这三个键之后设置标志位flag
void copy_to_cooked(struct tty_struct * tty)
{
signed char c;
while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
GETCH(tty->read_q,c);
/*printk("\nI am %d\n",c);*/
if (c == 27)
{
flag1 = 1;
}
else if (flag1 == 1 && c == 91 && flag2 == 0)
{
flag2 = 1;
}
else if (flag1 == 1 && flag2 == 1 && c == 91)
{
flag3 = 1;
}
else if (flag1 == 1 && flag2 == 1 && flag3 == 1 && c == 76)
{
flag *= -1;
continue ;
}
else
{
flag1 = 0;
flag2 = 0;
flag3 = 0;
}
if (c==13)
if (I_CRNL(tty))
c=10;
else if (I_NOCR(tty))
continue;
else ;
else if (c==10 && I_NLCR(tty))
c=13;
if (I_UCLC(tty))
c=tolower(c);
if (L_CANON(tty)) {
if (c==KILL_CHAR(tty)) {
/* deal with killing the input line */
while(!(EMPTY(tty->secondary) ||
(c=LAST(tty->secondary))==10 ||
c==EOF_CHAR(tty))) {call show_stat
if (L_ECHO(tty)) {
if (c<32)
PUTCH(127,tty->write_q);
PUTCH(127,tty->write_q);
tty->write(tty);
}
DEC(tty->secondary.head);
}
continue;
}
if (c==ERASE_CHAR(tty)) {
if (EMPTY(tty->secondary) ||
(c=LAST(tty->secondary))==10 ||
c==EOF_CHAR(tty))
continue;
if (L_ECHO(tty)) {
if (c<32)
PUTCH(127,tty->write_q);
PUTCH(127,tty->write_q);
tty->write(tty);
}
DEC(tty->secondary.head);
continue;
}
if (c==STOP_CHAR(tty)) {
tty->stopped=1;
continue;
}
if (c==START_CHAR(tty)) {
tty->stopped=0;
continue;
}
}
if (L_ISIG(tty)) {
if (c==INTR_CHAR(tty)) {
tty_intr(tty,INTMASK);
continue;
}
if (c==QUIT_CHAR(tty)) {
tty_intr(tty,QUITMASK);
continue;
}
}
if (c==10 || c==EOF_CHAR(tty))
tty->secondary.data++;
if (L_ECHO(tty)) {
if (c==10) {
PUTCH(10,tty->write_q);
PUTCH(13,tty->write_q);
} else if (c<32) {
if (L_ECHOCTL(tty)) {
PUTCH('^',tty->write_q);
PUTCH(c+64,tty->write_q);
}
} else
PUTCH(c,tty->write_q);
tty->write(tty);
}
/*printk("\nI am %d after..\n",c);*/
PUTCH(c,tty->secondary);
}
wake_up(&tty->secondary.proc_list);
}
在linux-0.11\kernel\chr_drv文件夹下的 console.c文件
设置了一个外部的变量flag,表明是否是F12的按下
extern int flag;
在con_write方法中对字母和数字替换为“*”即可。
void con_write(struct tty_struct * tty)
{
int nr;
char c;
nr = CHARS(tty->write_q);
while (nr--) {
GETCH(tty->write_q,c);
switch(state) {
case 0:
if (c>31 && c<127) {
if (x>=video_num_columns) {
x -= video_num_columns;
pos -= video_size_row;
lf();
}
if (((c>='A' && c<='Z')||(c>='a' && c<='z')) && flag == 1)
c = '*';
__asm__("movb attr,%%ah\n\t"
"movw %%ax,%1\n\t"
::"a" (c),"m" (*(short *)pos)
);
pos += 2;
x++;
} else if (c==27)
state=1;
else if (c==10 || c==11 || c==12)
lf();
else if (c==13)
cr();
else if (c==ERASE_CHAR(tty))
del();
else if (c==8) {
if (x) {
x--;
pos -= 2;
}
} else if (c==9) {
c=8-(x&7);
x += c;
pos += c<<1;
if (x>video_num_columns) {
x -= video_num_columns;
pos -= video_size_row;
lf();
}
c=9;
} else if (c==7)
sysbeep();
break;
case 1:
state=0;
if (c=='[')
state=2;
else if (c=='E')
gotoxy(0,y+1);
else if (c=='M')
ri();
else if (c=='D')
lf();
else if (c=='Z')
respond(tty);
else if (x=='7')
save_cur();
else if (x=='8')
restore_cur();
break;
case 2:
for(npar=0;npar<NPAR;npar++)
par[npar]=0;
npar=0;
state=3;
if ((ques=(c=='?')))
break;
case 3:
if (c==';' && npar<NPAR-1) {
npar++;
break;
} else if (c>='0' && c<='9') {
par[npar]=10*par[npar]+c-'0';
break;
} else state=4;
case 4:
state=0;
switch(c) {
case 'G': case '`':
if (par[0]) par[0]--;
gotoxy(par[0],y);
break;
case 'A':
if (!par[0]) par[0]++;
gotoxy(x,y-par[0]);
break;
case 'B': case 'e':
if (!par[0]) par[0]++;
gotoxy(x,y+par[0]);
break;
case 'C': case 'a':
if (!par[0]) par[0]++;
gotoxy(x+par[0],y);
break;
case 'D':
if (!par[0]) par[0]++;
gotoxy(x-par[0],y);
break;
case 'E':
if (!par[0]) par[0]++;
gotoxy(0,y+par[0]);
break;
case 'F':
if (!par[0]) par[0]++;
gotoxy(0,y-par[0]);
break;
case 'd':
if (par[0]) par[0]--;
gotoxy(x,par[0]);
break;
case 'H': case 'f':
if (par[0]) par[0]--;
if (par[1]) par[1]--;
gotoxy(par[1],par[0]);
break;
case 'J':
csi_J(par[0]);
break;
case 'K':
csi_K(par[0]);
break;
case 'L':
csi_L(par[0]);
break;
case 'M':
csi_M(par[0]);
break;
case 'P':
csi_P(par[0]);
break;
case '@':
csi_at(par[0]);
break;
case 'm':
csi_m();
break;
case 'r':
if (par[0]) par[0]--;
if (!par[1]) par[1] = video_num_lines;
if (par[0] < par[1] &&
par[1] <= video_num_lines) {
top=par[0];
bottom=par[1];
}
break;
case 's':
save_cur();
break;
case 'u':
restore_cur();
break;
}
}
}
set_cursor();
}
最后说明的一点是,上述的修改并不会对向文件输出的字符进行修改,只过滤了向终端输出的字符。