Reputation: 1874
Here's my problem.
I wrote a little Volume Control Script to control my volume like windows do with it's Microsoft Keyboard's shortcut.
I have 3 functions. Two to controls volumes and the other one to control the Hold state of the key to continue rise or down my volume
Here's the code.
;//**************************************************
;// Volume Mouse Control
;//**************************************************
VolumeUp(p_numberToDecrease, p_holdToDecrease = true)
{
Send {Volume_Up %p_numberToDecrease%}
if(p_holdtoDecrease)
{
VolumeHoldTreatment("Up")
}
}
VolumeDown(p_numberToDecrease, p_holdToDecrease = true)
{
Send {Volume_Down %p_numberToDecrease%}
if(p_holdtoDecrease)
{
VolumeHoldTreatment("Down")
}
}
VolumeHoldTreatment(p_treatment)
{
Count := 0
Sleep 300
While GetKeyState(A_ThisHotkey,"P")
{
++Count
if(p_treatment == "Up")
{
Send {Volume_Up %Count%}
}
else
{
Send {Volume_Down %Count%}
}
Sleep 25
}
}
When I call the methods in the shortcuts like this ↓, they work correctly.
I can rise up and down my volume.
If I hold the key more then 300ms, the volume will continue rising/downing.
XButton1:: VolumeDown(1)
XButton2:: VolumeUp(1)
But When I add my mute shortcut ↓
XButton1 & XButton2:: Send {Volume_Mute}
XButton2 & XButton1:: Send {Volume_Mute}
The hold behavior don't act normaly. I need to press my Button1/2 two times to call the hold behavior. Why ?
Thanks for your help
Upvotes: 0
Views: 176
Reputation: 4065
The combinations
XButton1 & XButton2:: Send {Volume_Mute}
XButton2 & XButton1:: Send {Volume_Mute}
make XButton1
and XButton2
prefix keys. Prefix keys have a slightly different behaviour. They only fire upon release, which can't be avoided: For example, if you press XButton1
, it is possible that you will press XButton2
, causing the combination to be triggered. Only if you haven't pressed any additional button, XButton1::
will be triggered, and that on the other hand can't be determined before it was released.
To your VolumeHoldTreatment()
function: In this case, a loop with GetKeyState()
isn't necessary. A normal key will continue firing anyway when you hold it down. That's why some people are able to produce the word LOL
with way too many O letters, with only three keystrokes.
Disregarding the mute function, something like this would do exactly the same:
XButton1::Send, {Volume_Down}
XButton2::Send, {Volume_Up}
Avoiding the use of a combination like XButton1 & XButton2
and therewith preventing the occurrence of prefix keys will save you a lot of trouble and can e.g. be accomplished like this:
XButton1::
if( GetKeyState("XButton2") ) {
Send, {Volume_Mute}
} else {
Send, {Volume_Down}
}
return
XButton2::
if( GetKeyState("XButton1") ) {
Send, {Volume_Mute}
} else {
Send, {Volume_Up}
}
return
This will work almost flawlessly: If you hold just one button, it will be triggered again and again, continuously sending Volume_Up
or Volume_Down
. As soon as you press both keys, two things will happen:
{Volume_Mute}
Unfortunately, this comes with two downsides when muting: a) There will always be at least one Volume_Up
or Volume_Down
(even more when you take a really long time pressing the second button) sent before the {Volume_Mute}
is sent. b) If you hold both keys for a long time, {Volume_Mute}
will be sent over and over again; but this at least won't change the outcome.
Update:
The XButton
s indeed show a strange behaviour, namely they don't keep firing when they are held down. Check out this code:
XButton1::
if( GetKeyState("XButton2", "P") ) {
SetTimer, FireVolumeUp, Off
Send, {Volume_Mute}
} else {
SetTimer, FireVolumeDown, 100
}
return
XButton1 Up::
SetTimer, FireVolumeDown, Off
return
XButton2::
if( GetKeyState("XButton1", "P") ) {
SetTimer, FireVolumeDown, Off
Send, {Volume_Mute}
} else {
SetTimer, FireVolumeUp, 100
}
return
XButton2 Up::
SetTimer, FireVolumeUp, Off
return
FireVolumeUp:
Send, {Volume_Up}
return
FireVolumeDown:
Send, {Volume_Down}
return
This has become more similar to your code, but it uses timers
instead of loops, making the script able to execute other code in between timer runs. Also, I'm using XButtonN Up::
hotkeys, leading to more precision in terms of detecting the key release. The rest should be pretty self-explanatory. If you don't want the timers to wait 100 ms before their first run, add a GoSub, FireVolume...
before each SetTimer
.
Upvotes: 2