diff --git a/gpii/node_modules/WindowsUtilities/WindowsUtilities.js b/gpii/node_modules/WindowsUtilities/WindowsUtilities.js index 1e320006b..d35dfc71b 100644 --- a/gpii/node_modules/WindowsUtilities/WindowsUtilities.js +++ b/gpii/node_modules/WindowsUtilities/WindowsUtilities.js @@ -595,6 +595,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, @@ -620,6 +622,10 @@ windows.API_constants = { PBT_APMSUSPEND: 0x4, PBT_APMRESUMEAUTOMATIC: 0x12, + // 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 088dd3e75..3c5b780d4 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 with the current volume (0 if there was an error) */ @@ -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"); @@ -287,7 +288,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)); + } + }); }; /** diff --git a/package.json b/package.json index b7c01df3d..8b909a597 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "dependencies": { "edge-js": "10.3.1", "ffi-napi": "2.4.3", - "gpii-universal": "0.3.0-dev.20200604T131823Z.d6fed9a", + "gpii-universal": "javihernandez/universal#4b4f238858a3e0be0ab801703299676cbba1399a", "@pokusew/pcsclite": "0.4.18", "ref": "1.3.4", "ref-struct": "1.1.0", diff --git a/provisioning/NpmInstall.ps1 b/provisioning/NpmInstall.ps1 index 5f9f77eda..40fc00711 100755 --- a/provisioning/NpmInstall.ps1 +++ b/provisioning/NpmInstall.ps1 @@ -24,7 +24,7 @@ Invoke-Command $msbuild "SettingsHelper.sln /p:Configuration=Release /p:Platform # Build the volumeControl solution $volumeControlDir = Join-Path $rootDir "gpii\node_modules\nativeSettingsHandler\nativeSolutions\VolumeControl" -Invoke-Command $msbuild "VolumeControl.sln /p:Configuration=Release /p:Platform=`"x86`" /p:FrameworkPathOverride=`"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1`"" $volumeControlDir +Invoke-Command $msbuild "VolumeControl.sln /p:Configuration=Release /p:Platform=`"x86`"" $volumeControlDir # Build the process test helper $testProcessHandlingDir = Join-Path $rootDir "gpii\node_modules\processHandling\test"