Skip to content

Commit a152014

Browse files
committed
[STOBJECT] Second round of thoughts on volume button detection
1 parent cf70b4c commit a152014

File tree

1 file changed

+72
-48
lines changed

1 file changed

+72
-48
lines changed

dll/shellext/stobject/volume.cpp

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include "precomp.h"
10+
#include "winuser.h"
1011

1112
#include <mmddk.h>
1213

@@ -174,69 +175,93 @@ HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray * pSysTray)
174175
Volume_IsMute();
175176

176177
// Unmute if volume is increased or unmuted explicitly
177-
if (pSysTray->lpVolCmd)
178-
{
178+
if (!pSysTray->lpVolCmd)
179+
return S_OK;
180+
181+
if (pSysTray->lpVolCmd == APPCOMMAND_VOLUME_UP || pSysTray->lpVolCmd == APPCOMMAND_VOLUME_MUTE)
179182
g_IsMute = pSysTray->lpVolCmd == APPCOMMAND_VOLUME_UP ? FALSE : !g_IsMute;
180183

181-
MIXERCONTROLDETAILS_BOOLEAN mxcdMute = {0};
182-
mxcdMute.fValue = g_IsMute;
184+
MIXERCONTROLDETAILS_BOOLEAN mxcdMute{};
185+
mxcdMute.fValue = g_IsMute;
186+
187+
MIXERCONTROLDETAILS mxcd{};
188+
mxcd.cbStruct = sizeof(mxcd);
189+
mxcd.cChannels = 1;
190+
mxcd.hwndOwner = NULL;
191+
mxcd.dwControlID = g_muteControlID;
192+
mxcd.paDetails = &mxcdMute;
193+
mxcd.cbDetails = sizeof(mxcdMute);
194+
195+
MMRESULT mmres = mixerSetControlDetails((HMIXEROBJ)UlongToHandle(g_mixerId), &mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
196+
197+
if (mmres != MMSYSERR_NOERROR)
198+
{
199+
ERR("Volume_Update failed at updating mute state: %d\n", mmres);
200+
return E_FAIL;
201+
}
202+
203+
if (pSysTray->lpVolCmd == APPCOMMAND_VOLUME_UP || pSysTray->lpVolCmd == APPCOMMAND_VOLUME_DOWN)
204+
{
205+
MIXERLINECONTROLSW mxlc{};
206+
MIXERCONTROLW mxctrl{};
183207

184-
MIXERCONTROLDETAILS mxcd = {0};
185-
mxcd.cbStruct = sizeof(mxcd);
186-
mxcd.cChannels = 1;
187-
mxcd.hwndOwner = NULL;
188-
mxcd.dwControlID = g_muteControlID;
189-
mxcd.paDetails = &mxcdMute;
190-
mxcd.cbDetails = sizeof(mxcdMute);
208+
mxlc.cbStruct = sizeof(mxlc);
209+
mxlc.dwLineID = g_mixerLineID;
210+
mxlc.cControls = 1;
211+
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
212+
mxlc.pamxctrl = &mxctrl;
213+
mxlc.cbmxctrl = sizeof(mxctrl);
191214

192-
MMRESULT mmres = mixerSetControlDetails((HMIXEROBJ)UlongToHandle(g_mixerId), &mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
215+
mmres = mixerGetLineControlsW((HMIXEROBJ)UlongToHandle(g_mixerId), &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
193216

194-
if (mmres)
217+
if (mmres != MMSYSERR_NOERROR)
195218
{
196-
ERR("Volume_Update failed at updating mute state: %d\n", mmres);
219+
ERR("Volume_Update failed retrieving line control: %d\n", mmres);
197220
return E_FAIL;
198221
}
199222

200-
// Update volume depending on pressed button.
201-
if (pSysTray->lpVolCmd != APPCOMMAND_VOLUME_MUTE)
202-
{
203-
MIXERLINECONTROLSW mxlc;
204-
MIXERCONTROLW mxctrl;
205-
206-
mxlc.cbStruct = sizeof(mxlc);
207-
mxlc.dwLineID = g_mixerLineID;
208-
mxlc.cControls = 1;
209-
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
210-
mxlc.pamxctrl = &mxctrl;
211-
mxlc.cbmxctrl = sizeof(mxctrl);
212-
213-
mmres = mixerGetLineControlsW((HMIXEROBJ)UlongToHandle(g_mixerId), &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
223+
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume{};
214224

215-
if (mmres)
216-
{
217-
ERR("Volume_Update failed retrieving line control: %d\n", mmres);
218-
return E_FAIL;
219-
}
225+
mxcd.dwControlID = mxctrl.dwControlID;
226+
mxcd.paDetails = &mxcdVolume;
227+
mxcd.cbDetails = sizeof(mxcdVolume);
220228

221-
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
229+
mmres = mixerGetControlDetailsW((HMIXEROBJ)UlongToHandle(g_mixerId), &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
222230

223-
mxcd.dwControlID = mxctrl.dwControlID;
224-
mxcd.paDetails = &mxcdVolume;
225-
mxcd.cbDetails = sizeof(mxcdVolume);
231+
if (mmres != MMSYSERR_NOERROR)
232+
{
233+
ERR("Volume_Update failed reading current volume: %d\n", mmres);
234+
return E_FAIL;
235+
}
226236

227-
mmres = mixerGetControlDetailsW((HMIXEROBJ)UlongToHandle(g_mixerId), &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
237+
DPRINTF("Volume_Update: Current volume is %d, volume is expected to go %s\n", mxcdVolume.dwValue, pSysTray->lpVolCmd == APPCOMMAND_VOLUME_UP ? "up" : "down");
238+
DPRINTF("Volume_Update: Control step: %u | Bounds: (%u, %u)\n", mxctrl.Metrics.cSteps, mxctrl.Bounds.dwMinimum, mxctrl.Bounds.dwMaximum);
239+
240+
/*
241+
* In perfect conditions, there must be exactly 50 steps when changing volume.
242+
* The formula of mxctrl.Metrics.cSteps * 7, assuming cSteps == 192, gives us 48 whole steps.
243+
* In close to bounds situations we have odd results, so the volume value is explicitly set
244+
* to 65535 or 0 depending on volume change direction.
245+
*/
246+
if (pSysTray->lpVolCmd == APPCOMMAND_VOLUME_UP)
247+
mxcdVolume.dwValue += mxctrl.Metrics.cSteps * 7;
248+
else
249+
mxcdVolume.dwValue -= mxctrl.Metrics.cSteps * 7;
228250

229-
if (mmres)
230-
{
231-
ERR("Volume_Update failed reading current volume: %d\n", mmres);
232-
return E_FAIL;
233-
}
251+
mmres = mixerSetControlDetails((HMIXEROBJ)UlongToHandle(g_mixerId), &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
234252

235-
pSysTray->lpVolCmd = 0;
253+
if (mmres != MMSYSERR_NOERROR)
254+
{
255+
ERR("Volume_Update failed writing current volume: %d\n", mmres);
256+
return E_FAIL;
257+
}
258+
else
259+
{
236260
DPRINTF("Volume_Update: Current volume is %d\n", mxcdVolume.dwValue);
237261
}
238262
}
239263

264+
// Update system tray icon depending on new volume settings
240265
if (pSysTray->lpVolCmd == APPCOMMAND_VOLUME_MUTE || PrevState != g_IsMute)
241266
{
242267
WCHAR strTooltip[128];
@@ -255,10 +280,9 @@ HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray * pSysTray)
255280
pSysTray->lpVolCmd = 0;
256281
return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, strTooltip);
257282
}
258-
else
259-
{
260-
return S_OK;
261-
}
283+
284+
pSysTray->lpVolCmd = 0;
285+
return S_OK;
262286
}
263287

264288
HRESULT STDMETHODCALLTYPE Volume_Shutdown(_In_ CSysTray * pSysTray)

0 commit comments

Comments
 (0)