gpt4 book ai didi

c - 当我按下键盘上的键时如何防止重复的字符

转载 作者:太空狗 更新时间:2023-10-29 15:37:26 24 4
gpt4 key购买 nike

我正在尝试学习如何防止键盘将多个字符发送到屏幕和 DOS 下的 scanf。我正在使用带有内联汇编的 Turbo-C。

如果键盘输入的字符是:

mmmmmmmmyyyyy nnnnnaaaaammmmmmeeeeee iiiiiissss HHHHaaaaiiiimmmm

在控制台上看到并由 scanf 处理的字符将是:

my name is Haim

基本输出来自 C 中的代码,我不允许接触。我必须实现 eliminate_multiple_pressuneliminate_multiple_press 而不触及它们之间的代码。 enter image description here

到目前为止,我编写的 Turbo-C 代码是:

#include <stdio.h>
#include <dos.h>
#include <string.h>

volatile char key;
volatile int i=0;
void interrupt (*Int9save) (void);

void interrupt kill_multiple_press()
{
asm{
MOV AL, 0
MOV AH,1
INT 16h
PUSHF
CALL DWORD PTR Int9save
MOV AX,0
}

asm{
JZ notSet
MOV key, AL
MOV AH, 04H
INT 16H

}
notSet:
//I am not sure what to do from here...............
I also know that it should be related to the zero flag, but what I
wrote so far didn`t effect on multiple characters.
}

void eliminate_multiple_press()
{
Int9save=getvect(9);
setvect(9,kill_multiple_press);
}

void uneliminate_multiple_press()
{
setvect(9,Int9save);
}

void main()
{
char str[10000]="";
clrscr();
eliminate_multiple_press();
printf("Enter your string: ");
scanf("%s",&str);
printf("\n%s",str);
uneliminate_multiple_press();
}

我得到的与解决方案相关的信息是可以在 this link 找到的键盘 BIOS 例程。 :

我遇到的问题可能与不了解标签notSet 上的操作有关。该解决方案似乎与使用缓冲区和寄存器AX(尤其是AL)有关,但我真的不知道如何制作scanf得到我需要的结果。有谁知道我该如何完成这段代码以达到预期的效果?

最佳答案

BIOS、DOS 和C 库(包括scanf)可以使用多层缓冲区。当您的机器启动时,中断 vector 表被修改为将 IRQ1/INT 9h(外部键盘中断)指向 BIOS 例程以在字符键入时处理它们。在最低级别通常有一个 32 字节的 6 circular bufferBIOS Data Area 中维护(BDA) 来跟踪字符。您可以使用 Int 16h BIOS calls 1 与这个低级键盘缓冲区进行交互。如果您在中断时从 BIOS 键盘缓冲区中删除字符,那么 DOS 和 Cscanf5 例程将永远看不到它们。


在BIOS/中断级别消除重复字符的方法

看来,该练习是通过中断 9 (IRQ1) 和丢弃重复项。一个新的键盘中断处理程序的想法是在 DOS(以及最终 scanf)看到它们之前消除重复:

  • 在变量中跟踪上一个按下的字符
  • 调用原始(保存的)中断 9,以便 BIOS 更新键盘缓冲区和键盘标志,因为 DOS 期望它们出现。
  • 查询键盘以查看字符是否可用 Int 16h/AH=1h . 如果没有字符可用,零标志 (ZF) 将被设置,如果有可用字符,则零标志 (ZF) 将被设置。此键盘 BIOS 调用会查看键盘缓冲区的开头,而不会实际删除下一个可用字符。
  • 如果一个字符可用,则将其与前一个字符进行比较。
    • 如果它们不同则用当前字符更新前一个字符并退出
    • 如果相同则使用Int 16h/AH=0h从键盘缓冲区中删除重复字符并退出

代码的 Turbo-C 3.0x 版本4:

#include <stdio.h>
#include <dos.h>
#include <string.h>
#include <conio.h>

volatile char key = 0;
void interrupt (*Int9save)(void);

void interrupt kill_multiple_press(void)
{
asm {
PUSHF
CALL DWORD PTR Int9save /* Fake an interrupt call to original handler */

MOV AH, 1 /* Peek at next key in buffer without removing it */
INT 16h
JZ noKey /* If no keystroke then we are finished */
/* If ZF=1 then no key */

CMP AL, [key] /* Compare key to previous key */
JNE updChar /* If characters are not same, update */
/* last character and finish */

/* Last character and current character are same (duplicate)
* Read keystroke from keyboard buffer and throw it away (ignore it)
* When it is thrown away DOS and eventually `scanf` will never see it */
XOR AH, AH /* AH = 0, Read keystroke BIOS Call */

INT 16h /* Read keystroke that has been identified as a */
/* duplicate in keyboard buffer and throw away */
JMP noKey /* We are finished */
}
updChar:
asm {
MOV [key], AL /* Update last character pressed */
}
noKey: /* We are finished */
}

void eliminate_multiple_press()
{
Int9save = getvect(9);
setvect(9, kill_multiple_press);
}

void uneliminate_multiple_press()
{
setvect(9, Int9save);
}

void main()
{
char str[1000];
clrscr();
eliminate_multiple_press();
printf("Enter your string: ");
/* Get a string terminated by a newline. Max 999 chars + newline */
scanf("%999[^\n]s", &str);
printf("\n%s", str);
uneliminate_multiple_press();
}

注意事项

  • 1在键盘中断处理程序中,您希望避免任何会阻止等待键盘输入的键盘 BIOS 调用。如果使用 Int 16h/AH=0 确保首先有一个字符可用 Int 16h/AH=1 否则 Int 16h/AH=0 将在等待另一个角色到达时阻塞。
  • 2删除重复字符与禁用键盘重复率不同。
  • 3因为重复项在 DOS 例程看到它们之前被删除(以及依赖于 DOS 的 scanf 函数),它们永远不会被 scanf
  • 4可能需要进行一些修改才能与 3.0x 以外的 Turbo-C 版本兼容。
  • 5此方法之所以有效,是因为 scanf 将间接进行 BIOS 调用以保持键盘缓冲区清晰。此代码不适用于所有一般情况,尤其是在 BIOS 可能缓冲击键的情况下。为了解决这个问题,键盘中断例程必须删除键盘缓冲区中的所有重复项,而不仅仅是像这段代码那样在头部。
  • 6每次击键占用 BIOS 键盘缓冲区(BDA)中的 2 个字节的空间。 32 个字节中有 2 个丢失,因为它们用于检测键盘缓冲区是满的还是空的。这意味着 BIOS 可以缓冲的最大击键次数为 15。

关于c - 当我按下键盘上的键时如何防止重复的字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51911808/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com