The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: dedndave on April 12, 2011, 03:05:35 PM

Title: Keyboard Help - ALT Key
Post by: dedndave on April 12, 2011, 03:05:35 PM
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 ?


Title: Re: Keyboard Help - ALT Key
Post by: Neil on April 12, 2011, 03:24:01 PM
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?
Title: Re: Keyboard Help - ALT Key
Post by: MichaelW on April 12, 2011, 05:27:49 PM
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

Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 12, 2011, 06:19:53 PM
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
Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 12, 2011, 07:11:01 PM
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
Title: Re: Keyboard Help - ALT Key
Post by: baltoro on April 12, 2011, 07:42:23 PM
:eek
Title: Re: Keyboard Help - ALT Key
Post by: MichaelW on April 13, 2011, 12:43:14 AM
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?

Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 13, 2011, 01:24:26 AM
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
Title: Re: Keyboard Help - ALT Key
Post by: MichaelW on April 13, 2011, 04:20:17 AM
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.


Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 13, 2011, 05:28:56 AM
thanks Michael   :U
i will see if i can get these messages to work - if not, i'll try your hook
Title: Re: Keyboard Help - ALT Key
Post by: Tight_Coder_Ex on April 13, 2011, 05:55:44 AM
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.
Title: Re: Keyboard Help - ALT Key
Post by: 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?
Title: Re: Keyboard Help - ALT Key
Post by: hutch-- on April 13, 2011, 07:13:43 AM
Try trapping either WM_KEYUP or WM_KEYDOWN in the message loop to get the ALT key.
Title: Re: Keyboard Help - ALT Key
Post by: Tight_Coder_Ex on April 13, 2011, 04:09:17 PM
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.
Title: Re: Keyboard Help - ALT Key
Post by: MichaelW on April 13, 2011, 05:29:23 PM
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


Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 13, 2011, 05:39:31 PM
yes - the toggle action that you are speaking of is the keyboard access to the menu
if you will notice, the "File" menu highlights the first time you press (and release) the ALT key
the next time, it turns off - that is why i am looking at the menu messages

i modified my little program to display message values (as well as hWnd, wParam, lParam)
so - i can trap certain messages and display others, filtering out the ones i do not want to see
that is how i found the menu messages listed above

Hutch -
see my original post   :P
Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 13, 2011, 06:47:20 PM
on a side-note   :P

i was filtering out unwanted messages
and i thought i would share this little tid-bit
the window proc receives hundreds or thousands of the following messages...

WM_SETCURSOR
WM_CTLCOLORSCROLLBAR
WM_ENTERIDLE
WM_NCHITTEST
WM_NCMOUSEMOVE

had to filter those out just to make sense of the rest of them
i may leave some of them in there - lol
Title: Re: Keyboard Help - ALT Key
Post by: jj2007 on April 13, 2011, 09:16:02 PM
Quote from: Tight_Coder_Ex on April 13, 2011, 04:09:17 PM
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.

MSDN (http://msdn.microsoft.com/en-us/library/ms646301%28v=vs.85%29.aspx):
QuoteReturn Value

Type: SHORT

The return value specifies the status of the specified virtual key, as follows:

    * If the high-order bit is 1, the key is down; otherwise, it is up.
    * If the low-order bit is 1, the key is toggled
The high-order bit of a SHORT is bit 15, or, if you want it even "shorter", bit 7 of ah.
The low-order bit of a SHORT is bit 0 of ax or al.
Title: Re: Keyboard Help - ALT Key
Post by: oex on April 13, 2011, 09:41:46 PM
FYI My middle mouse button doesnt work properly :lol

I say this not only to divert attention from the inevitable doom of the human race but also because I find it somewhat annoying when someone writes a progam and their 'clever' mouse wheely function prevents me from using their application :lol.... I dont know why my mouse middle wheel doesnt work, the button clicks but it doesnt scroll when I wheel it but it's not the first mouse I have had the problem and sometimes mice dont even have middle buttons ::).... This isnt really a bug, more like a mouse trap but if you are writing a sqeeky clean final application you might want an alternative key combo :lol
Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 14, 2011, 02:53:23 AM
if i get it figured out, Peter, you'll be the first to test it for me   :bg
i actually have some time to play with it, tonight
Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 14, 2011, 01:14:30 PM
it looks like i can reset the mouse wheel step counter upon receiving any of the following and have working code:

WM_SETFOCUS
WM_KEYDOWN
WM_KEYUP
WM_SYSKEYDOWN
WM_SYSKEYUP
WM_ENTERMENULOOP
WM_EXITMENULOOP

i exit via DefWindowProc for these, unless i was to otherwise process them
WM_SYSKEYDOWN and WM_SYSKEYUP require it
and, i imagine it's a good idea for the menu messages for the same reason
Title: Re: Keyboard Help - ALT Key
Post by: dedndave on April 15, 2011, 06:23:48 PM
well - in the end, i decided to forego the ALT-wheel feature
the above works, but it conflicts with the ux guide definition
i got the idea by playing with firefox, i think
i should know that the mozilla guys don't read the ux guide   :P