News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

CRT getch aka Masm32 getkey returns odd values for VK_LEFT

Started by jj2007, January 17, 2012, 09:58:09 AM

Previous topic - Next topic

jj2007

Does anybody have a clue why CRT getch returns 75 instead of VK_LEFT when you press the left arrow? There are a couple of others, see below. I am in the process of rolling my own, and get correct values, but I am curious why C behaves differently.

CRT:
VK_F1=  112
VK_F12= 123
VK_LEFT=        37
VK_INSERT=      45
VK_NEXT=        34
Char
59
134
75
82
81

MasmBasic (unpublished version, see code attached):
Char/Virtual key
112/112
123/123
37/37
45/45
34/34

hutch--

Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

QuoteWhen reading a function key or an arrow key, each function must be called twice.
The first call returns 0 or 0xE0, and the second call returns the actual key code.

if AL = 0, it is an "extended" key - read it again to get the keyboard scan code
if AL = 0E0h, it is an "enhanced" key (function keys, etc) - read it again to get the keyboard scan code

if you notice in the following code, i typically put the 0/E0 in AL and the scan code in AH

notice that this routine does not return the shift/alt/ctrl key states
the CRT getch function translates the keys for you, based on the shift states
;--------------------------------------------------------------------------

InKyb   PROC

;Polled Keyboard Input - DednDave 8, 2010
;
;This function returns a keystroke in EAX if there is one in the buffer.
;If the buffer is empty, the function returns immediately.
;
;If the keyboard buffer is empty, AH = 0, AL = 0, ZF = 1.
;If the stroke is a regular key, AH = 0, AL = key char, ZF = 0.
;If the stroke is an extended key, AH = extended key, AL = E0h, ZF = 0.
;If the stroke is a function key, AH = function key, AL = 0, ZF = 0.
;
;ECX, EDX are not preserved.

        call    crt__kbhit
        or      eax,eax
        jz      InKyb1

        call    crt__getch
        and     eax,0FFh
        jz      InKyb0

        cmp     al,0E0h
        jnz     InKyb1

InKyb0: push    eax
        call    crt__getch
        pop     edx
        mov     ah,al
        or      eax,edx

InKyb1: ret

InKyb   ENDP

;--------------------------------------------------------------------------

MichaelW

At least on a US keyboard, for keys that don't have an assigned character, _getch returns 0 or 0E0h on the first call and then the keyboard scan code on the second call.

;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================

printf MACRO format:REQ, args:VARARG
    IFNB <args>
        invoke crt_printf, cfm$(format), args
    ELSE
        invoke crt_printf, cfm$(format)
    ENDIF
    EXITM <>
ENDM

;==============================================================================
    .data
    .code
;==============================================================================
start:
;==============================================================================

    xor ebx, ebx
    .WHILE ebx != 27
        call crt__getch
        mov ebx, eax
        .IF ebx == 0 || ebx == 0E0h
            printf("%Xh (%d)\t", ebx, ebx)
            call crt__getch
            mov ebx, eax
            printf("%Xh (%d)\n", ebx, ebx)
        .ELSE
            printf("%Xh (%d)\n", ebx, ebx)
        .ENDIF
    .ENDW

    inkey "Press any key to exit..."
    exit
;==============================================================================
end start

eschew obfuscation

jj2007

Quote from: hutch-- on January 17, 2012, 11:38:59 AM
It is designed for characters, not control keys.
http://msdn.microsoft.com/en-US/library/078sfkak(v=vs.80).aspx

QuoteThe _getch and _getwch functions read a single character from the console without echoing the character. None of these functions can be used to read CTRL+C. When reading a function key or an arrow key, each function must be called twice; the first call returns 0 or 0xE0, and the second call returns the actual key code.

They don't specify what they mean with "key code", but apparently it's the hardware keyboard scan code, not the virtual key code. Which differs significantly from Windows WM_KEYxxx behaviour, of course. Actually, I remember the arrow values from the days of programming the Atari ST in 68000k Assembler, so it seems keyboard hardware hasn't changed much in the last 25 years :bg

Quote from: MichaelW_getch returns 0 or 0E0h on the first call and then the keyboard scan code on the second call.

Strangely enough, crt_getch uses ReadConsoleInput and translates the virtual key back into a scan code. On Win XP, this happens here:
77C2E793            8B55 08       mov edx, [ebp+8]
...
77C2E7F7            0FB742 08     movzx eax, word ptr [edx+8]
77C2E7FB            74 09         je short 77C2E806


For all printable characters, my version always returns the correct code, i.e. it echoes the typed character when using Print Chr$(eax). Since it is more intuitive to use .if eax==VK_LEFT, I will return the Windows-compatible codes instead of the scan codes.

Thanks to everybody for illuminating me :thumbu

dedndave

yah - i think the getch function is a carry-over from 16-bit days
they tried to maintain compatibility when they made the 32-bit version
so, it behaves very much like the old INT 16h, AH=0 function

the problem that i see is that you are trying to return the shift-key state
this is out of context for a function that translates the keystroke according to shift-key state

jj2007

Quote from: dedndave on January 17, 2012, 01:20:27 PM
the problem that i see is that you are trying to return the shift-key state
this is out of context for a function that translates the keystroke according to shift-key state

A shift only will be ignored, but if you hold shift and press a, Ascii 65 aka "A" will be returned in eax. The virtual key (returned in edx) is 65, shift or not shift.

What doesn't work apparently is Unicode. The Euro key (Alt Gr E) returns 8255, but it doesn't print right. Oh well :(

dedndave

console-mode = imperfect world   :U

i would be more concerned about gui-mode stuff   :P