Sign in to follow this  
Followers 0
sulfurious

SetWindowsHookEx vs _IsPressed

4 posts in this topic

Here is a question for people who know more than I do about this.

I have a mouse driver that allows settings such as speed and acceleration to be changed via registry setting. The driver discovers the changes very quickly, so when you modify the reg value, it is prety much instant.

Playing with RegWrite() shows that a script can easily write/read the values with good speed. This left me with the problem of changing the setting in a more convenient way that most drivers do. Many mice today have DPI buttons, which is nice, but when using something where you want high precision, it is nice to have a low speed and moderate acceleration, yet also be able to change this on-the-fly.

So, I create a small GUI which shows the current value, and obviously lets you change it via buttons. No problem. But, I wanted to make it more efficient, so I made it monitor a keypress using _IsPressed() in a While/EndWhile loop. I used the MouseSetOnEvent UDF to set a scroll up event raise the value by X power, and the scroll down even lower the value by X power.

Later, I started to mess with adding a callback using SetWindowsHookEx. I have made other scripts that use _IsPressed() in a While/EndWhile loop, but those were restricted to working only if a specific WinTitle was active. In this program I am working on, I want a LL hook to be gathered globally, so any program can be running and the callback will work.

I ran into a problem though. It seems that if I use _IsPressed() in the While/EndWhile loop, things become a bit unresponsive. I assume it is because of the constant checking with _IsPressed(). Here is what the main loop looks like

While 1
    Sleep(100)
    If _IsPressed($hotkey_Speed) Then
        If $use_on_the_fly Then
            _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT,'btnUpSpeedClick')
            _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, 'btnDownSpeedClick')
            While _IsPressed($hotkey_Speed)
                Sleep(10)
            WEnd
            _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT)
            _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT)
        ElseIf $use_configs Then
            _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT,'ConfigUp')
            _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, 'ConfigDown')
            While _IsPressed($hotkey_Speed)
                Sleep(10)
            WEnd
            _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT)
            _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT)
        ElseIf $use_presets Then
            _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT,'PresetUp')
            _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, 'PresetDown')
            While _IsPressed($hotkey_Speed)
                Sleep(10)
            WEnd
            _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT)
            _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT)
        EndIf
    ElseIf _IsPressed($hotkey_Accel) Then
        _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT, "btnUpAccelClick")
        _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, "btnDownAccelClick")
        While _IsPressed($hotkey_Accel)
            Sleep(10)
        WEnd
        _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT)
        _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT)
    ElseIf _IsPressed($hotkey_Max) Then
        _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT, "btnUpMaxClick")
        _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, "btnDownMaxClick")
        While _IsPressed($hotkey_Max)
            Sleep(10)
        WEnd
        _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT)
        _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT)
    ElseIf _IsPressed($hotkey_Sens) Then
        _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT, "btnUpSensClick")
        _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, "btnDownSensClick")
        While _IsPressed($hotkey_Sens)
            Sleep(10)
        WEnd
        _MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT)
        _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT)
    EndIf

WEnd

As you can see, every 100ms the script checks, and if it finds the key is pressed, and then "while" the key is pressed, the _MouseSetOnEvent() is called to one of the functions that modify the registry value. The While/EndWhile for sleeping 10ms is a dummy loop that simply ensures the mouse event is not removed until the button has been released.

I notice though that if I start a game while this is running, that doing something like moving forward, where a button is constantly held down, causes a "lag" in mouse movement. Ceasing to press a button alleviates this issue. I know it is becuase of the 10ms pause, but I believe I must have a slight pause in there so the While _IsPressed() does not go off constnatly.

Alternatively, I implemented SetWindowsHookEx and monitored for one of my keypresses that would engage the mouse. Unfortunately, it did not operate as I expected it would. Using the

If $wParam = $WM_KEYDOWN

allowed me to check a VKcode ok, but there was no down/up event, only down. So what happened was I could successfully trap the keypress like I wanted, and apply the _MouseSetOnEvent(), but before I physically release the key, the function returns and then repeats itself.

I used the example from the help files for _WinAPI_SetWindowsHookEx, the only difference is what VKcode I was checking for.

Can anyone give me some pointers on:

1. which implementation would be best suited for a low level keyboard hook

2. if my logic on implementing the _MouseSetOnEvent is proper, by implementing then releasing

3. if SetWindowsHookEx is better, how could I successfully trap and release on the physical press/release.

I am happy to post more code if needed, I kept it short intially.

Sul.

Share this post


Link to post
Share on other sites



I think I figured this out. I used SetWindowsHookEx and used a boolean. The boolean gets set on $WM_KEYDOWN if the vkCode is one of my targets. Then, when $WM_KEYUP is checked, if the boolean is true, it processes to see if the vkCode is one of my targets and if so, it sets to boolean to false. This seems to keep the cpu cycles down much better than using _IsPressed(). I just had to find if $WM_KEYUP was already declared in an include (which it was), as I didn't see it in the example but MSDN referenced it.

If anyone would be willing I would like to PM the code segment to see if there is a way to maximize efficiency, as I know it is likely to have performance issues especially while doing things like gaming where keys are constantly held down.

Sul.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

You probably already know this but GUICtrlCreateSlider() would probably be very convinent for your GUI. it should react to the scroll wheel automatically when it is active too. :)

Best of luck on your script. Sounds intresting as my mouse has DPI settings too (Microsoft SideWinder X5)

Edited by FuryCell

HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code.

Share this post


Link to post
Share on other sites

You probably already know this but GUICtrlCreateSlider() would probably be very convinent for your GUI. it should react to the scroll wheel automatically when it is active too. :)

Best of luck on your script. Sounds intresting as my mouse has DPI settings too (Microsoft SideWinder X5)

Good thinking. I did something close to that. There are 4 parameters that a user would likely change: speed, acceleration, smoothing maximum and sensitivity. Changing them on-the-fly is very convenient to be sure. I allowed a combo box for each value to gather the rate of change, such as .01, .10, .50, etc. A simple button for each parameter allows a reset, increase or decrease by the rate of change.

I used progress bars for each parameter. In this fashion I set a max/min and then show the progress bar and a numeric value on a change, either from button or scroll.

I used to use the original SideWinder, and also have the newer wireless one. They are nice. My goal here is to be able to not have the software needed to control the DPI/speed. It is interesting that when you have a mouse with 3 stock dpi, and you set the speed of the driver, the dpi buttons still toggle the 3 dpi, but you can control the speed. So a DPI of say 2000 offers more "resolution", but now with this driver, across all programs, the speed remains constant according to the driver. It is also interesting that if you start a game, in some you set the mouse speed to 0 as the driver is low level even before direct input, so it provides a very nice feeling. I also implemented separate X and Y for times when I need it.

Thanks for the reply.

Sul.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0