8

When the standard keyboard key to increase the volume is hit on windows, a small window appears in the upper left displaying the volume and possibly information about playing media. I am looking for a way to trigger the window without changing the volume status, preferably in an easy to integrate way with Autohotkey.

  • Quickly press up and then down volume in quick succession? – ifconfig Jul 30 '17 at 01:02
  • @ifconfig, the question specifies "without changing the volume status" I'm wanting this since the native windows keys use increments of 2%, though you can use AHK to increment by 1% (what I want, and toggling up and down the volume rounds off to even numbers, invalidating the 1% change). – Matthew Sundberg Jul 30 '17 at 01:35
  • @MatthewSundberg If that is what you want, then just do it. I am confused as to what you are asking. – ifconfig Jul 30 '17 at 01:38
  • 1
    @ifconfig The end goal is to increment the volume by 1% (using SoundSet, +1) and display the standard volume OSD. I have the volume change working, but it won't trigger the volume display, hence this question. Your suggestion of toggling the volume up and down rounds the volume to an even number, making it impossible to change the volume. Toggling mute, another way to bring up the display causes a blip in the audio. I'm looking for a command or dll or some non-key-input way to bring up the display. – Matthew Sundberg Jul 30 '17 at 01:51
  • As long as you adjust it +-1 volume level after you trigger it, no. – ifconfig Jul 30 '17 at 03:25
  • 2
    @ifconfig, the problem is that if the volume is 12 to start (remember media keys round to even), then you toggle up (rounds it to 14) then down (back to 12), *then* +1 with AHK, for 13, the next time you try to increase the volume by toggling up it rounds to 14, then back down to 12 and then you're back to 13. That's why I'm looking to bypass the media keys to change volume by *only* using the AHK SoundSet, +/-1. Hence the question of how to bring up the volume display "*without changing the volume status*". – Matthew Sundberg Jul 30 '17 at 08:35
  • I don't know if there is a way to just display the window but I do know that the APIs used to interact with the media playback side of things are only available to store applications, not desktop applications. – Anders Aug 03 '17 at 14:34
  • @Anders despite you don't know how to do it, I see it as perfectly valid question. But rather it's WinAPI-related, not AutoHotkey-specific. – LogicDaemon Aug 03 '17 at 16:07
  • 1
    @LogicDaemon I never said it was not valid, I just said that I believe the documented APIs related to it are only available to Modern apps. – Anders Aug 03 '17 at 20:06

4 Answers4

4

Windows 8 introduced the Media​Control class that lets Modern apps hook into the system playback control. In Windows 8.1 and 10 it was replaced by the System​Media​Transport​Controls class.

While it supports "Manual control of the System Media Transport Controls" there does not seem to be a way to show/hide the overlay and certainly not from a desktop app.

Going into undocumented territory I found the class name of the overlay and that lead me to HideVolumeOSD. Unfortunately the class names are rather generic so you probably have to look at the size of the window as well to determine if it is the volume overlay.

I don't know if just showing the window will work, Windows is not expecting it to be visible except in response to keyboard and playback events. The HideVolumeOSD app uses keybd_event (volume up/down) to trigger it but this is problematic as noted in the comments...

Anders
  • 97,548
  • 12
  • 110
  • 164
2

I set up an autohotkey to send volume up, the volume down (For shortcut ctrl+pgdn).

^PgDn::
   Send {Volume_Up}
   Send {Volume_Down}
   return     
Anna Wang
  • 21
  • 2
  • Unfortunately this will disrupt the current volume if set to an odd value, since `Volume_Up` and `Volume_Down` round the current volume then change it by 2, as mentioned in the question comments. For example, from volume 13, `Volume_Up` rounds to 14, then bumps to 16, then the `Volume_Down` sets it to 14, changing it from the initial value. – Matthew Sundberg Nov 30 '21 at 10:13
1

The desired behavior when used with volume control keys can be gotten by storing the current volume, sending a media key press, then updating the volume to the stored value +/- 1 (or +0, if just seeking to display the OSD).

There is an edge case when mimicking Volume_Down when the volume is <=3. The sent Volume_Down keypress triggers the mute, but this can be accommodated for by manually setting the mute to be off afterwards, or by pre-setting the volume to 4, which prevents the rounding to 0. Which method to choose depends upon if you prefer a brief blip of potentially louder sound (pre-set to 4) or a brief mute (disable mute afterwards) when the volume is lowered from <=3 values.

The following code is in AHK v2.

; Prefix with '$' so as to prevent self triggering, since internally sending Volume_Up
$Volume_Up::{
    ; Get the current volume. SoundGetVolume returns a float which often needs rounding
    volume:=Round(SoundGetVolume())
    ; Send the Volume_Up key, so the media display is triggered
    Send "{Volume_Up}"
    ; Indiscriminately set the volume manually to volume+1
    SoundSetVolume(volume+1)
}

; Much the same as above, yet when sending Volume_Down at volumes <=3 the volume
;   is rounded down to 0 which triggers mute. The volume is then set properly,
;   yet remains muted. In order to not hear a cut in the audio, you need to set
;   the volume to 4 when (1<volume<=3) so that the Volume_Down doesn't round it
;   down to 0, or disable the mute afterwards (if volume > 1). This causes a
;   brief volume spike or mute blip, respectively. Currently the volume spike option
;   is uncommented.
$Volume_Down::{
    volume:=Round(SoundGetVolume())

    ; Bumping the volume before sending the Volume_Down to prevent mute blip (if needed)
    if(1 < volume and volume <= 3){
        SoundSetVolume(4)
    }

    Send "{Volume_Down}"
    SoundSetVolume(volume-1)

    ; ; Disable accidental triggering of mute when volume >= 3 after sending Volume_Down
    ; if(volume > 1) {
    ;   SoundSetMute(0)
    ; }
}

To just trigger the OSD as the question asks the following works. Hitting a volume key then quickly resetting the volume will displays it, yet considerations need to be made if currently muted as to prevent a blip of sound. Volume keys are used since double toggling Volume_Mute causes a gap in the sound output.

; Trigger the on screen display of the volume bar by hitting Volume_Up and
;   then quickly resetting the volume. If muted and send Volume_Up, we will
;   hear audio at original volume for a brief second. To prevent this, we
;   can set the volume to 0 and send Volume_Down instead.
^PgUp::{
    volume:=Round(SoundGetVolume())
    muted:=SoundGetMute()

    ; Trigger the display with a volume key (might briefly bump the volume if unmuted)
    if (muted or volume == 0) {
        SoundSetVolume(0)
        Send "{Volume_Down}"
    } else {
        Send "{Volume_Up}"
    }

    ; Reset to the original volume and mute status
    SoundSetMute(muted)
    SoundSetVolume(volume)
}

All of the same code, yet uncommented:

$Volume_Up::{
    volume:=Round(SoundGetVolume())
    Send "{Volume_Up}"
    SoundSetVolume(volume+1)
}

$Volume_Down::{
    volume:=Round(SoundGetVolume())
    if(1 < volume and volume <= 3){
        SoundSetVolume(4)
    }
    Send "{Volume_Down}"
    SoundSetVolume(volume-1)
}

^PgUp::{
    volume:=Round(SoundGetVolume())
    muted:=SoundGetMute()
    if (muted or volume == 0) {
        SoundSetVolume(0)
        Send "{Volume_Down}"
    } else {
        Send "{Volume_Up}"
    }
    SoundSetMute(muted)
    SoundSetVolume(volume)
}
0

Building on Anna Wang's answer (https://stackoverflow.com/a/62012058/3251466).

This will restore the volume even when it was at an odd value.

^PgDn:: ;Ctrl+Page Down
  SoundGet, original_volume
  SendInput {Volume_Down}  
  SoundSet, original_volume
return
sharp-spark
  • 57
  • 1
  • 1
  • 8