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 ?
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?
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
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
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
:eek
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?
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
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.
thanks Michael :U
i will see if i can get these messages to work - if not, i'll try your hook
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.
Are you sure it shouldn't be bt eax, 15? And bit eax, 0 for toggled keys?
Try trapping either WM_KEYUP or WM_KEYDOWN in the message loop to get the ALT key.
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.
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
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
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
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.
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
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
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
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