News:

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

Recommendations for keyboard interpretation

Started by zemtex, August 13, 2011, 07:59:47 PM

Previous topic - Next topic

zemtex

I know this forum doesn't like the term keyboard hooks very much, I have great experience with it so I will not ask anything about it. My question however is if RawInput can be a good replacement using the RIDEV_INPUTSINK flag in terms of speed. I find that global hooks can be somewhat slow.
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

dedndave

we have had many uses for keyboard hooks   :P
so - are you thinking of processing keyboard data as raw ?

zemtex

I will not label you butler, but I somehow knew you would be the one to come first  :lol

dave, raw yes. I am considering that for now. I only need a single hotkey while the program is resting in the background. I don't really want to use global hooks for that, global hooks is not only unreliable but very slow too. Don't get me wrong I've already written the library, I just haven't changed the flag to RIDEV_INPUTSINK and tested that yet. Wondering if it will work and if it is fast.
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

Tedd

Any global hook is going to slow down the entire system as all messages for all windows are filtered through it.

You should be able to use GetAsyncKeyState to just check the key combination you want - it doesn't require that you have keyboard focus.

However, if you put it in a flat polling loop, you should add a Sleep so it doesn't eat 99% cpu time.
(It may seem this is doing too much work, but a global hook still processes EVERY message, so it's possibly even less.)

  @@:
    invoke Sleep, 300
    invoke GetAsyncKeyState, VK_Q
    test eax,1
    jz @B
    invoke MessageBeep, MB_ICONEXCLAMATION

300ms gives a good enough response time, and testing the low bit indicates whether key was pressed since the previous call to GetAsyncKeyState.
No snowflake in an avalanche feels responsible.

zemtex

#4
GetASyncKeyState should not be used as it is unreliable, I've been into the thought of using it but it is very unreliable. I appreciate the help though  :U

If you only need a single hotkey it seems to me that solutions like rawinput (and getasynckeystate) is the only practical solution. I've used global hooks for a while and it is not worth injecting a dll into every process on the system, just to get a single hotkey. It becomes extremely vounerable, it depends on all applications and that they continue to pass the hook, very risky.

I will try your solution if my rawinput solution doesn't work first.
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

dedndave

have you looked into the possibility of using a keyboard accelerator ???
i used them with my MDI window, and they were surprisingly simple to create
the message loop was a little hairy, at first - but not that bad

in the resource file....
#define  IDM_FILEEXIT                        1000
#define  IDA_ACC                             999

IDA_ACC  ACCELERATORS
  BEGIN
    "X",  IDM_FILEEXIT,  VIRTKEY,  CONTROL,  NOINVERT  ;Ctrl-X key
  END

i am sure there is a way to create the accelerator with code, rather than in resource

the accelerators are loaded in WM_CREATE...
        INVOKE  LoadAccelerators,hInstance,IDA_ACC
        mov     hAccel,eax


then, in the message loop...
;EDI = 0
;EBP = offset MSG structure

        jmp short mLoop1

mLoop0: INVOKE  TranslateAccelerator,hWin,hAccel,ebp
        or      eax,eax
        jnz     mLoop1
   
        INVOKE  TranslateMessage,ebp
        INVOKE  DispatchMessage,ebp

mLoop1: INVOKE  GetMessage,ebp,edi,edi,edi
        inc     eax                                         ;exit only
        shr     eax,1                                       ;if 0 or -1
        jnz     mLoop0

this message loop is a simplified version of the MDI loop

after that, the hotkey generates a WM_COMMAND message, like selecting a menu item
the difference is, bit 16 of wParam is set to 1 if it comes from an accelerator

if i wanted to write a game that used arrow keys - or something similar, i would probably use accelerators

Geryon

If you can ignore old windows (pre win2k), User32.RegisterHotKey function would define a system-wide hotkey
"Some people have got a mental horizon of radius zero and call it their point of view." --D.Hilbert

zemtex

Old windows can be safely ignored  :U

The problems of all the available methods is that some of them register as keyloggers within specific anti virus programs. Now the rawinput model is only registered as a keylogger with one specific anti virus and is generally considered "unknown method", so it is safer. I am thinking about compatability and "safe".

But I will try your suggestion, I never thought about such a simple thing. It is ingenious that you know about this  :U

EDIT: Please respect the forum rules about "hooks" so that you don't bring up too much code, or else hutch might explode.
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

MichaelW

I didn't have very long to experiment with GetAsyncKeyState, but so far it seems to be very reliable.

;==============================================================================
    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
  L0:
    invoke Sleep, 10
    invoke GetAsyncKeyState, VK_ESCAPE
    test eax, 8000h
    jnz L3
  L1:   ; wait for key press
    invoke GetAsyncKeyState, VK_Z
    test eax, 8000h
    jz  L0
  L2:   ; wait for key release   
    invoke GetAsyncKeyState, VK_Z
    test eax, 8000h
    jnz L2
    inc ebx
    jmp L0
  L3:
    printf( "%d\n", ebx )

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

eschew obfuscation

zemtex

I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

Tedd

Quote from: zemtex on August 14, 2011, 02:43:44 PM
GetASyncKeyState should not be used as it is unreliable, I've been into the thought of using it but it is very unreliable. I appreciate the help though  :U
It only appears unreliable if you test the top bit (which indicates the current state of the key) and don't poll quickly enough, so then you could potentially miss a key-press. This is why I put the lowest bit, which indicates whether the key was pressed at all (since the previous call) - then you don't miss one by not polling quickly enough.
No snowflake in an avalanche feels responsible.

zemtex

No no it is not because of the handling of input, it is due to the polling effect, it drains resources for my taste and if I reduce polling to my level of preference it become unreliable. It's nothing about the handling of the different bits. I already have a working lib for GetASyncKeyState and it works wonderfully, but the polling isn't always wanted in every application. The least significant bit is not reliable btw. Unreliable means that it is not guaranteed to get the keystroke. The polling happens in a "vacuum", while other system methods the keystrokes comes travelling along a pipe and is more reliable. If you have sudden outbursts and cpu gets up 100% for some reason, you might miss keystrokes as well.
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

hutch--

GetAsynchKeyState() is in fact very reliable if you perform the correct bit tests. Main problem is the documentation is a little obscure.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

zemtex

From a user experience it is VERY reliable, technically there is an uncertainty factor that makes it unreliable. For the most part it works wonderfully, I have a good include file with proper bit testing and it is excellent, and it never failed from my experience. If every program would make a program and do keyboard polling it would not be very system friendly. One should design a program with care.
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

Tedd

And if every program set a global hook then it wouldn't be system friendly either. But it's not every program - it's only yours - and it's not all the time - only when yours isn't 'activated.'
There are only a few ways to achieve what you want, and none of them are particularly system friendly.
My suggestion reduces your polling to 3 times a second - that's not too bad.
No snowflake in an avalanche feels responsible.