News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Detect or Get Keypress

Started by raleep, March 12, 2015, 01:14:58 PM

Previous topic - Next topic

raleep

I apologise for not doing more research on my own.  I have searched MSDN, but the simple (I think) information I want seems to be buried in masses of what is not immediately useful to me.

I think GetAsyncKeyState would do it if invoked once for each key (as well as once at the start of the routine I want to pause).

I am looking for a function that when called will return when and only when (although a forced return would also be nice) a key is pressed - any key.

Can anyone suggest an answer or a direction for further research?

Thank you - Robert Leeper

raleep

Quote from: raleep on March 12, 2015, 01:14:58 PM
I am looking for a function that when called will return when and only when (although a forced return would also be nice) a key is pressed - any key.
Never mind about the forced return - I see how to do [something like] that.

dedndave

if you're talking about console-mode programs, i suggest crt__getch
it's part of the msvcrt library
but, the console is buggish, and the library often yields best results

for GUI-mode programs, you write a handler in WndProc
it activates when a key is pressed, but allows other processing when no key is in the buffer

rrr314159

Hello raleep,

Don't really think this is what you want but at least it's a starting point

include \masm32\include\masm32rt.inc

.data
    thechar db 0, 0
    format db 'You pressed %s',10,0
.code

start:
    print "Press any key, ctrl-C to exit", 10, 0
    @@:
        call wait_key
        mov thechar, al
        invoke crt_printf, ADDR format, ADDR thechar
    jmp @B
    ret

end start


Assume you know how to run this with masm32

wait_key is using the function dedndave mentioned, crt__getch, and can be found in \masm32\m32lib\wait_key.asm

I am NaN ;)

MichaelW

Assuming that your goal here is to detect key presses in your app, and not in other apps, crt__getch is easy, and while it cannot detect "any" key it can detect all but the shift and toggle keys.

Edit: modified code to display the return value as a number and a character.

;===============================================================================
include \masm32\include\masm32rt.inc
;===============================================================================
.data
.code
;=============================================================================== 
start: 
;===============================================================================     
  @@:
    invoke crt__getch
    cmp   eax, "X"
    je    @F
    cmp   eax, "x"
    je    @F
    printf("%d\t%c\n",eax,eax)
    jmp   @B
  @@: 
    inkey
    exit
end start
;===============================================================================


Well Microsoft, here's another nice mess you've gotten us into.

dedndave

hi Michael,

as i recall, _getch IS capable of detecting all keys except system keys (ALT-?) and CTRL-C (CTRL-Break)
if you want to detect CTRL-Break, install a handler for it

if it returns 0 or 0E0h on the first call, it must be called again (arrow keys, function keys, etc)
very similar to how the old 16-bit INT 16h worked

here is a function that returns immediately if no key has been pressed (non-blocking)
it's one i have used often
give me a few minutes, and i can adapt it to a blocking function

;*************************************************************************

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
        shl     eax,8
        or      eax,edx

InKyb1: retn

InKyb   ENDP

;*************************************************************************

dedndave


MichaelW

Dave, from a 32-bit app running under Windows 7-64 the _getch function does not return until you press a non-toggle or non-shift key. And, one that I forgot to test, it does not return when you press the Pause/Break key. The arrow and function keys work as you describe, returning 0E0h ahead of the arrow keys and 0 ahead of the function keys.

MSDN _getch _getwch

And your app behaves the same way, not responding to the shift, toggle, or Pause/Break keys.
Well Microsoft, here's another nice mess you've gotten us into.

dedndave

that's strange
under XP (32-bit), shift , caps lock, and num lock work as expected
even many of the CTRL keys work

ALT keys are system keys, which msvcrt authors chose not to override - understandably

MichaelW

The key combinations involving the shift and toggle keys, or at least the ones that I tested, work as expected. _getch, like most or all high-level input functions, does not meet the "any key" requirement because it does not detect the shift or toggle keys when they are pressed as single keys. Perhaps I should have interpreted "any key" as "any normal key".

Well Microsoft, here's another nice mess you've gotten us into.

dedndave

you can use one of the console API functions to "get any key"
really, i try not to spend too much time on it, because the console is buggish
no matter what you do, you get buggish behavior   :P

to me, it works fine for simple test programs or tools in "teletype" fashion
i.e., print a line, get a line - no fancy cursor movement stuff

dedndave

here's one that uses ReadConsoleInput...

;***********************************************************************************************

AnyKey  PROC

;Wait for Any Console Key Press - DednDave
;version 1, 12-2011
;version 2, 2-2013
;
;  This function returns when any console key is pressed (bKeyDown = 1).
;A possible drawback is that all input event records are removed from
;the console input queue until a key is pressed. In many cases, this is
;not an issue. The virtual key code, virtual scan code, TCHAR character,
;and control key state values are returned in registers.

;Call With: Nothing
;
;  Returns: EAX = TCHAR character (high word of EAX = 0)
;           ECX = control key state flags
;               Bit   Name                Meaning
;                0    RIGHT_ALT_PRESSED   Right ALT key is pressed
;                1    LEFT_ALT_PRESSED    Left ALT key is pressed
;                2    RIGHT_CTRL_PRESSED  Right CTRL key is pressed
;                3    LEFT_CTRL_PRESSED   Left CTRL key is pressed
;                4    SHIFT_PRESSED       SHIFT key is pressed
;                5    NUMLOCK_ON          NUM LOCK light is on
;                6    SCROLLLOCK_ON       SCROLL LOCK light is on
;                7    CAPSLOCK_ON         CAPS LOCK light is on
;                8    ENHANCED_KEY        Key is enhanced
;           EDX:
;           low word (DX) = virtual key code
;               high word = virtual scan code
;
;           all other registers are preserved

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

    LOCAL   ir          :INPUT_RECORD
    LOCAL   uRecCnt     :UINT
    LOCAL   hStdInp     :HANDLE

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

    INVOKE  GetStdHandle,STD_INPUT_HANDLE
    mov     hStdInp,eax
    .repeat
        INVOKE  ReadConsoleInput,hStdInp,addr ir,1,addr uRecCnt
        movzx   ecx,word ptr ir.EventType
        mov     edx,dword ptr ir.KeyEvent.wVirtualKeyCode
    .until (ecx==KEY_EVENT) && (ecx==ir.KeyEvent.bKeyDown) && (dx!=VK_SHIFT) && (dx!=VK_CONTROL) && (dx!=VK_MENU)
    movzx   eax,word ptr ir.KeyEvent.UnicodeChar
    mov     ecx,ir.KeyEvent.dwControlKeyState
    ret

AnyKey  ENDP

;***********************************************************************************************


it doesn't mention it, but that one is UNICODE aware, i think

notice that you can modify this line to customize behaviour for different key sets

    .until (ecx==KEY_EVENT) && (ecx==ir.KeyEvent.bKeyDown) && (dx!=VK_SHIFT) && (dx!=VK_CONTROL) && (dx!=VK_MENU)

raleep

Quote from: dedndave on March 12, 2015, 02:07:17 PM
if you're talking about console-mode programs, i suggest crt__getch
it's part of the msvcrt library
but, the console is buggish, and the library often yields best results

for GUI-mode programs, you write a handler in WndProc
it activates when a key is pressed, but allows other processing when no key is in the buffer

sbrtst_test:
call beep0
pushad
call wosw
invoke crt__getch
popad
   jmp sbrtst_test


This doesn't work for me; it just goes on beeping until stopped.

jj2007

Old-fashioned but seems to work:

include \masm32\include\masm32rt.inc

.data?
kb1 db 256 dup(?)
kb2 db 256 dup(?)

.code
start:
  mov esi, offset kb1
  mov edi, offset kb2
  .Repeat
invoke GetKeyboardState, esi
.Repeat
invoke Sleep, 1
invoke GetKeyState, VK_SHIFT
invoke GetKeyboardState, edi
mov ecx, 255
push esi
push edi
repe cmpsb
pop edi
pop esi
.Until sdword ptr ecx>0
neg cl
sub cl, 2
.Break .if ecx==VK_ESCAPE
print str$(ecx), " was pressed", 13, 10
  .Until 0
  print "bye"
  exit
end start


dedndave

sbrtst_test:
call beep0
pushad
call wosw
invoke crt__getch
popad
   jmp sbrtst_test


that code will continually loop and beep whenever a key is pressed

first of all, the PUSHAD/POPAD preserves and restores all the registers, including EAX
crt__getch returns a value in EAX that should be tested for key-presses (destroyed by POPAD)
and - you don't display that value

also, the loop ends with an unconditional branch back to the top
you may way to use a conditional branch, instead