-1

我正在处理的一个简单程序(用于家庭作业)要求我将击键作为输入并返回它所属的类别(它是可打印的字符、小数等)

我正在使用 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
4

2 回答 2

0

The Escape key won't be read by your application, since it is - most probably - caught by the terminal that your application runs in. I can see that you're using the read syscall in your code, which is, of course, fine, but you should remember that this function only provides reading from a file descriptor, which doesn't necessarily have to contain all the control signals sent from the keyboard. The file descriptor (stdin) doesn't even have to come from the keyboard, since a file might be redirected to your process as standard input.

I don't know if there's a good way of achieving (capturing keystrokes, not the data that they represent - and this is what you're doing now) what you're trying to do just with system calls in Linux. You could try using some terminal controlling library, for example ncurses or termios, but I guess that isn't a part of your assignment.

于 2013-02-28T23:05:25.863 回答
0

我已经这样做了一段时间,这里有一个示例来展示如何打开/关闭字符回显,以及打开/关闭规范模式。运行时,按一个键,屏幕上会显示keycode,按shift+q后程序退出:

终端.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

生成文件

APP = terminos
$(APP): $(APP).o
    ld -o $(APP) $(APP).o
$(APP).o: $(APP).asm
    nasm -f elf $(APP).asm
于 2013-03-01T00:18:23.307 回答