diff --git a/gpii/node_modules/WindowsUtilities/WindowsUtilities.js b/gpii/node_modules/WindowsUtilities/WindowsUtilities.js index 2fc9fe8a8..bf2844554 100644 --- a/gpii/node_modules/WindowsUtilities/WindowsUtilities.js +++ b/gpii/node_modules/WindowsUtilities/WindowsUtilities.js @@ -571,6 +571,8 @@ windows.API_constants = { WM_DISPLAYCHANGE: 0x7e, // https://docs.microsoft.com/windows/desktop/winmsg/wm-themechanged WM_THEMECHANGED: 0x31a, + // https://docs.microsoft.com/windows/win32/inputdev/wm-appcommand + WM_APPCOMMAND: 0x319, // https://docs.microsoft.com/windows/win32/inputdev/wm-activate WM_ACTIVATE: 0x0006, @@ -592,6 +594,10 @@ windows.API_constants = { DBT_DEVICEREMOVECOMPLETE: 0x8004, DBT_DEVTYP_VOLUME: 0x2, + // https://docs.microsoft.com/windows/win32/inputdev/wm-appcommand + APPCOMMAND_VOLUME_DOWN: 9, + APPCOMMAND_VOLUME_UP: 10, + // https://msdn.microsoft.com/library/dd375731 virtualKeyCodes: { VK_LBUTTON: 0x01, // Left mouse button diff --git a/gpii/node_modules/nativeSettingsHandler/nativeSolutions/VolumeControl/VolumeControl/VolumeControl.cpp b/gpii/node_modules/nativeSettingsHandler/nativeSolutions/VolumeControl/VolumeControl/VolumeControl.cpp index 6c4aa8461..776502349 100644 --- a/gpii/node_modules/nativeSettingsHandler/nativeSolutions/VolumeControl/VolumeControl/VolumeControl.cpp +++ b/gpii/node_modules/nativeSettingsHandler/nativeSolutions/VolumeControl/VolumeControl/VolumeControl.cpp @@ -1,99 +1,118 @@ -// VolumeControl.cpp : This file contains the 'main' function. Program execution begins and ends there. -// - -#include "pch.h" -#include -#include -#include - -#include - -// Operation constants -const wchar_t* Get = L"Get"; -const wchar_t* Set = L"Set"; - -int wmain(int argc, wchar_t *argv[]) { - // Payload - std::wstring operation; - float value; - // COM Interfaces - HRESULT hr = NULL; - const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); - const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); - IMMDeviceEnumerator* pEnumerator; - LPVOID pvReserved = NULL; - - if (argc == 2) { - operation = argv[1]; - if (operation != Get) { - std::wcout << L"{ \"code\": \"160\", \"message\": \"EINVAL\" }"; - return 0; - } - } else if (argc == 3) { - operation = argv[1]; - std::wstring strValue = argv[2]; - - // Parse the received string into a float - const wchar_t* start = strValue.c_str(); - wchar_t* end = NULL; - - value = std::wcstof(start, &end); - - if (operation != Set || (value == 0 && end == start)) { - std::wcout << L"{ \"code\": \"160\", \"message\": \"EINVAL\" }"; - return 0; - } - } else { - std::wcout << L"{ \"code\": \"160\", \"message\": \"EINVAL\" }"; - return 0; - } - - hr = CoInitialize(pvReserved); - if (hr != S_OK) { - std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to initialize COM\" }"; - } - - hr = CoCreateInstance( - CLSID_MMDeviceEnumerator, - NULL, - CLSCTX_ALL, - IID_IMMDeviceEnumerator, - (void**)&pEnumerator - ); - if (hr != S_OK) { - std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to initialize COM instance\" }"; - } - - IMMDevice* pAudioDevice; - hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pAudioDevice); - if (hr != S_OK) { - std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to get default audio endpoint\" }"; - } - - IAudioEndpointVolume* pEndpointVolume; - pAudioDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pEndpointVolume); - if (hr != S_OK) { - std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to activate the audio endpoint\" }"; - } - - if (operation == Get) { - float curVolume = 0; - hr = pEndpointVolume->GetMasterVolumeLevelScalar(&curVolume); - if (hr != S_OK) { - std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to get current system volume\" }"; - } else { - std::wcout << L"{ \"Value\": \"" << std::to_wstring(curVolume) << "\" }"; - } - } else { - float curVolume = 0; - hr = pEndpointVolume->SetMasterVolumeLevelScalar(value, NULL); - - if (hr != S_OK) { - std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to set current system volume\" }"; - } else { - std::wcout << L"{ \"Value\": \"" << std::to_wstring(curVolume) << "\" }"; - } - } - - return 0; -} +// VolumeControl.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include "pch.h" +#include +#include +#include + +#include + +// Operation constants +const wchar_t* Get = L"Get"; +const wchar_t* Set = L"Set"; +const wchar_t* SetNear = L"SetNear"; + +int wmain(int argc, wchar_t *argv[]) { + // Payload + std::wstring operation; + float value; + // COM Interfaces + HRESULT hr = NULL; + const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); + const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); + IMMDeviceEnumerator* pEnumerator; + LPVOID pvReserved = NULL; + + if (argc == 2) { + operation = argv[1]; + if (operation != Get) { + std::wcout << L"{ \"code\": \"160\", \"message\": \"EINVAL\" }"; + return 0; + } + } else if (argc == 3) { + operation = argv[1]; + std::wstring strValue = argv[2]; + + // Parse the received string into a float + const wchar_t* start = strValue.c_str(); + wchar_t* end = NULL; + + value = std::wcstof(start, &end); + + if ((operation != Set && operation != SetNear) || (value == 0 && end == start)) { + std::wcout << L"{ \"code\": \"160\", \"message\": \"EINVAL\" }"; + return 0; + } + } else { + std::wcout << L"{ \"code\": \"160\", \"message\": \"EINVAL\" }"; + return 0; + } + + hr = CoInitialize(pvReserved); + if (hr != S_OK) { + std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to initialize COM\" }"; + } + + hr = CoCreateInstance( + CLSID_MMDeviceEnumerator, + NULL, + CLSCTX_ALL, + IID_IMMDeviceEnumerator, + (void**)&pEnumerator + ); + if (hr != S_OK) { + std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to initialize COM instance\" }"; + } + + IMMDevice* pAudioDevice; + hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pAudioDevice); + if (hr != S_OK) { + std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to get default audio endpoint\" }"; + } + + IAudioEndpointVolume* pEndpointVolume; + pAudioDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pEndpointVolume); + if (hr != S_OK) { + std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to activate the audio endpoint\" }"; + } + + if (operation == Get) { + float curVolume = 0; + hr = pEndpointVolume->GetMasterVolumeLevelScalar(&curVolume); + if (hr != S_OK) { + std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to get current system volume\" }"; + } else { + std::wcout << L"{ \"Value\": \"" << std::to_wstring(curVolume) << "\" }"; + } + } else { + float curVolume = 0; + hr = pEndpointVolume->GetMasterVolumeLevelScalar(&curVolume); + + if (operation == SetNear && hr == S_OK) { + // Set the volume to near the target volume, allowing a small amount for the UI to finish the job. + if (abs(value - curVolume) > 0.02) { + value += (value > curVolume) ? -0.02 : 0.02; + } else { + value = curVolume; + } + } + + if (operation == Set || value != curVolume) { + hr = pEndpointVolume->SetMasterVolumeLevelScalar(value, NULL); + } + + if (hr != S_OK) { + std::wcout << L"{ \"code\": \"" << std::to_wstring(hr) << "\", \"message\": \"Failed to set current system volume\" }"; + } else { + float newVolume = 0; + if (pEndpointVolume->GetMasterVolumeLevelScalar(&newVolume) != S_OK) { + newVolume = value; + } + std::wcout << L"{ \"Value\": \"" << std::to_wstring(newVolume) << "\", \"Old\": \"" + << std::to_wstring(curVolume) << "\" }"; + } + } + + return 0; +} diff --git a/gpii/node_modules/nativeSettingsHandler/src/nativeSettingsHandler.js b/gpii/node_modules/nativeSettingsHandler/src/nativeSettingsHandler.js index 03f073b51..3df5fad54 100644 --- a/gpii/node_modules/nativeSettingsHandler/src/nativeSettingsHandler.js +++ b/gpii/node_modules/nativeSettingsHandler/src/nativeSettingsHandler.js @@ -234,7 +234,8 @@ windows.nativeSettingsHandler.SetDoubleClickHeight = function (num) { /** * Function that handles calling the native executable for volume control. * - * @param {String} mode The operation mode, could be either "Set" or "Get". + * @param {String} mode The operation mode, could be either "Set", "SetNear" or "Get". Calling with "SetNear" will + * adjust the volume so it's near the target volume, allowing room for the shell to do the rest. * @param {Number} [num] The value to set as the current system volume. Range is normalized from 0 to 1. * @return {Promise} A promise that resolves on success or holds a object with the error information. */ @@ -246,9 +247,9 @@ windows.nativeSettingsHandler.VolumeHandler = function (mode, num) { var valueBuff; if (mode === "Get") { - valueBuff = child_process.execFileSync(fileName, ["Get"], {}); + valueBuff = child_process.execFileSync(fileName, [mode], {}); } else { - valueBuff = child_process.execFileSync(fileName, ["Set", num], {}); + valueBuff = child_process.execFileSync(fileName, [mode, num], {}); } var strRes = valueBuff.toString("utf8"); @@ -285,7 +286,18 @@ windows.nativeSettingsHandler.GetVolume = function () { * @return {Promise} A promise that resolves on success or holds a object with the error information. */ windows.nativeSettingsHandler.SetVolume = function (num) { - return windows.nativeSettingsHandler.VolumeHandler("Set", num); + return windows.nativeSettingsHandler.VolumeHandler("SetNear", num).then(function (result) { + var current = parseFloat(result); + if (current !== num) { + // Complete the last bit of the change, as though the media keys where used, in order to show the new volume + // on the screen. + var action = current < num + ? windows.API_constants.APPCOMMAND_VOLUME_UP : windows.API_constants.APPCOMMAND_VOLUME_DOWN; + // Send the volume up/down command directly to the task tray (rather than a simulated key press) + gpii.windows.messages.sendMessage("Shell_TrayWnd", windows.API_constants.WM_APPCOMMAND, 0, + windows.makeLong(0, action)); + } + }); }; /**