News:

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

Keyboard Help - ALT Key

Started by dedndave, April 12, 2011, 03:05:35 PM

Previous topic - Next topic

dedndave

i would like to implement mouse wheel scroll
and...
if a CTRL key is held while wheeling, zoom text
if a SHFT key is held while wheeling, page scroll
if an ALT key is held while wheeling, single-line scroll
otherwise, it will scroll according to the SPI_GETWHEELSCROLLLINES and SPI_GETWHEELSCROLLCHARS values

my problem is not so much with handling the wheel messages
it is knowing when keys have changed state   :P
i have read the docs, so i understand the basics
the problem is primarily with the ALT keys
i want to reset the wheel count (steps by 120) whenever the keys change state

my current plan is to simply reset the counter when any of the following are received:

WM_SETFOCUS
WM_KEYDOWN
WM_KEYUP
WM_SYSKEYDOWN (exit via DefWindowProc)
WM_SYSKEYUP (exit via DefWindowProc)

i can get the key states easy enough
but, according to the docs, i don't see that a message is generated when an ALT key changes states

is there a better way to do this ?



Neil

My understanding of the Alt key is that it does send a message but this is ignored by DefWindowProc & is only used by the system, so how you intercept it I don't know. Maybe it sets a flag in lParam?

MichaelW

#2
GetAsyncKeyState seems to reliably detect the Alt key, and you should be able to call it from wherever you are handling the mouse wheel.

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

DlgProc proc hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    SWITCH uMsg

      CASE WM_INITDIALOG

        invoke SetTimer, hwndDlg, 1, 10, 0

      CASE WM_TIMER

        invoke GetAsyncKeyState, VK_MENU
        .IF eax
          invoke SetDlgItemText, hwndDlg, 1000, chr$("Alt")
        .ELSE
          invoke SetDlgItemText, hwndDlg, 1000, chr$("   ")
        .ENDIF

      CASE WM_COMMAND

        SWITCH wParam

          CASE IDCANCEL

            invoke KillTimer, hwndDlg, 1

            invoke EndDialog, hwndDlg, 0

        ENDSW

      CASE WM_CLOSE

        invoke KillTimer, hwndDlg, 1

        invoke EndDialog, hwndDlg, 0

    ENDSW

    xor eax, eax
    ret

DlgProc endp

;==============================================================================
start:
;==============================================================================

    Dialog "Test", "MS Sans Serif",10, \
           WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           1,0,0,100,75,1024

    DlgStatic 0,SS_CENTER or WS_BORDER,34,25,30,10,1000

    invoke GetModuleHandle, NULL

    CallModalDialog eax,0,DlgProc,NULL

    exit
;==============================================================================
end start

eschew obfuscation

dedndave

thanks Michael
but, you are missing the issue
i want to reset the wheel counter whenever an ALT key is pressed or released
because the ALT keys are used for menus and other system stuff, they are not handled the same as other keys

dedndave

it looks like i can reset the counter upon one or more of the following and get what i want
(in addition to those listed above)

WM_INITMENU
WM_MENUSELECT
WM_ENTERMENULOOP
WM_EXITMENULOOP

i had to look at menu messages, not keyboard messages   :P

i need to do some testing to see which are required

baltoro

#5
:eek
Baltoro

MichaelW

Dave,

I was assuming that the count is a scale factor for mouse wheel rotation, and that your app is handling the WM_MOUSEWHEEL notification. What purpose would it serve to change the scale factor other than when the wheel is being rotated?

eschew obfuscation

dedndave

the scale factor depends on the shift-key state
but, it isn't the scale factor that is giving me fits - lol

as an example...
you hold the ALT key down, then rotate the mouse wheel
this causes single-line scrolling
all sounds very simple, right ?

but, if the keys change state - any keys, actually, the wheel count value is reset to 0
you see, i totalize the wheel steps until some total is reached
for single-line scroll, each time the count reaches 120, 120 is subtracted from the stored total,
and the client is scolled by one line

but, if the shift, alt, or control keys change state, the totalizer is reset to 0
WM_KEYUP and WM_KEYDOWN will let you know if the CTRL or SHFT keys change
or, if the ALT key is held down,
WM_SYSKEYUP and WM_SYSKEYDOWN will let you know if the CTRL or SHFT keys change

but, because the ALT keys are used for menus, etc, there is no such message sent
when an ALT key changes state

so - nevermind about the wheel
nevermind about scroll
nevermind about getting the key state asynchronously

tell me what message is sent when the ALT keys change state   :bg

in the end, it probably isn't going to affect operation in a critical way, really
it is just a little bit of "polish" i want to put on the behaviour

MichaelW

#8
I can't find any message that is sent when the Alt key alone changes state, but I did determine that you can intercept the Alt key in a local keyboard hook (at least under Windows 2000). I didn't have time to test this detail, but I think you can get the press/release-state in the hook procedure from lParam.

;==============================================================================
; Build as a console app.
;==============================================================================
    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
      hhk   HHOOK 0
    .code
;==============================================================================

KeyboardProc proc nCode:SDWORD, wParam:WPARAM, lParam:LPARAM
    .IF nCode < 0
      invoke CallNextHookEx, hhk, nCode, wParam, lParam
      ret
    .ENDIF
    .IF lParam & (1 SHL 31)
        printf( "%Xh\trelease\n", wParam )
    .ELSE
        printf( "%Xh\tpress\n", wParam )
    .ENDIF
    ret
KeyboardProc endp

;==============================================================================

DlgProc proc hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    SWITCH uMsg
      CASE WM_COMMAND
        SWITCH wParam
          CASE IDCANCEL
            invoke EndDialog, hwndDlg, 0
        ENDSW
      CASE WM_CLOSE
        invoke EndDialog, hwndDlg, 0
    ENDSW
    xor eax, eax
    ret
DlgProc endp

;==============================================================================
start:
;==============================================================================

    invoke GetCurrentThreadId
    invoke SetWindowsHookEx, WH_KEYBOARD, KeyboardProc, NULL, eax
    mov hhk, eax
    printf( "hhk = %xh\n", eax )

    Dialog "Test", "MS Sans Serif",10, \
           WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           0,0,0,100,75,1024

    invoke GetModuleHandle, NULL
    CallModalDialog eax,0,DlgProc,NULL

    exit
;==============================================================================
end start


Edit: Added code to display the press/release-state.


eschew obfuscation

dedndave

thanks Michael   :U
i will see if i can get these messages to work - if not, i'll try your hook

Tight_Coder_Ex

Quote from: dedndave on April 13, 2011, 01:24:26 AM
tell me what message is sent when the ALT keys change state

There is no such message, but while pressing or doing something that does trigger an event, GetKeyState in the handler can be used to determine the ALT or any combination of control keys.

This is a method I use to determine if I want to scroll forward or backward in response to either TAB or RETURN being pressed.
.if      al == VK_TAB || al == VK_RETURN
push      VK_SHIFT
call        GetKeyState
bt         eax, 7
mov       ecx, CurrentID
This snippet is part of WM_CHAR.  See manual for details on what bits 7 & 1 do.

jj2007

Are you sure it shouldn't be bt eax, 15? And bit eax, 0 for toggled keys?

hutch--

Try trapping either WM_KEYUP or WM_KEYDOWN in the message loop to get the ALT key.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Tight_Coder_Ex

Quote from: jj2007 on April 13, 2011, 06:24:10 AM
Are you sure it shouldn't be bt eax, 15? And bit eax, 0 for toggled keys?
Although not specifically noted in documentation, experimentation or maybe even an example I saw somewhere showed it was the high order of the byte.  This would make sense as if you were to mask that bit with a boolean operator 16 bit, the instruction would be preceded with 66 whereas bytes and dwords would not.

MichaelW

In the message loop for the Alt key I can trap WM_SYSKEYDOWN and WM_SYSKEYUP, with the virtual key code 12h in wParam, but only WM_SYSKEYUP is reliable. There seems to be some sort of toggle acting, where typically every other WM_SYSKEYDOWN message is missing. And this works the same way whether I use IsDialogMessage or TranslateMessage/DispatchMessage.

;==============================================================================
; Build as a console app.
;==============================================================================
    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
      hDlg HWND 0
      msg  MSG  <>
    .code
;==============================================================================

DlgProc proc hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    SWITCH uMsg
      CASE WM_COMMAND
        SWITCH wParam
          CASE IDCANCEL
            invoke DestroyWindow, hwndDlg
        ENDSW
      CASE WM_CLOSE
        invoke DestroyWindow, hwndDlg
      CASE WM_DESTROY
        invoke PostQuitMessage, NULL
    ENDSW
    xor eax, eax
    ret
DlgProc endp

;==============================================================================
start:
;==============================================================================

    Dialog "Test", "MS Sans Serif",10, \
           WS_OVERLAPPED or WS_SYSMENU or WS_VISIBLE or DS_CENTER, \
           0,0,0,100,75,1024

    invoke GetModuleHandle, NULL
    CallModelessDialog eax,0,DlgProc,NULL
    mov hDlg, eax

  msgLoop:

    invoke GetMessage, ADDR msg, 0, 0, 0
    .IF eax != 0
      SWITCH msg.message
        CASE WM_KEYDOWN
          printf( "WM_KEYDOWN\n" )
        CASE WM_KEYUP
          printf( "WM_KEUP\n" )
        CASE WM_SYSKEYDOWN
          printf( "WM_SYSKEYDOWN\t%Xh\n", msg.wParam )
        CASE WM_SYSKEYUP
          printf( "WM_SYSKEYUP\t%Xh\n", msg.wParam )
        DEFAULT
          printf( "%Xh\n", msg.message )
      ENDSW
      invoke IsDialogMessage, hDlg, ADDR msg
      ;invoke TranslateMessage, ADDR msg
      ;invoke DispatchMessage, ADDR msg
      jmp msgLoop
    .ENDIF

    exit
;==============================================================================
end start


eschew obfuscation