Nikita Andrasovich
Nikita Andrasovich

Reputation: 13

How to 'silently' get user input from a terminal on Linux?

I need to get user input skipping every second consonant in it. So every second consonant should not be printed out (not just deleted in some process after hitting Enter).

I've got a task from my teacher in assembler language. Currently I'm using NASM on Linux and would like to stick to it.

The problem is that I need to 'overload' user input interrupt and in it I should be able to process that input (skip every second consonant). I've searched the Net and didn't find any suiting answers. Not how to 'catch' user input before buffering and printing it out, nor the way to read a single character without printing it in terminal.

I would like to see an example of replacing (or modifying) the standard input interrupt system call. That would be the ideal case.

The second option is to make your own type of 'handler' getting each char one by one without echoing it and than handling things like Backspace and Enter myself. Just like getch() in Windows C does. (or 0x16 BIOS interrupt).

Upvotes: 1

Views: 358

Answers (1)

Shift_Left
Shift_Left

Reputation: 1243

Here is an example of what I use to retrieve a single keystroke. Keep in mind, functions keys, arrows and others like HOME, PGDN etc return more than one byte and for that reason I read up to 8 bytes so what's left in the input buffer won't become an artifact of the next write. This snippet was designed as a response system to things like;

Continue [Y/N]

Calling process would read character returned in AL. If it's 0x1b (27 dec / ESC) then we know it's one of the extended keys. As an example, F1 would return 0x504f1b in EAX.

USE64

      sys_read      equ      0
      sys_write     equ      1
      sys_ioctl     equ     16

      %define      ICANON      2
      %define        ECHO      8
      %define      TCGETS      0x5401
      %define      TCPUTS      0X5402

            section    .text
    ; =============================================================================
    ; Accept a single key press from operator and return the result that may be
    ; up to 5 bytes in length.

    ;    LEAVE: RAX = Byte[s] returned by SYS_READ
    ; -----------------------------------------------------------------------------

      %define   c_lflag     rdx + 12
      %define      keys     rbp +  8
      %define      MASK     ICANON | ECHO

      STK_SIZE  equ 56              ; Room for 36 byte termios structure

      QueryKey:

            xor     eax, eax
            push    rax             ; This is where result will be stored.

            push    rbp
            mov     rbp, rsp
            sub     rsp, STK_SIZE

            push    r11             ; Modified by SYSCALL
            push    rbx
            push    rdx
            push    rcx
            push    rdi
            push    rsi             ; With size of 56, stack is now QWORD aligned

            mov     edi, eax            ; Equivalent to setting EDI to STDIN
            mov     esi, TCGETS
            lea     rdx, [rbp-STK_SIZE] ; Points to TERMIOS buffer on stack
            mov      al, sys_ioctl
            syscall

            lea     rbx, [c_lflag]
            and     byte [rbx], ~(MASK)
            inc     esi                 ; RSI = TCPUTS
            push    rsi
            mov      al, sys_ioctl
            push    rax
            syscall

       ; Wait for keypress from operator.

            lea     rsi, [keys]         ; Set buffer for input
            push    rdx
            mov     edx, 8              ; Read QWORD bytes max
            mov      al, sys_read
            syscall

NOTE: The code you need could go here

            pop     rdx                 ; Points back to TERMIOS
            pop     rax
            pop     rsi                 ; TCPUTS again
            or      byte [rbx], MASK
            syscall

            pop     rsi
            pop     rdi
            pop     rcx
            pop     rdx
            pop     rbx
            pop     r11

            leave
            pop        rax              ; Return up to 8 characters
            ret

Upvotes: 1

Related Questions