2013-02-28 53 views
-1

我正在处理的一个简单程序(用于作业)要求我将键击作为输入并返回它所属的类别(它是可打印的字符,十进制等)。在NASM中,我想根据其ASCII值比较输入击键

我正在使用cmp比较击键与最大值和/或最小值的类别(例如,如果击键的ASCII码高于0x7F,那么它是一个可打印的字符)

但是,显然有一些东西在我的比较中不起作用,因为无论如何,即当我使用退出按钮作为输入时,它不打印“控制键”。

难道是密钥需要一些更多的处理之前,他们可以根据ASCII值进行比较?

这里是我的代码

segment .data 
    controlKey: db "Control Key", 10 
    controlLen: equ $-controlKey 

    printableKey: db "Printable", 10 
    printableLen: equ $-printableKey 

    decimalKey: db "Decimal", 10 
    decimalLen: equ $-decimalKey 

segment .bss 

    key resb 2 

segment .text 

    global main 
main: 
    mov eax, 3 ; system call 3 to get input 
    mov ebx, 0 ; standart input device 
    mov ecx, key ; pointer to id 
    mov edx, 2 ; take in this many bytes 
    int 0x80  

control:  ; check if it's a control key 
    mov ebx, 31 ; highest control key 
    mov edx, key 
    cmp edx, ebx 
    jg printable 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, controlKey 
    mov edx, controlLen 
    int 0x80 
    ; jmp exit ; It's obviously not any of the other categories 

printable: ; Tell that it's a printable symbol 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, printableKey 
    mov edx, printableLen 
    int 0x80 
decimal: 
    mov ebx, 30h ; smallest decimal ASCII 
    mov edx, key 
    cmp edx, ebx 
    jl uppercase 
    mov ebx, 39h ; test against 9 
    cmp edx, ebx 
    jg uppercase 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, decimalKey 
    mov edx, decimalLen 
    int 0x80 

uppercase: 
lowercase: 



    mov eax, 4 ; system call 4 for output 
    mov ebx, 1 ; standard output device 
    mov ecx, key ; move the content into ecx 
    mov edx, 1 ; tell edx how many bytes 
    int 0x80 ; 

exit: 
    mov eax, 1 
    xor ebx, ebx 
    int 0x80 

回答

0

Escape键不会被你的应用程序读取,因为它是 - 最有可能 - 用您的应用程序在运行终端抓住了,我可以看到你”。在你的代码中重新使用了系统调用read,这当然很好,但是你应该记住,这个函数只提供了一个文件描述符的读取,它不一定包含从键盘发送的所有控制信号。文件描述符(stdin)甚至不必来自键盘的,因为文件可能被重定向到您的进程作为标准输入。

我不知道是否有实现的一个很好的方式(捕捉按键,而不是数据,他们代表 - 这是你现在在做什么)你现在要做的只是什么系统调用在Linux中。你可以尝试使用一些终端控制库,例如ncursestermios,但我想这不是你的任务的一部分。

+0

当我在程序运行时按下逃脱按钮时,它确实会读取它,但我已确认 – CodyBugstein 2013-02-28 23:11:45

+0

奇怪,我无法重现该行为。 – 2013-02-28 23:12:52

+0

运行该程序,并在输入提示符下按下转义键,您将得到一个像^这样的字符[ – CodyBugstein 2013-02-28 23:23:01

0

我已经做了一段时间后,这里是一个示例来展示如何打开/关闭字符回声,以及开启/关闭规范模式。在运行时,当您按下一个键,键码会显示在屏幕上,程序会退出一次Shift + Q键被按下:

terminos.asm

ICANON  equ 1<<1 
ECHO  equ 1<<3 

sys_exit equ 1 
sys_read equ 3 
sys_write equ 4 
stdin  equ 0 
stdout  equ 1 


global _start 

SECTION  .bss 
lpBufIn  resb 2 
lpBufOut resb 2 
termios  resb 36 

section .text 
_start: 
    call echo_off 
    call canonical_off 

.GetCode:  
    call GetKeyCode 
    movzx esi, byte[lpBufIn] 
    push esi 
    call PrintNum 
    pop  esi 
    cmp  esi, 81 
    jne  .GetCode 

    call echo_on 
    call canonical_on 

    mov  eax, sys_exit 
    xor  ebx, ebx 
    int  80H 

;~ ######################################### 
GetKeyCode: 
    mov  eax, sys_read 
    mov  ebx, stdin 
    mov  ecx, lpBufIn 
    mov  edx, 1 
    int  80h 
    ret 

;~ ######################################### 
canonical_off: 
     call read_stdin_termios 

     ; clear canonical bit in local mode flags 
     mov eax, ICANON 
     not eax 
     and [termios+12], eax 

     call write_stdin_termios 
     ret 

;~ ######################################### 
echo_off: 
     call read_stdin_termios 

     ; clear echo bit in local mode flags 
     mov eax, ECHO 
     not eax 
     and [termios+12], eax 

     call write_stdin_termios 
     ret 

;~ ######################################### 
canonical_on: 
     call read_stdin_termios 

     ; set canonical bit in local mode flags 
     or dword [termios+12], ICANON 

     call write_stdin_termios 
     ret 

;~ ######################################### 
echo_on: 
     call read_stdin_termios 

     ; set echo bit in local mode flags 
     or dword [termios+12], ECHO 

     call write_stdin_termios 
     ret 

;~ ######################################### 
read_stdin_termios: 
     mov eax, 36h 
     mov ebx, stdin 
     mov ecx, 5401h 
     mov edx, termios 
     int 80h 
     ret 

;~ ######################################### 
write_stdin_termios: 
     mov eax, 36h 
     mov ebx, stdin 
     mov ecx, 5402h 
     mov edx, termios 
     int 80h 
     ret 

PrintNum: 
    push lpBufOut 
    push esi 
    call dwtoa 

    mov  edi, lpBufOut 
    call GetStrlen 
    inc  edx 
    mov  ecx, lpBufOut 
    mov  eax, sys_write 
    mov  ebx, stdout 
    int  80H  
    ret  

;~ ######################################### 
GetStrlen: 
    push ebx 
    xor  ecx, ecx 
    not  ecx 
    xor  eax, eax 
    cld 
    repne scasb 
    mov  byte [edi - 1], 10 
    not  ecx 
    pop  ebx 
    lea  edx, [ecx - 1] 
    ret 

;~ #########################################  
dwtoa: 
;~ number to convert = [ebp+8] 
;~ pointer to buffer that receives number = [ebp+12] 
    push ebp 
    mov  ebp, esp 

    push ebx 
    push esi 
    push edi 

    mov  eax, [ebp + 8] 
    mov  edi, [ebp + 12] 

    test eax, eax 
    jnz  .sign 

.zero: 
    mov  word [edi], 30H 
    jmp  .done 

.sign: 
    jns  .pos 
    mov  byte [edi], "-" 
    neg  eax 
    add  edi, 1 

.pos: 
    mov  ecx, 3435973837 
    mov  esi, edi 

.doit: 
    mov  ebx, eax 
    mul  ecx 
    shr  edx, 3 
    mov  eax, edx 
    lea  edx, [edx * 4 + edx] 
    add  edx, edx 
    sub  ebx, edx 
    add  bl, "0" 
    mov  [edi], bl 
    add  edi, 1 
    cmp  eax, 0 
    jg  .doit 

    mov  byte [edi], 0 

.fixit: 
    sub  edi, 1 
    mov  al, [esi] 
    mov  ah, [edi] 
    mov  [edi], al 
    mov  [esi], ah 
    add  esi, 1 
    cmp  esi, edi 
    jl  .fixit 

.done:  
    pop  edi 
    pop  esi 
    pop  ebx 

    mov  esp, ebp 
    pop  ebp 
    ret  4 * 2 

的makefile

APP = terminos 
$(APP): $(APP).o 
    ld -o $(APP) $(APP).o 
$(APP).o: $(APP).asm 
    nasm -f elf $(APP).asm 
+0

有一个更简单的方法...也需要在程序中,而不是依赖于用户如何输入 – CodyBugstein 2013-03-01 02:00:51

+0

得到一个更简单的方法?!?!?!然后使用高级语言! – Gunner 2013-03-01 02:01:34

+0

哈哈!就像我说的,这是作业,我没有选择做这件事。我知道有一种更简单的方法,因为解决方案应该简单明了,只需要初学者的知识。 – CodyBugstein 2013-03-01 02:18:53