📄 第20章 杂项.txt
字号:
请参见:
20.17可以使热启动(Ctrl+Break+Delete)失效吗?
20.17 可以使热启动(Ctrl+Alt+Delete)失效吗?
可以。尽管不容易讲清楚如何使热启动失效,但其编程实现却并非难事。为了捕获Ctrl+Alt+Delete击键序列,你必须利用键盘的中断服务程序(interrupt service routine,缩写为ISR)。从一个高的层次上讲,键盘ISR是这样工作的:监视(捕获)所有的键盘输入,等待Ctrl+Alt+Delete击键序列。如果捕获到的不是Ctrl+Alt+Delete击键序列,就把它传给“计算机”;如果捕获到Ctrl+Alt+Del击键序列,就把它抹掉(从键盘的字符缓冲区中删掉),或者把它转换为其它击键(你的程序知道这个击键表示用户想要热启动计算机)。在程序结束时,停止监视键盘输入并恢复正常的操作。这就是ISR的工作方式一~它们把自己连接到键盘和其它中断上,这样它们就能知道在什么时候出面去完成自己的任务。
那么你应该如何完成这些工作呢?当然,要用一个C程序。下面是一个简化了的例子,它
监视所有的ctrl+Alt+Del击键序列,在该组合键按下时不作任何反应:
# include <stdlib. h>
# include <dos. h>
/ * function prototypes * /
void ( interrupt far_cdecl KbIntProc)(
unsigned short es,unsigned short ds, unsigned short di,
unsigned short si,unsigned short bp, unsigned short sp,
unsigned short bx,unsigned short dx, unsigned short cx,
unsigned short ax,unsigned short ip, unsigned short cs,
unsigned short flags);
void( interrupt far cdecl * OldKbIntProc) (void);
unsigned char far * kbFlags; / * pointer to keyboard flags * /
int key char, junk; * miscellaneous variables * /
/ * keyboard scancode valuss * /
# define AI.T 0x8
# define CTRL 0x4
# define KEY MASK 0x0F
# define DELETE 0x53
void
main(int argc,char ** argv)
{
int i,idx ;
/ * Save old interrupt vectors * /
OldKbIntProc= dos_getvect (0x9)
/* Set pointer to keyboard flags * /
FP SEG(kbFlags) = 0;
FP OFF(kbFlags) = 0x417;
/ * Add my ISR to the chain * /
dos setvect(0xg,KbIntProc) ;
/ * Print something while user presses keys... * /
/ * Until ESCAPE is pressed, then leave * /
while (getch() !=27){
printf ("Disallowing Ctrl+Alt+Delete... \n" );
}
/ * Remove myself from the chain * /
dos setvect(0x9,OldKbIntProc) ;
}
void _interrupt_far_cdecl KblntProc
unsigned short es,unsigned short ds, unsigned short di,
unsigned short si,unsigned short bp, unsigned short sp,
unsigned short bx,unsigned short dx, unsigned short cx,
unsigned short ax,unsigned short ip, unsigned short cs,
unsigned short flags)
{
/ * Get keystroke input from keyboard port * /
key_char =inp (0x60) ;
if( (( * kbFlags & KEY_MASK)= = (CTRL | ALT))
&& (key_char = =DELETE) ) {
/ * Reset the keyboard * /
junk = inp(0x61) ;
outp(0x61,(junk ] 0x80));
outp (0x61 ,iunk) ;
outp(0x60,(key_char | 0x80));
outp (0x60,0xgC) ;
}
/ * Reset the interrupt counter * /
outp (0x20,0x20) ;
/ * Now call the next ISR in line * /
( * OldKbIntProc) () ;
}
这个程序只有两个部分:main()函数体和键盘中断服务程序KbIntProc().main()函数先是通过dos getvect()来检索当前键盘中断服务程序(ISR)的地址,然后通过_dos_setvect()把键盘中断服务程序换为KbIntProc().while循环不断地接收键盘输入,并反复打印同一条消息,直到Escape键(其ASCII码为十进制数27)被按下为止。当Escape键被按下后,程序就调用dos_setvect()来恢复原来的键盘中断服务程序。
然而,好戏全在KbIntProc()之中。当它被装入后(通过前面所介绍的__dos_setvect()调用),它将在任何其它函数(或程序)之前看到所有的键盘输入,因此,它能首先处理或全部删掉键盘输入。当它接收到一个键时,它会检查键盘,看一看Ctrl键和Alt键是否已经被按下,并且检查所接收的键是否是Delete键。如果这两种情况都发生了,它就会复位键盘,从而删掉接收到的Delete键。不管所接收的键是否被忽略、处理或删掉,这个键盘ISR总要调用原来的键盘中断服务程序(OldKbIntProc());否则,计算机会立即停止运行。
如果你认真思考一下,你就会发现这个程序可以捕获任何击键或组合键,包括Ctrl+c和Ctrl+Break。因此,你完全可以考虑用这种办法来捕获Ctrl+Break组合键。应该指出的是,这种方法的入侵性比较强—— 一个很小的错误都会导致计算机停止运行。但是,你不要因此就不去学习或使用这种方法。
请参见:
20.16 怎样使Ctrl+Break失效?
20.18 怎样判断一个字符是否是一个字母?
字母表中的所有字母(包括计算机键盘上的所有键)都被赋予了一个值,这些字符及其相应的值一起组成了ASCII字符集,该字符集在北美、欧洲和许多讲英语的国家中得到了广泛的使用。
字母字符被分成大写和小写两组,并按数字顺序排列。有了这种安排,就能很方便地检查一个字符是否是一个字母以及是大写还是小写。下面这段代码说明了如何检查一个字符是否是一个字母:
int ch ;
ch=getche() ;
if((ch>=97) && (ch<=122))
printf(" %c is a lowercase letter\n" ,ch);
else if ((ch>=65) && (ch<=90))
print(" %c is an uppercase letter\n" ,ch);
else
printf(" %c is not an alphabet letter\n" ,ch) ;
在上例中,变量ch的值与十进制值进行比较。当然,它也可以与字符本身进行比较,因为ASCII字符既是按字符顺序定义的,也是按数字顺序定义的。请看下例:
int ch ;
ch=getche() ;
if((ch>='a') && (ch<='z'))
printf("%c is a lowercase letter\n" ,ch);
else if ((ch>='A') && (ch<='Z'))
print(" %c is a uppercase letter\n" ,ch);
else
printf(" %c is not an alphabet letter\n" ,ch);
你可以随便选择一种方法在程序中使用。但是,后一种方法的可读性要好一些,因为你很难记住ASCII码表中每个字符所对应的十进制值。
请参见:
20.19 怎样判断一个字符是否是一个数字?
20.19 怎样判断一个字符是否是一个数字?
在ASCII码表中,数字字符所对应的十进制值在48到57这个范围之内,因此,你可以用如下所示的代码来检查一个字符是否是一个数字:
int ch ;
ch=getche() ;
if((ch>=48) && (ch<=57))
printf(" %c is a number character between 0 and 9\n" ,ch) ;
else
printf(" %c is not a number\n" ,ch) ;
与20.18相似,变量ch也可以和数字本身进行比较:
int ch ;
ch=getche () ;
if((ch>='O') && (ch<='9'))
printf(" %c is a number character between 0 and 9\n" ,oh) ;
else
printf(" %c is not a number~n" ,ch) ;
同样,选用哪一种方法由你决定,但后一种方法可读性更强。
请参见:
20.18 怎样判断一个字符是否是一个字母?
20.20 怎样把一个十六进制的值赋给一个变量?
c语言支持二进制、八进制、十进制和十六进制的计数系统,在表示一个数字时,用某个特殊的字符来区别其所属的计数系统是必要的。在表示二进制数时,要在数字的末尾加上“b”(如101b);在表示八进制数时,要使用反斜杠(如\014);在表示十六制数时,要使用“0x”字符序列(如0x34);显然,在表示十进制数时,不需要任何标识符,因为十进制是缺省的计数系统。
要把一个十六进制的值赋给一个变量,你可以象下面这样做:
int x ;
x=0x20; /* put hex 20(32 in decimal) into x */
x='0x20' ; / * put the ASCII character whose value is
hex 20 into x * /
只有了解了十六进制计数系统,你才能知道要赋的值应该如何表示,详见20.24。
请参见:
20.24 什么是十六进制?
20.21 怎样把一个八进制的值赋给一个变量?
把一个八进制的值赋给一个变量与把一个十六进制的值赋给一个变量一样简单:
int x ;
x=\033; / * put octal 33 (decimal 27) into x * /
x='\033' ; / * put the ASCII character whose value is
octal 33 into x * /
同样,只有了解了八进制计数系统,你才能知道要赋的值应该如何表示,详见20.23。
请参见:
20.23 什么是八进制?
20.22 什么是二制制?
在数学计算中,二进制计数系统的公分母是最小的,它以2为基数。你还记得在小学或中学时所学的不同的计数系统吗?笔者在上小学时,曾在一堂数学课中学过以6为基数的计数系统;你先数1,2,3,4,5,然后是10,11,12,13,14,15,然后是20,等等,实际上,应该先数0,1,2,3,4,5,然后是10,1l,12,13,14,15,等等。从O开始数,能比较清楚地看出每6个数字组成一组——因此6就是基数。注意,你应该从O开始一起数到比基数小1的数(因为基数是6,所以你应该从O数到5)。当你数到5后,接着应该开始数两位数。如果你思考一下,你就会发现这与以10为基数(十进制)的计数系统是类似的——在你数到比基数小1的数(9)后,就转到两位数,并继续往下数。
计算机中的计数系统以2为基数——即二进制。由于以2为基数,所以你先
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -