Formatting chores (#1441)

* format_sources: exclude 3rd party sources

* format common project

* format leftovers in runner & settings projects

* move source formatting-related files according to #939
This commit is contained in:
Andrey Nekrasov 2020-03-05 13:07:06 +03:00 committed by GitHub
parent 92f64188d5
commit cf1b53831f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 2602 additions and 2220 deletions

View file

@ -20,7 +20,9 @@ $sourceExtensions.Add(".cpp") | Out-Null
$sourceExtensions.Add(".h") | Out-Null
function Get-Dirty-Files-From-Git() {
$staged = & git diff --name-only --diff-filter=d --cached
$repo_root = & git rev-parse --show-toplevel
$staged = & git diff --name-only --diff-filter=d --cached | % { $repo_root + "/" + $_ }
$unstaged = & git ls-files -m
$untracked = & git ls-files --others --exclude-standard
$result = New-Object System.Collections.Generic.List[string]
@ -34,9 +36,10 @@ function Get-Dirty-Files-From-Git() {
if($all) {
$filesToFormat =
Get-ChildItem -Recurse -File src |
Get-ChildItem -Recurse -File ..\src |
Resolve-Path -Relative |
where {$sourceExtensions.Contains((Get-Item $_).Extension)}
where { (Get-Item $_).Directory -notmatch "(Generated Files)|node_modules" -And
$sourceExtensions.Contains((Get-Item $_).Extension)}
}
else {
$filesToFormat = Get-Dirty-Files-From-Git

View file

@ -65,7 +65,8 @@ IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: "BEGIN_TEST_METHOD_PROPERTIES|BEGIN_MODULE|BEGIN_TEST_CLASS|BEGIN_TEST_METHOD"
ForEachMacros: ['TEST_CLASS', 'TEST_METHOD']
MacroBlockBegin: "TEST_METHOD|TEST_CLASS|BEGIN_TEST_METHOD_PROPERTIES|BEGIN_MODULE|BEGIN_TEST_CLASS|BEGIN_TEST_METHOD"
MacroBlockEnd: "END_TEST_METHOD_PROPERTIES|END_MODULE|END_TEST_CLASS|END_TEST_METHOD"
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All

View file

@ -48,14 +48,14 @@ namespace UnitTestsCommonLib
}
}
TEST_CLASS(PowerToyValuesUnitTests)
TEST_CLASS (PowerToyValuesUnitTests)
{
private:
const std::wstring m_json = L"{\"name\":\"Module Name\",\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }";
const std::wstring m_moduleName = L"Module Name";
public:
TEST_METHOD(LoadFromJsonBoolTrue)
TEST_METHOD (LoadFromJsonBoolTrue)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_bool_value(L"bool_toggle_true");
@ -63,7 +63,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(true, *value);
}
TEST_METHOD(LoadFromJsonBoolFalse)
TEST_METHOD (LoadFromJsonBoolFalse)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_bool_value(L"bool_toggle_false");
@ -71,7 +71,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, *value);
}
TEST_METHOD(LoadFromJsonInt)
TEST_METHOD (LoadFromJsonInt)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_int_value(L"int_spinner");
@ -79,7 +79,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(10, *value);
}
TEST_METHOD(LoadFromJsonString)
TEST_METHOD (LoadFromJsonString)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_string_value(L"string_text");
@ -89,7 +89,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(expected, *value);
}
TEST_METHOD(LoadFromJsonColorPicker)
TEST_METHOD (LoadFromJsonColorPicker)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
auto value = values.get_string_value(L"color_picker");
@ -99,19 +99,19 @@ namespace UnitTestsCommonLib
Assert::AreEqual(expected, *value);
}
TEST_METHOD(LoadFromEmptyString)
TEST_METHOD (LoadFromEmptyString)
{
auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L""); };
Assert::ExpectException<winrt::hresult_error>(func);
}
TEST_METHOD(LoadFromInvalidString_NameMissed)
TEST_METHOD (LoadFromInvalidString_NameMissed)
{
auto func = [] { PowerToyValues values = PowerToyValues::from_json_string(L"{\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }"); };
Assert::ExpectException<winrt::hresult_error>(func);
}
TEST_METHOD(LoadFromInvalidString_VersionMissed)
TEST_METHOD (LoadFromInvalidString_VersionMissed)
{
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}}");
const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}";
@ -121,7 +121,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(LoadFromInvalidString_PropertiesMissed)
TEST_METHOD (LoadFromInvalidString_PropertiesMissed)
{
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }");
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"version\" : \"1.0\" }";
@ -131,7 +131,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(LoadFromValidString_EmptyProperties)
TEST_METHOD (LoadFromValidString_EmptyProperties)
{
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {}, \"version\" : \"1.0\" }");
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }";
@ -141,7 +141,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(LoadFromValidString_ChangedVersion)
TEST_METHOD (LoadFromValidString_ChangedVersion)
{
PowerToyValues values = PowerToyValues::from_json_string(L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"2.0\"}");
const std::wstring expectedStr = L"{\"name\" : \"Module Name\", \"properties\" : {},\"version\" : \"1.0\"}"; //version from input json is ignored
@ -152,7 +152,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(CreateWithName)
TEST_METHOD (CreateWithName)
{
PowerToyValues values(m_moduleName);
const std::wstring expectedStr = L"{\"name\":\"Module Name\",\"properties\" : {},\"version\" : \"1.0\" }";
@ -163,7 +163,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(AddPropertyBoolPositive)
TEST_METHOD (AddPropertyBoolPositive)
{
PowerToyValues values(m_moduleName);
values.add_property<bool>(L"positive_bool_value", true);
@ -173,7 +173,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(true, *value);
}
TEST_METHOD(AddPropertyBoolNegative)
TEST_METHOD (AddPropertyBoolNegative)
{
PowerToyValues values(m_moduleName);
values.add_property<bool>(L"negative_bool_value", false);
@ -183,7 +183,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, *value);
}
TEST_METHOD(AddPropertyIntPositive)
TEST_METHOD (AddPropertyIntPositive)
{
PowerToyValues values(m_moduleName);
const int intVal = 4392854;
@ -194,7 +194,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(intVal, *value);
}
TEST_METHOD(AddPropertyIntNegative)
TEST_METHOD (AddPropertyIntNegative)
{
PowerToyValues values(m_moduleName);
const int intVal = -4392854;
@ -205,7 +205,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(intVal, *value);
}
TEST_METHOD(AddPropertyIntZero)
TEST_METHOD (AddPropertyIntZero)
{
PowerToyValues values(m_moduleName);
const int intVal = 0;
@ -216,7 +216,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(intVal, *value);
}
TEST_METHOD(AddPropertyStringEmpty)
TEST_METHOD (AddPropertyStringEmpty)
{
PowerToyValues values(m_moduleName);
const std::wstring stringVal = L"";
@ -227,7 +227,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(stringVal, *value);
}
TEST_METHOD(AddPropertyString)
TEST_METHOD (AddPropertyString)
{
PowerToyValues values(m_moduleName);
const std::wstring stringVal = L"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
@ -238,7 +238,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(stringVal, *value);
}
TEST_METHOD(AddPropertyJsonEmpty)
TEST_METHOD (AddPropertyJsonEmpty)
{
PowerToyValues values(m_moduleName);
const auto json = json::JsonObject();
@ -249,7 +249,7 @@ namespace UnitTestsCommonLib
compareJsons(json, *value);
}
TEST_METHOD(AddPropertyJsonObject)
TEST_METHOD (AddPropertyJsonObject)
{
PowerToyValues values(m_moduleName);
const auto json = json::JsonObject::Parse(m_json);
@ -261,7 +261,7 @@ namespace UnitTestsCommonLib
}
};
TEST_CLASS(SettingsUnitTests)
TEST_CLASS (SettingsUnitTests)
{
private:
const std::wstring m_moduleName = L"Module Name";
@ -279,7 +279,7 @@ namespace UnitTestsCommonLib
}
public:
TEST_METHOD(SettingsSerialization)
TEST_METHOD (SettingsSerialization)
{
Settings settings(nullptr, m_moduleName);
@ -288,7 +288,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsSerializationToBuffer)
TEST_METHOD (SettingsSerializationToBuffer)
{
Settings settings(nullptr, m_moduleName);
@ -307,7 +307,7 @@ namespace UnitTestsCommonLib
compareJsons(m_defaultSettingsJson, actualJson);
}
TEST_METHOD(SettingsSetDescription)
TEST_METHOD (SettingsSetDescription)
{
const auto value = L"description value";
Settings settings(nullptr, m_moduleName);
@ -320,7 +320,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsSetIconKey)
TEST_METHOD (SettingsSetIconKey)
{
const auto value = L"icon key";
Settings settings(nullptr, m_moduleName);
@ -333,7 +333,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsSetOverviewLink)
TEST_METHOD (SettingsSetOverviewLink)
{
const auto value = L"overview link";
Settings settings(nullptr, m_moduleName);
@ -346,7 +346,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsSetVideoLink)
TEST_METHOD (SettingsSetVideoLink)
{
const auto value = L"video link";
Settings settings(nullptr, m_moduleName);
@ -359,7 +359,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddBoolTogglePositive)
TEST_METHOD (SettingsAddBoolTogglePositive)
{
const auto value = true;
@ -376,7 +376,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddBoolToggleNegative)
TEST_METHOD (SettingsAddBoolToggleNegative)
{
const auto value = false;
@ -393,7 +393,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddSpinner)
TEST_METHOD (SettingsAddSpinner)
{
const int value = 738543;
const int min = 0;
@ -416,7 +416,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddString)
TEST_METHOD (SettingsAddString)
{
const auto value = L"string text ";
@ -433,7 +433,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddStringMultiline)
TEST_METHOD (SettingsAddStringMultiline)
{
const auto value = L"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident,\nsunt in culpa qui officia deserunt mollit anim id est laborum.";
@ -451,7 +451,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddColorPicker)
TEST_METHOD (SettingsAddColorPicker)
{
const auto value = L"#ffffff";
@ -468,7 +468,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddHotkey)
TEST_METHOD (SettingsAddHotkey)
{
const auto value = PowerToysSettings::HotkeyObject::from_settings(true, true, true, true, 0);
@ -485,7 +485,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddChoiceGroup)
TEST_METHOD (SettingsAddChoiceGroup)
{
const auto value = L"choice group value";
const auto keysAndTexts = {
@ -516,7 +516,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddChoiceGroupEmpty)
TEST_METHOD (SettingsAddChoiceGroupEmpty)
{
const auto value = L"choice group value";
@ -534,7 +534,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddDropdown)
TEST_METHOD (SettingsAddDropdown)
{
const auto value = L"dropdown value";
const auto keysAndTexts = {
@ -565,7 +565,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddDropdownEmpty)
TEST_METHOD (SettingsAddDropdownEmpty)
{
const auto value = L"dropdown value";
@ -582,7 +582,7 @@ namespace UnitTestsCommonLib
compareJsons(expected, actual);
}
TEST_METHOD(SettingsAddCustomAction)
TEST_METHOD (SettingsAddCustomAction)
{
const auto value = L"custom action value";
const std::wstring buttonText = L"button text";
@ -602,17 +602,17 @@ namespace UnitTestsCommonLib
}
};
TEST_CLASS(CustomActionObjectUnitTests)
TEST_CLASS (CustomActionObjectUnitTests)
{
public:
TEST_METHOD(CustomActionObjectName)
TEST_METHOD (CustomActionObjectName)
{
const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}";
CustomActionObject obj = CustomActionObject::from_json_string(json);
Assert::AreEqual(std::wstring(L"action name"), obj.get_name());
}
TEST_METHOD(CustomActionObjectValue)
TEST_METHOD (CustomActionObjectValue)
{
const std::wstring json = L"{\"action_name\": \"action name\", \"value\": \"action value\"}";
CustomActionObject obj = CustomActionObject::from_json_string(json);
@ -620,44 +620,44 @@ namespace UnitTestsCommonLib
}
};
TEST_CLASS(HotkeyObjectUnitTests)
TEST_CLASS (HotkeyObjectUnitTests)
{
private:
json::JsonObject m_defaultHotkeyJson = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": true, \"ctrl\": true, \"alt\": true, \"shift\": true}");
json::JsonObject m_defaultHotkeyJsonAlternative = json::JsonObject::Parse(L"{\"key\":\"(Key 0)\", \"code\": 123, \"win\": false, \"ctrl\": false, \"alt\": false, \"shift\": false}");
public:
TEST_METHOD(GetKeyFromJson)
TEST_METHOD (GetKeyFromJson)
{
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key());
}
TEST_METHOD(GetKeyFromJsonString)
TEST_METHOD (GetKeyFromJsonString)
{
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(std::wstring(L"(Key 0)"), object.get_key());
}
TEST_METHOD(GetCodeFromJson)
TEST_METHOD (GetCodeFromJson)
{
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(UINT(123), object.get_code());
}
TEST_METHOD(GetCodeFromJsonString)
TEST_METHOD (GetCodeFromJsonString)
{
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(UINT(123), object.get_code());
}
TEST_METHOD(GetCodeFromSettings)
TEST_METHOD (GetCodeFromSettings)
{
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(UINT(123), object.get_code());
}
TEST_METHOD(GetWinPressedFromJson)
TEST_METHOD (GetWinPressedFromJson)
{
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.win_pressed());
@ -666,7 +666,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.win_pressed());
}
TEST_METHOD(GetWinPressedFromJsonString)
TEST_METHOD (GetWinPressedFromJsonString)
{
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.win_pressed());
@ -675,7 +675,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.win_pressed());
}
TEST_METHOD(GetWinPressedFromSettings)
TEST_METHOD (GetWinPressedFromSettings)
{
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.win_pressed());
@ -684,7 +684,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.win_pressed());
}
TEST_METHOD(GetCtrlPressedFromJson)
TEST_METHOD (GetCtrlPressedFromJson)
{
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.ctrl_pressed());
@ -693,7 +693,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
}
TEST_METHOD(GetCtrlPressedFromJsonString)
TEST_METHOD (GetCtrlPressedFromJsonString)
{
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.ctrl_pressed());
@ -702,7 +702,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
}
TEST_METHOD(GetCtrlPressedFromSettings)
TEST_METHOD (GetCtrlPressedFromSettings)
{
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.ctrl_pressed());
@ -711,7 +711,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.ctrl_pressed());
}
TEST_METHOD(GetAltPressedFromJson)
TEST_METHOD (GetAltPressedFromJson)
{
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.alt_pressed());
@ -720,7 +720,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.alt_pressed());
}
TEST_METHOD(GetAltPressedFromJsonString)
TEST_METHOD (GetAltPressedFromJsonString)
{
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.alt_pressed());
@ -729,7 +729,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.alt_pressed());
}
TEST_METHOD(GetAltPressedFromSettings)
TEST_METHOD (GetAltPressedFromSettings)
{
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.alt_pressed());
@ -738,7 +738,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.alt_pressed());
}
TEST_METHOD(GetShiftPressedFromJson)
TEST_METHOD (GetShiftPressedFromJson)
{
HotkeyObject object = HotkeyObject::from_json(m_defaultHotkeyJson);
Assert::AreEqual(true, object.shift_pressed());
@ -747,7 +747,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.shift_pressed());
}
TEST_METHOD(GetShiftPressedFromJsonString)
TEST_METHOD (GetShiftPressedFromJsonString)
{
HotkeyObject object = HotkeyObject::from_json_string(m_defaultHotkeyJson.Stringify());
Assert::AreEqual(true, object.shift_pressed());
@ -756,7 +756,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.shift_pressed());
}
TEST_METHOD(GetShiftPressedFromSettings)
TEST_METHOD (GetShiftPressedFromSettings)
{
HotkeyObject object = HotkeyObject::from_settings(true, true, true, true, 123);
Assert::AreEqual(true, object.shift_pressed());
@ -765,7 +765,7 @@ namespace UnitTestsCommonLib
Assert::AreEqual(false, objectNegativeValues.shift_pressed());
}
TEST_METHOD(GetModifiersRepeat)
TEST_METHOD (GetModifiersRepeat)
{
std::map<UINT, HotkeyObject> expectedMap = {
std::make_pair(0x0000, HotkeyObject::from_settings(false, false, false, false, 0)),
@ -792,7 +792,7 @@ namespace UnitTestsCommonLib
}
}
TEST_METHOD(GetModifiers)
TEST_METHOD (GetModifiers)
{
std::map<UINT, HotkeyObject> expectedMap = {
std::make_pair(0x4000, HotkeyObject::from_settings(false, false, false, false, 0)),

View file

@ -10,10 +10,10 @@ namespace UnitTestsVersionHelper
const int MINOR_VERSION_12 = 12;
const int REVISION_VERSION_0 = 0;
TEST_CLASS(UnitTestsVersionHelper)
TEST_CLASS (UnitTestsVersionHelper)
{
public:
TEST_METHOD(integerConstructorShouldProprelyInitializateVersionNumbers)
TEST_METHOD (integerConstructorShouldProprelyInitializateVersionNumbers)
{
VersionHelper sut(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
@ -21,7 +21,7 @@ namespace UnitTestsVersionHelper
Assert::AreEqual(MINOR_VERSION_12, sut.minor);
Assert::AreEqual(REVISION_VERSION_0, sut.revision);
}
TEST_METHOD(integerConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
TEST_METHOD (integerConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
{
const int testcaseMajor = 2;
const int testcaseMinor = 25;
@ -32,16 +32,15 @@ namespace UnitTestsVersionHelper
Assert::AreEqual(testcaseMinor, sut.minor);
Assert::AreEqual(testcaseRevision, sut.revision);
}
TEST_METHOD(stringConstructorShouldProprelyInitializateVersionNumbers)
TEST_METHOD (stringConstructorShouldProprelyInitializateVersionNumbers)
{
VersionHelper sut("v0.12.3");
Assert::AreEqual(0, sut.major);
Assert::AreEqual(12, sut.minor);
Assert::AreEqual(3, sut.revision);
}
TEST_METHOD(stringConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
TEST_METHOD (stringConstructorShouldProprelyInitializateWithDifferentVersionNumbers)
{
VersionHelper sut("v2.25.1");
@ -49,21 +48,21 @@ namespace UnitTestsVersionHelper
Assert::AreEqual(25, sut.minor);
Assert::AreEqual(1, sut.revision);
}
TEST_METHOD(whenMajorVersionIsGreaterComparationOperatorShouldReturnProperValue)
TEST_METHOD (whenMajorVersionIsGreaterComparationOperatorShouldReturnProperValue)
{
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0);
Assert::IsTrue(lhs > rhs);
}
TEST_METHOD(whenMajorVersionIsLesserComparationOperatorShouldReturnProperValue)
TEST_METHOD (whenMajorVersionIsLesserComparationOperatorShouldReturnProperValue)
{
VersionHelper rhs(MAJOR_VERSION_0 + 1, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
Assert::IsFalse(lhs > rhs);
}
TEST_METHOD(whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue)
TEST_METHOD (whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue)
{
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0);
@ -71,7 +70,7 @@ namespace UnitTestsVersionHelper
Assert::IsTrue(lhs > rhs);
}
TEST_METHOD(whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue2)
TEST_METHOD (whenMajorVersionIsEqualComparationOperatorShouldCompareMinorVersionValue2)
{
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12 - 1, REVISION_VERSION_0);
@ -79,14 +78,14 @@ namespace UnitTestsVersionHelper
Assert::IsFalse(lhs > rhs);
}
TEST_METHOD(whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue)
TEST_METHOD (whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue)
{
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1);
Assert::IsTrue(lhs > rhs);
}
TEST_METHOD(whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue2)
TEST_METHOD (whenMajorAndMinorVersionIsEqualComparationOperatorShouldCompareRevisionValue2)
{
VersionHelper rhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0 + 1);
VersionHelper lhs(MAJOR_VERSION_0, MINOR_VERSION_12, REVISION_VERSION_0);

View file

@ -2,42 +2,50 @@
#include "animation.h"
Animation::Animation(double duration, double start, double stop) :
duration(duration), start_value(start), end_value(stop), start(std::chrono::high_resolution_clock::now()) { }
duration(duration), start_value(start), end_value(stop), start(std::chrono::high_resolution_clock::now()) {}
void Animation::reset() {
start = std::chrono::high_resolution_clock::now();
void Animation::reset()
{
start = std::chrono::high_resolution_clock::now();
}
void Animation::reset(double duration) {
this->duration = duration;
reset();
void Animation::reset(double duration)
{
this->duration = duration;
reset();
}
void Animation::reset(double duration, double start, double stop) {
start_value = start;
end_value = stop;
reset(duration);
void Animation::reset(double duration, double start, double stop)
{
start_value = start;
end_value = stop;
reset(duration);
}
static double ease_out_expo(double t) {
return 1 - pow(2, -8 * t);
static double ease_out_expo(double t)
{
return 1 - pow(2, -8 * t);
}
double Animation::apply_animation_function(double t, AnimFunctions apply_function) {
switch (apply_function) {
case EASE_OUT_EXPO:
return ease_out_expo(t);
case LINEAR:
default:
return t;
}
double Animation::apply_animation_function(double t, AnimFunctions apply_function)
{
switch (apply_function)
{
case EASE_OUT_EXPO:
return ease_out_expo(t);
case LINEAR:
default:
return t;
}
}
double Animation::value(AnimFunctions apply_function) const {
auto anim_duration = std::chrono::high_resolution_clock::now() - start;
double t = std::chrono::duration<double>(anim_duration).count() / duration;
if (t >= 1)
return end_value;
return start_value + (end_value - start_value) * apply_animation_function(t, apply_function);
double Animation::value(AnimFunctions apply_function) const
{
auto anim_duration = std::chrono::high_resolution_clock::now() - start;
double t = std::chrono::duration<double>(anim_duration).count() / duration;
if (t >= 1)
return end_value;
return start_value + (end_value - start_value) * apply_animation_function(t, apply_function);
}
bool Animation::done() const {
return std::chrono::high_resolution_clock::now() - start >= std::chrono::duration<double>(duration);
bool Animation::done() const
{
return std::chrono::high_resolution_clock::now() - start >= std::chrono::duration<double>(duration);
}

View file

@ -11,21 +11,24 @@
When redering, call value() to get value from 0 to 1 - depending on animation
progress.
*/
class Animation {
class Animation
{
public:
enum AnimFunctions {
LINEAR = 0,
EASE_OUT_EXPO
};
enum AnimFunctions
{
LINEAR = 0,
EASE_OUT_EXPO
};
Animation(double duration = 1, double start = 0, double stop = 1);
void reset();
void reset(double duration);
void reset(double duration, double start, double stop);
double value(AnimFunctions apply_function) const;
bool done() const;
Animation(double duration = 1, double start = 0, double stop = 1);
void reset();
void reset(double duration);
void reset(double duration, double start, double stop);
double value(AnimFunctions apply_function) const;
bool done() const;
private:
static double apply_animation_function(double t, AnimFunctions apply_function);
std::chrono::high_resolution_clock::time_point start;
double start_value, end_value, duration;
static double apply_animation_function(double t, AnimFunctions apply_function);
std::chrono::high_resolution_clock::time_point start;
double start_value, end_value, duration;
};

View file

@ -5,43 +5,50 @@
#include <condition_variable>
#include <string>
class AsyncMessageQueue {
class AsyncMessageQueue
{
private:
std::mutex queue_mutex;
std::queue<std::wstring> message_queue;
std::condition_variable message_ready;
bool interrupted = false;
std::mutex queue_mutex;
std::queue<std::wstring> message_queue;
std::condition_variable message_ready;
bool interrupted = false;
//Disable copy
AsyncMessageQueue(const AsyncMessageQueue&);
AsyncMessageQueue& operator=(const AsyncMessageQueue&);
//Disable copy
AsyncMessageQueue(const AsyncMessageQueue&);
AsyncMessageQueue& operator=(const AsyncMessageQueue&);
public:
AsyncMessageQueue() {
}
void queue_message(std::wstring message) {
this->queue_mutex.lock();
this->message_queue.push(message);
this->queue_mutex.unlock();
this->message_ready.notify_one();
}
std::wstring pop_message() {
std::unique_lock<std::mutex> lock(this->queue_mutex);
while (message_queue.empty() && !this->interrupted) {
this->message_ready.wait(lock);
AsyncMessageQueue()
{
}
if (this->interrupted) {
//Just returns a empty string if the queue was interrupted.
return std::wstring(L"");
void queue_message(std::wstring message)
{
this->queue_mutex.lock();
this->message_queue.push(message);
this->queue_mutex.unlock();
this->message_ready.notify_one();
}
std::wstring pop_message()
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
while (message_queue.empty() && !this->interrupted)
{
this->message_ready.wait(lock);
}
if (this->interrupted)
{
//Just returns a empty string if the queue was interrupted.
return std::wstring(L"");
}
std::wstring message = this->message_queue.front();
this->message_queue.pop();
return message;
}
void interrupt()
{
this->queue_mutex.lock();
this->interrupted = true;
this->queue_mutex.unlock();
this->message_ready.notify_all();
}
std::wstring message = this->message_queue.front();
this->message_queue.pop();
return message;
}
void interrupt() {
this->queue_mutex.lock();
this->interrupted = true;
this->queue_mutex.unlock();
this->message_ready.notify_all();
}
};

View file

@ -8,7 +8,7 @@ template<typename T>
class com_object_factory : public IClassFactory
{
public:
HRESULT __stdcall QueryInterface(const IID & riid, void** ppv) override
HRESULT __stdcall QueryInterface(const IID& riid, void** ppv) override
{
static const QITAB qit[] = {
QITABENT(com_object_factory, IClassFactory),
@ -28,7 +28,7 @@ public:
return refCount;
}
HRESULT __stdcall CreateInstance(IUnknown* punkOuter, const IID & riid, void** ppv)
HRESULT __stdcall CreateInstance(IUnknown* punkOuter, const IID& riid, void** ppv)
{
*ppv = nullptr;
HRESULT hr;

File diff suppressed because it is too large Load diff

View file

@ -14,18 +14,20 @@ std::optional<RECT> get_window_pos(HWND hwnd);
std::optional<POINT> get_mouse_pos();
// Test if window can be zoned by FancyZones
struct FancyZonesFilter {
bool zonable = false; // If the window is zonable by FancyZones by default - true when both standard_window and no_visible_owner are also true
bool standard_window = false; // True if from the styles the window looks like a standard window
bool no_visible_owner = false; // True if the window is a top-level window that does not have a visible owner
std::wstring process_path; // Path to the executable owning the window
struct FancyZonesFilter
{
bool zonable = false; // If the window is zonable by FancyZones by default - true when both standard_window and no_visible_owner are also true
bool standard_window = false; // True if from the styles the window looks like a standard window
bool no_visible_owner = false; // True if the window is a top-level window that does not have a visible owner
std::wstring process_path; // Path to the executable owning the window
};
FancyZonesFilter get_fancyzones_filtered_window(HWND window);
// Gets active foreground window, filtering out all "non standard" windows like the taskbar, etc.
struct ShortcutGuideFilter {
HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window
bool snappable = false; // True, if the window can react to Windows Snap keys
struct ShortcutGuideFilter
{
HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window
bool snappable = false; // True, if the window can react to Windows Snap keys
};
ShortcutGuideFilter get_shortcutguide_filtered_window();
@ -42,17 +44,18 @@ int run_message_loop();
std::optional<std::wstring> get_last_error_message(const DWORD dw);
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw);
enum WindowState {
UNKNONW,
MINIMIZED,
MAXIMIZED,
SNAPED_TOP_LEFT,
SNAPED_LEFT,
SNAPED_BOTTOM_LEFT,
SNAPED_TOP_RIGHT,
SNAPED_RIGHT,
SNAPED_BOTTOM_RIGHT,
RESTORED
enum WindowState
{
UNKNONW,
MINIMIZED,
MAXIMIZED,
SNAPED_TOP_LEFT,
SNAPED_LEFT,
SNAPED_BOTTOM_LEFT,
SNAPED_TOP_RIGHT,
SNAPED_RIGHT,
SNAPED_BOTTOM_RIGHT,
RESTORED
};
WindowState get_window_state(HWND hwnd);

View file

@ -1,105 +1,117 @@
#include "pch.h"
#include "d2d_svg.h"
D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc) {
svg = nullptr;
winrt::com_ptr<IStream> svg_stream;
winrt::check_hresult(SHCreateStreamOnFileEx(filename.c_str(),
STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE,
nullptr,
svg_stream.put()));
D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc)
{
svg = nullptr;
winrt::com_ptr<IStream> svg_stream;
winrt::check_hresult(SHCreateStreamOnFileEx(filename.c_str(),
STGM_READ,
FILE_ATTRIBUTE_NORMAL,
FALSE,
nullptr,
svg_stream.put()));
winrt::check_hresult(d2d_dc->CreateSvgDocument(
svg_stream.get(),
D2D1::SizeF(1, 1),
svg.put()));
winrt::check_hresult(d2d_dc->CreateSvgDocument(
svg_stream.get(),
D2D1::SizeF(1, 1),
svg.put()));
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
float tmp;
winrt::check_hresult(root->GetAttributeValue(L"width", &tmp));
svg_width = (int)tmp;
winrt::check_hresult(root->GetAttributeValue(L"height", &tmp));
svg_height = (int)tmp;
return *this;
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
float tmp;
winrt::check_hresult(root->GetAttributeValue(L"width", &tmp));
svg_width = (int)tmp;
winrt::check_hresult(root->GetAttributeValue(L"height", &tmp));
svg_height = (int)tmp;
return *this;
}
D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float max_scale) {
// Center
transform = D2D1::Matrix3x2F::Identity();
transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
float h_scale = fill * height / svg_height;
float v_scale = fill * width / svg_width;
used_scale = min(h_scale, v_scale);
if (max_scale > 0) {
used_scale = min(used_scale, max_scale);
}
transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
transform = transform * D2D1::Matrix3x2F::Translation((float)x, (float)y);
return *this;
D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float max_scale)
{
// Center
transform = D2D1::Matrix3x2F::Identity();
transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
float h_scale = fill * height / svg_height;
float v_scale = fill * width / svg_width;
used_scale = min(h_scale, v_scale);
if (max_scale > 0)
{
used_scale = min(used_scale, max_scale);
}
transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
transform = transform * D2D1::Matrix3x2F::Translation((float)x, (float)y);
return *this;
}
D2DSVG& D2DSVG::recolor(uint32_t oldcolor, uint32_t newcolor) {
auto new_color = D2D1::ColorF(newcolor & 0xFFFFFF, 1);
auto old_color = D2D1::ColorF(oldcolor & 0xFFFFFF, 1);
std::function<void(ID2D1SvgElement* element)> recurse = [&](ID2D1SvgElement* element) {
D2DSVG& D2DSVG::recolor(uint32_t oldcolor, uint32_t newcolor)
{
auto new_color = D2D1::ColorF(newcolor & 0xFFFFFF, 1);
auto old_color = D2D1::ColorF(oldcolor & 0xFFFFFF, 1);
std::function<void(ID2D1SvgElement * element)> recurse = [&](ID2D1SvgElement* element) {
if (!element)
return;
if (element->IsAttributeSpecified(L"fill"))
{
D2D1_COLOR_F elem_fill;
winrt::com_ptr<ID2D1SvgPaint> paint;
element->GetAttributeValue(L"fill", paint.put());
paint->GetColor(&elem_fill);
if (elem_fill.r == old_color.r && elem_fill.g == old_color.g && elem_fill.b == old_color.b)
{
winrt::check_hresult(element->SetAttributeValue(L"fill", new_color));
}
}
winrt::com_ptr<ID2D1SvgElement> sub;
element->GetFirstChild(sub.put());
while (sub)
{
recurse(sub.get());
winrt::com_ptr<ID2D1SvgElement> next;
element->GetNextChild(sub.get(), next.put());
sub = next;
}
};
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
recurse(root.get());
return *this;
}
D2DSVG& D2DSVG::render(ID2D1DeviceContext5* d2d_dc)
{
D2D1_MATRIX_3X2_F current;
d2d_dc->GetTransform(&current);
d2d_dc->SetTransform(transform * current);
d2d_dc->DrawSvgDocument(svg.get());
d2d_dc->SetTransform(current);
return *this;
}
D2DSVG& D2DSVG::toggle_element(const wchar_t* id, bool visible)
{
winrt::com_ptr<ID2D1SvgElement> element;
if (svg->FindElementById(id, element.put()) != S_OK)
return *this;
if (!element)
return;
if (element->IsAttributeSpecified(L"fill")) {
D2D1_COLOR_F elem_fill;
winrt::com_ptr<ID2D1SvgPaint> paint;
element->GetAttributeValue(L"fill", paint.put());
paint->GetColor(&elem_fill);
if (elem_fill.r == old_color.r && elem_fill.g == old_color.g && elem_fill.b == old_color.b) {
winrt::check_hresult(element->SetAttributeValue(L"fill", new_color));
}
}
winrt::com_ptr<ID2D1SvgElement> sub;
element->GetFirstChild(sub.put());
while (sub) {
recurse(sub.get());
winrt::com_ptr<ID2D1SvgElement> next;
element->GetNextChild(sub.get(), next.put());
sub = next;
}
};
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
recurse(root.get());
return *this;
}
D2DSVG& D2DSVG::render(ID2D1DeviceContext5* d2d_dc) {
D2D1_MATRIX_3X2_F current;
d2d_dc->GetTransform(&current);
d2d_dc->SetTransform(transform * current);
d2d_dc->DrawSvgDocument(svg.get());
d2d_dc->SetTransform(current);
return *this;
}
D2DSVG& D2DSVG::toggle_element(const wchar_t* id, bool visible) {
winrt::com_ptr<ID2D1SvgElement> element;
if (svg->FindElementById(id, element.put()) != S_OK)
return *this;
element->SetAttributeValue(L"display", visible ? D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_INLINE : D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_NONE);
return *this;
if (!element)
return *this;
element->SetAttributeValue(L"display", visible ? D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_INLINE : D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_NONE);
return *this;
}
winrt::com_ptr<ID2D1SvgElement> D2DSVG::find_element(const std::wstring& id) {
winrt::com_ptr< ID2D1SvgElement> element;
winrt::check_hresult(svg->FindElementById(id.c_str(), element.put()));
return element;
winrt::com_ptr<ID2D1SvgElement> D2DSVG::find_element(const std::wstring& id)
{
winrt::com_ptr<ID2D1SvgElement> element;
winrt::check_hresult(svg->FindElementById(id.c_str(), element.put()));
return element;
}
D2D1_RECT_F D2DSVG::rescale(D2D1_RECT_F rect) {
D2D1_RECT_F result;
auto src = reinterpret_cast<D2D1_POINT_2F*>(&rect);
auto dst = reinterpret_cast<D2D1_POINT_2F*>(&result);
dst[0] = src[0] * transform;
dst[1] = src[1] * transform;
return result;
D2D1_RECT_F D2DSVG::rescale(D2D1_RECT_F rect)
{
D2D1_RECT_F result;
auto src = reinterpret_cast<D2D1_POINT_2F*>(&rect);
auto dst = reinterpret_cast<D2D1_POINT_2F*>(&result);
dst[0] = src[0] * transform;
dst[1] = src[1] * transform;
return result;
}

View file

@ -4,21 +4,23 @@
#include <winrt/base.h>
#include <string>
class D2DSVG {
class D2DSVG
{
public:
D2DSVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc);
D2DSVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f);
D2DSVG& render(ID2D1DeviceContext5* d2d_dc);
D2DSVG& recolor(uint32_t oldcolor, uint32_t newcolor);
float get_scale() const { return used_scale; }
int width() const { return svg_width; }
int height() const { return svg_height; }
D2DSVG& toggle_element(const wchar_t* id, bool visible);
winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id);
D2D1_RECT_F rescale(D2D1_RECT_F rect);
D2DSVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc);
D2DSVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f);
D2DSVG& render(ID2D1DeviceContext5* d2d_dc);
D2DSVG& recolor(uint32_t oldcolor, uint32_t newcolor);
float get_scale() const { return used_scale; }
int width() const { return svg_width; }
int height() const { return svg_height; }
D2DSVG& toggle_element(const wchar_t* id, bool visible);
winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id);
D2D1_RECT_F rescale(D2D1_RECT_F rect);
protected:
float used_scale = 1.0f;
winrt::com_ptr<ID2D1SvgDocument> svg;
int svg_width = -1, svg_height = -1;
D2D1::Matrix3x2F transform;
float used_scale = 1.0f;
winrt::com_ptr<ID2D1SvgDocument> svg;
int svg_width = -1, svg_height = -1;
D2D1::Matrix3x2F transform;
};

View file

@ -1,48 +1,54 @@
#include "pch.h"
#include "d2d_text.h"
D2DText::D2DText(float text_size, float scale) {
winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<IUnknown**>(factory.put_void())));
resize(text_size, scale);
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
D2DText::D2DText(float text_size, float scale)
{
winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<IUnknown**>(factory.put_void())));
resize(text_size, scale);
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
}
D2DText & D2DText::resize(float text_size, float scale) {
format = nullptr;
winrt::check_hresult(factory->CreateTextFormat(L"Segoe UI",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
text_size * scale,
L"en-us",
format.put()));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
return *this;
D2DText& D2DText::resize(float text_size, float scale)
{
format = nullptr;
winrt::check_hresult(factory->CreateTextFormat(L"Segoe UI",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
text_size * scale,
L"en-us",
format.put()));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
return *this;
}
D2DText & D2DText::set_aligment_left() {
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING));
return *this;
D2DText& D2DText::set_aligment_left()
{
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING));
return *this;
}
D2DText & D2DText::set_aligment_center() {
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
return *this;
D2DText& D2DText::set_aligment_center()
{
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
return *this;
}
D2DText & D2DText::set_aligment_right() {
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING));
return *this;
D2DText& D2DText::set_aligment_right()
{
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING));
return *this;
}
void D2DText::write(ID2D1DeviceContext5 * d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text) {
winrt::com_ptr<ID2D1SolidColorBrush> brush;
d2d_dc->CreateSolidColorBrush(color, brush.put());
d2d_dc->DrawText(text.c_str(),
(UINT32)text.length(),
format.get(),
rect,
brush.get());
void D2DText::write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text)
{
winrt::com_ptr<ID2D1SolidColorBrush> brush;
d2d_dc->CreateSolidColorBrush(color, brush.put());
d2d_dc->DrawText(text.c_str(),
(UINT32)text.length(),
format.get(),
rect,
brush.get());
}

View file

@ -2,15 +2,17 @@
#include <winrt/base.h>
#include <dwrite.h>
class D2DText {
class D2DText
{
public:
D2DText(float text_size = 15.0f, float scale = 1.0f);
D2DText& resize(float text_size, float scale);
D2DText& set_aligment_left();
D2DText& set_aligment_center();
D2DText& set_aligment_right();
void write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text);
D2DText(float text_size = 15.0f, float scale = 1.0f);
D2DText& resize(float text_size, float scale);
D2DText& set_aligment_left();
D2DText& set_aligment_center();
D2DText& set_aligment_right();
void write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text);
private:
winrt::com_ptr<IDWriteFactory> factory;
winrt::com_ptr<IDWriteTextFormat> format;
winrt::com_ptr<IDWriteFactory> factory;
winrt::com_ptr<IDWriteTextFormat> format;
};

View file

@ -3,182 +3,204 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
D2DWindow::D2DWindow() {
static const WCHAR* class_name = L"PToyD2DPopup";
WNDCLASS wc = {};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
wc.lpszClassName = class_name;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = d2d_window_proc;
RegisterClass(&wc);
hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOREDIRECTIONBITMAP | WS_EX_LAYERED,
wc.lpszClassName,
L"PToyD2DPopup",
WS_POPUP| WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, wc.hInstance, this);
WINRT_VERIFY(hwnd);
D2DWindow::D2DWindow()
{
static const WCHAR* class_name = L"PToyD2DPopup";
WNDCLASS wc = {};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
wc.lpszClassName = class_name;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = d2d_window_proc;
RegisterClass(&wc);
hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOREDIRECTIONBITMAP | WS_EX_LAYERED,
wc.lpszClassName,
L"PToyD2DPopup",
WS_POPUP | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
wc.hInstance,
this);
WINRT_VERIFY(hwnd);
}
void D2DWindow::show(UINT x, UINT y, UINT width, UINT height) {
if (!initialized) {
void D2DWindow::show(UINT x, UINT y, UINT width, UINT height)
{
if (!initialized)
{
base_init();
}
base_resize(width, height);
render_empty();
on_show();
SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, 0);
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
}
void D2DWindow::hide()
{
ShowWindow(hwnd, SW_HIDE);
on_hide();
}
void D2DWindow::initialize()
{
base_init();
}
base_resize(width, height);
render_empty();
on_show();
SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, 0);
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
}
void D2DWindow::hide() {
ShowWindow(hwnd, SW_HIDE);
on_hide();
}
void D2DWindow::initialize() {
base_init();
}
void D2DWindow::base_init() {
std::unique_lock lock(mutex);
// D2D1Factory is independent from the device, no need to recreate it if we need to recreate the device.
if (!d2d_factory) {
void D2DWindow::base_init()
{
std::unique_lock lock(mutex);
// D2D1Factory is independent from the device, no need to recreate it if we need to recreate the device.
if (!d2d_factory)
{
#ifdef _DEBUG
D2D1_FACTORY_OPTIONS options = { D2D1_DEBUG_LEVEL_INFORMATION };
D2D1_FACTORY_OPTIONS options = { D2D1_DEBUG_LEVEL_INFORMATION };
#else
D2D1_FACTORY_OPTIONS options = {};
D2D1_FACTORY_OPTIONS options = {};
#endif
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
__uuidof(d2d_factory),
&options,
d2d_factory.put_void()));
}
// For all other stuff - assing nullptr first to release the object, to reset the com_ptr.
d2d_dc = nullptr;
d2d_device = nullptr;
dxgi_factory = nullptr;
dxgi_device = nullptr;
d3d_device = nullptr;
winrt::check_hresult(D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
0,
D3D11_SDK_VERSION,
d3d_device.put(),
nullptr,
nullptr));
winrt::check_hresult(d3d_device->QueryInterface(__uuidof(dxgi_device), dxgi_device.put_void()));
winrt::check_hresult(CreateDXGIFactory2(0, __uuidof(dxgi_factory), dxgi_factory.put_void()));
winrt::check_hresult(d2d_factory->CreateDevice(dxgi_device.get(), d2d_device.put()));
winrt::check_hresult(d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, d2d_dc.put()));
init();
initialized = true;
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
__uuidof(d2d_factory),
&options,
d2d_factory.put_void()));
}
// For all other stuff - assing nullptr first to release the object, to reset the com_ptr.
d2d_dc = nullptr;
d2d_device = nullptr;
dxgi_factory = nullptr;
dxgi_device = nullptr;
d3d_device = nullptr;
winrt::check_hresult(D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
0,
D3D11_SDK_VERSION,
d3d_device.put(),
nullptr,
nullptr));
winrt::check_hresult(d3d_device->QueryInterface(__uuidof(dxgi_device), dxgi_device.put_void()));
winrt::check_hresult(CreateDXGIFactory2(0, __uuidof(dxgi_factory), dxgi_factory.put_void()));
winrt::check_hresult(d2d_factory->CreateDevice(dxgi_device.get(), d2d_device.put()));
winrt::check_hresult(d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, d2d_dc.put()));
init();
initialized = true;
}
void D2DWindow::base_resize(UINT width, UINT height) {
std::unique_lock lock(mutex);
if (!initialized) {
return;
}
window_width = width;
window_height = height;
if (window_width == 0 || window_height == 0) {
return;
}
DXGI_SWAP_CHAIN_DESC1 sc_description = {};
sc_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sc_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sc_description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
sc_description.BufferCount = 2;
sc_description.SampleDesc.Count = 1;
sc_description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
sc_description.Width = window_width;
sc_description.Height = window_height;
dxgi_swap_chain = nullptr;
winrt::check_hresult(dxgi_factory->CreateSwapChainForComposition(dxgi_device.get(),
&sc_description,
nullptr,
dxgi_swap_chain.put()));
composition_device = nullptr;
winrt::check_hresult(DCompositionCreateDevice(dxgi_device.get(),
__uuidof(composition_device),
composition_device.put_void()));
void D2DWindow::base_resize(UINT width, UINT height)
{
std::unique_lock lock(mutex);
if (!initialized)
{
return;
}
window_width = width;
window_height = height;
if (window_width == 0 || window_height == 0)
{
return;
}
DXGI_SWAP_CHAIN_DESC1 sc_description = {};
sc_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sc_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sc_description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
sc_description.BufferCount = 2;
sc_description.SampleDesc.Count = 1;
sc_description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
sc_description.Width = window_width;
sc_description.Height = window_height;
dxgi_swap_chain = nullptr;
winrt::check_hresult(dxgi_factory->CreateSwapChainForComposition(dxgi_device.get(),
&sc_description,
nullptr,
dxgi_swap_chain.put()));
composition_device = nullptr;
winrt::check_hresult(DCompositionCreateDevice(dxgi_device.get(),
__uuidof(composition_device),
composition_device.put_void()));
composition_target = nullptr;
winrt::check_hresult(composition_device->CreateTargetForHwnd(hwnd, true, composition_target.put()));
composition_visual = nullptr;
winrt::check_hresult(composition_device->CreateVisual(composition_visual.put()));
winrt::check_hresult(composition_visual->SetContent(dxgi_swap_chain.get()));
winrt::check_hresult(composition_target->SetRoot(composition_visual.get()));
dxgi_surface = nullptr;
winrt::check_hresult(dxgi_swap_chain->GetBuffer(0, __uuidof(dxgi_surface), dxgi_surface.put_void()));
D2D1_BITMAP_PROPERTIES1 properties = {};
properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
d2d_bitmap = nullptr;
winrt::check_hresult(d2d_dc->CreateBitmapFromDxgiSurface(dxgi_surface.get(),
properties,
d2d_bitmap.put()));
d2d_dc->SetTarget(d2d_bitmap.get());
resize();
composition_target = nullptr;
winrt::check_hresult(composition_device->CreateTargetForHwnd(hwnd, true, composition_target.put()));
composition_visual = nullptr;
winrt::check_hresult(composition_device->CreateVisual(composition_visual.put()));
winrt::check_hresult(composition_visual->SetContent(dxgi_swap_chain.get()));
winrt::check_hresult(composition_target->SetRoot(composition_visual.get()));
dxgi_surface = nullptr;
winrt::check_hresult(dxgi_swap_chain->GetBuffer(0, __uuidof(dxgi_surface), dxgi_surface.put_void()));
D2D1_BITMAP_PROPERTIES1 properties = {};
properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
d2d_bitmap = nullptr;
winrt::check_hresult(d2d_dc->CreateBitmapFromDxgiSurface(dxgi_surface.get(),
properties,
d2d_bitmap.put()));
d2d_dc->SetTarget(d2d_bitmap.get());
resize();
}
void D2DWindow::base_render() {
std::unique_lock lock(mutex);
if (!initialized || !d2d_dc || !d2d_bitmap)
return;
d2d_dc->BeginDraw();
render(d2d_dc.get());
winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
void D2DWindow::base_render()
{
std::unique_lock lock(mutex);
if (!initialized || !d2d_dc || !d2d_bitmap)
return;
d2d_dc->BeginDraw();
render(d2d_dc.get());
winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
}
void D2DWindow::render_empty() {
std::unique_lock lock(mutex);
if (!initialized || !d2d_dc || !d2d_bitmap)
return;
d2d_dc->BeginDraw();
d2d_dc->Clear();
winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
void D2DWindow::render_empty()
{
std::unique_lock lock(mutex);
if (!initialized || !d2d_dc || !d2d_bitmap)
return;
d2d_dc->BeginDraw();
d2d_dc->Clear();
winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
}
D2DWindow::~D2DWindow() {
ShowWindow(hwnd, SW_HIDE);
DestroyWindow(hwnd);
D2DWindow::~D2DWindow()
{
ShowWindow(hwnd, SW_HIDE);
DestroyWindow(hwnd);
}
D2DWindow* D2DWindow::this_from_hwnd(HWND window) {
return reinterpret_cast<D2DWindow*>(GetWindowLongPtr(window, GWLP_USERDATA));
D2DWindow* D2DWindow::this_from_hwnd(HWND window)
{
return reinterpret_cast<D2DWindow*>(GetWindowLongPtr(window, GWLP_USERDATA));
}
LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_NCCREATE: {
auto create_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(create_struct->lpCreateParams));
return TRUE;
}
case WM_MOVE:
case WM_SIZE:
this_from_hwnd(window)->base_resize((unsigned)lparam & 0xFFFF, (unsigned)lparam >> 16);
// Fall through to call 'base_render()'
case WM_PAINT:
this_from_hwnd(window)->base_render();
return 0;
default:
return DefWindowProc(window, message, wparam, lparam);
}
LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
{
switch (message)
{
case WM_NCCREATE:
{
auto create_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(create_struct->lpCreateParams));
return TRUE;
}
case WM_MOVE:
case WM_SIZE:
this_from_hwnd(window)->base_resize((unsigned)lparam & 0xFFFF, (unsigned)lparam >> 16);
// Fall through to call 'base_render()'
case WM_PAINT:
this_from_hwnd(window)->base_render();
return 0;
default:
return DefWindowProc(window, message, wparam, lparam);
}
}

View file

@ -14,47 +14,48 @@
class D2DWindow
{
public:
D2DWindow();
void show(UINT x, UINT y, UINT width, UINT height);
void hide();
void initialize();
virtual ~D2DWindow();
D2DWindow();
void show(UINT x, UINT y, UINT width, UINT height);
void hide();
void initialize();
virtual ~D2DWindow();
protected:
// Implement this:
// Implement this:
// Initialization - called when D2D device needs to be created.
// When called all D2DWindow members will be initialized, including d2d_dc
virtual void init() = 0;
// resize - when called, window_width and window_height will have current window size
virtual void resize() = 0;
// render - called on WM_PAIT, BeginPaint/EndPaint is handled by D2DWindow
virtual void render(ID2D1DeviceContext5* d2d_dc) = 0;
// on_show, on_hide - called when the window is about to be shown or about to be hidden
virtual void on_show() = 0;
virtual void on_hide() = 0;
// Initialization - called when D2D device needs to be created.
// When called all D2DWindow members will be initialized, including d2d_dc
virtual void init() = 0;
// resize - when called, window_width and window_height will have current window size
virtual void resize() = 0;
// render - called on WM_PAIT, BeginPaint/EndPaint is handled by D2DWindow
virtual void render(ID2D1DeviceContext5* d2d_dc) = 0;
// on_show, on_hide - called when the window is about to be shown or about to be hidden
virtual void on_show() = 0;
virtual void on_hide() = 0;
static LRESULT __stdcall d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
static D2DWindow* this_from_hwnd(HWND window);
void base_init();
void base_resize(UINT width, UINT height);
void base_render();
void render_empty();
static LRESULT __stdcall d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
static D2DWindow* this_from_hwnd(HWND window);
std::recursive_mutex mutex;
bool initialized = false;
HWND hwnd;
UINT window_width, window_height;
winrt::com_ptr<ID3D11Device> d3d_device;
winrt::com_ptr<IDXGIDevice> dxgi_device;
winrt::com_ptr<IDXGIFactory2> dxgi_factory;
winrt::com_ptr<IDXGISwapChain1> dxgi_swap_chain;
winrt::com_ptr<IDCompositionDevice> composition_device;
winrt::com_ptr<IDCompositionTarget> composition_target;
winrt::com_ptr<IDCompositionVisual> composition_visual;
winrt::com_ptr<IDXGISurface2> dxgi_surface;
winrt::com_ptr<ID2D1Bitmap1> d2d_bitmap;
winrt::com_ptr<ID2D1Factory6> d2d_factory;
winrt::com_ptr<ID2D1Device5> d2d_device;
winrt::com_ptr<ID2D1DeviceContext5> d2d_dc;
void base_init();
void base_resize(UINT width, UINT height);
void base_render();
void render_empty();
std::recursive_mutex mutex;
bool initialized = false;
HWND hwnd;
UINT window_width, window_height;
winrt::com_ptr<ID3D11Device> d3d_device;
winrt::com_ptr<IDXGIDevice> dxgi_device;
winrt::com_ptr<IDXGIFactory2> dxgi_factory;
winrt::com_ptr<IDXGISwapChain1> dxgi_swap_chain;
winrt::com_ptr<IDCompositionDevice> composition_device;
winrt::com_ptr<IDCompositionTarget> composition_target;
winrt::com_ptr<IDCompositionVisual> composition_visual;
winrt::com_ptr<IDXGISurface2> dxgi_surface;
winrt::com_ptr<ID2D1Bitmap1> d2d_bitmap;
winrt::com_ptr<ID2D1Factory6> d2d_factory;
winrt::com_ptr<ID2D1Device5> d2d_device;
winrt::com_ptr<ID2D1DeviceContext5> d2d_dc;
};

View file

@ -5,22 +5,22 @@
namespace json
{
std::optional<JsonObject> from_file(std::wstring_view file_name)
{
try
std::optional<JsonObject> from_file(std::wstring_view file_name)
{
std::wifstream file(file_name.data(), std::ios::binary);
using isbi = std::istreambuf_iterator<wchar_t>;
return JsonValue::Parse(std::wstring{isbi{file}, isbi{}}).GetObjectW();
try
{
std::wifstream file(file_name.data(), std::ios::binary);
using isbi = std::istreambuf_iterator<wchar_t>;
return JsonValue::Parse(std::wstring{ isbi{ file }, isbi{} }).GetObjectW();
}
catch (...)
{
return std::nullopt;
}
}
catch(...)
{
return std::nullopt;
}
}
void to_file(std::wstring_view file_name, const JsonObject & obj)
{
std::wofstream{file_name.data(), std::ios::binary} << obj.Stringify().c_str();
}
void to_file(std::wstring_view file_name, const JsonObject& obj)
{
std::wofstream{ file_name.data(), std::ios::binary } << obj.Stringify().c_str();
}
}

View file

@ -7,44 +7,44 @@
namespace json
{
using namespace winrt::Windows::Data::Json;
using namespace winrt::Windows::Data::Json;
std::optional<JsonObject> from_file(std::wstring_view file_name);
std::optional<JsonObject> from_file(std::wstring_view file_name);
void to_file(std::wstring_view file_name, const JsonObject& obj);
void to_file(std::wstring_view file_name, const JsonObject& obj);
inline bool has(
const json::JsonObject & o,
std::wstring_view name,
const json::JsonValueType type = JsonValueType::Object)
{
return o.HasKey(name) && o.GetNamedValue(name).ValueType() == type;
}
inline bool has(
const json::JsonObject& o,
std::wstring_view name,
const json::JsonValueType type = JsonValueType::Object)
{
return o.HasKey(name) && o.GetNamedValue(name).ValueType() == type;
}
template<typename T>
inline std::enable_if_t<std::is_arithmetic_v<T>, JsonValue> value(const T arithmetic)
{
return json::JsonValue::CreateNumberValue(arithmetic);
}
template<typename T>
inline std::enable_if_t<std::is_arithmetic_v<T>, JsonValue> value(const T arithmetic)
{
return json::JsonValue::CreateNumberValue(arithmetic);
}
template<typename T>
inline std::enable_if_t<!std::is_arithmetic_v<T>, JsonValue> value(T s)
{
return json::JsonValue::CreateStringValue(s);
}
template<typename T>
inline std::enable_if_t<!std::is_arithmetic_v<T>, JsonValue> value(T s)
{
return json::JsonValue::CreateStringValue(s);
}
inline JsonValue value(const bool boolean)
{
return json::JsonValue::CreateBooleanValue(boolean);
}
inline JsonValue value(const bool boolean)
{
return json::JsonValue::CreateBooleanValue(boolean);
}
inline JsonValue value(JsonObject value)
{
return value.as<JsonValue>();
}
inline JsonValue value(JsonObject value)
{
return value.as<JsonValue>();
}
inline JsonValue value(JsonValue value)
{
return value; // identity function overload for convenience
}
inline JsonValue value(JsonValue value)
{
return value; // identity function overload for convenience
}
}

View file

@ -3,67 +3,77 @@
#include "common.h"
#include "monitors.h"
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs) {
auto lhs_tuple = std::make_tuple(lhs.rect.left, lhs.rect.right, lhs.rect.top, lhs.rect.bottom);
auto rhs_tuple = std::make_tuple(rhs.rect.left, rhs.rect.right, rhs.rect.top, rhs.rect.bottom);
return lhs_tuple == rhs_tuple;
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs)
{
auto lhs_tuple = std::make_tuple(lhs.rect.left, lhs.rect.right, lhs.rect.top, lhs.rect.bottom);
auto rhs_tuple = std::make_tuple(rhs.rect.left, rhs.rect.right, rhs.rect.top, rhs.rect.bottom);
return lhs_tuple == rhs_tuple;
}
static BOOL CALLBACK get_displays_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcWork);
return true;
static BOOL CALLBACK get_displays_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
{
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcWork);
return true;
};
static BOOL CALLBACK get_displays_enum_cb_with_toolbar(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcMonitor);
return true;
static BOOL CALLBACK get_displays_enum_cb_with_toolbar(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
{
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcMonitor);
return true;
};
std::vector<MonitorInfo> MonitorInfo::GetMonitors(bool include_toolbar) {
std::vector<MonitorInfo> monitors;
EnumDisplayMonitors(NULL, NULL, include_toolbar ? get_displays_enum_cb_with_toolbar : get_displays_enum_cb, reinterpret_cast<LPARAM>(&monitors));
std::sort(begin(monitors), end(monitors), [](const MonitorInfo& lhs, const MonitorInfo& rhs) {
return lhs.rect < rhs.rect;
std::vector<MonitorInfo> MonitorInfo::GetMonitors(bool include_toolbar)
{
std::vector<MonitorInfo> monitors;
EnumDisplayMonitors(NULL, NULL, include_toolbar ? get_displays_enum_cb_with_toolbar : get_displays_enum_cb, reinterpret_cast<LPARAM>(&monitors));
std::sort(begin(monitors), end(monitors), [](const MonitorInfo& lhs, const MonitorInfo& rhs) {
return lhs.rect < rhs.rect;
});
return monitors;
return monitors;
}
static BOOL CALLBACK get_primary_display_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) {
reinterpret_cast<MonitorInfo*>(data)->handle = monitor;
reinterpret_cast<MonitorInfo*>(data)->rect = monitor_info.rcWork;
}
return true;
static BOOL CALLBACK get_primary_display_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
{
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
if (monitor_info.dwFlags & MONITORINFOF_PRIMARY)
{
reinterpret_cast<MonitorInfo*>(data)->handle = monitor;
reinterpret_cast<MonitorInfo*>(data)->rect = monitor_info.rcWork;
}
return true;
};
MonitorInfo MonitorInfo::GetPrimaryMonitor() {
MonitorInfo primary({}, {});
EnumDisplayMonitors(NULL, NULL, get_primary_display_enum_cb, reinterpret_cast<LPARAM>(&primary));
return primary;
MonitorInfo MonitorInfo::GetPrimaryMonitor()
{
MonitorInfo primary({}, {});
EnumDisplayMonitors(NULL, NULL, get_primary_display_enum_cb, reinterpret_cast<LPARAM>(&primary));
return primary;
}
MonitorInfo MonitorInfo::GetFromWindow(HWND hwnd) {
auto monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
MonitorInfo MonitorInfo::GetFromWindow(HWND hwnd)
{
auto monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
}
MonitorInfo MonitorInfo::GetFromPoint(POINT p) {
auto monitor = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
MonitorInfo MonitorInfo::GetFromPoint(POINT p)
{
auto monitor = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
}
MonitorInfo MonitorInfo::GetFromHandle(HMONITOR monitor) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
return MonitorInfo(monitor, monitor_info.rcWork);
MonitorInfo MonitorInfo::GetFromHandle(HMONITOR monitor)
{
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
return MonitorInfo(monitor, monitor_info.rcWork);
}

View file

@ -2,40 +2,44 @@
#include <Windows.h>
#include <vector>
struct ScreenSize {
explicit ScreenSize(RECT rect) : rect(rect) {}
RECT rect;
int left() const { return rect.left; }
int right() const { return rect.right; }
int top() const { return rect.top; }
int bottom() const { return rect.bottom; }
int height() const { return rect.bottom - rect.top; };
int width() const { return rect.right - rect.left; };
POINT top_left() const { return { rect.left, rect.top }; };
POINT top_middle() const { return { rect.left + width() / 2, rect.top }; };
POINT top_right() const { return { rect.right, rect.top }; };
POINT middle_left() const { return { rect.left, rect.top + height() / 2 }; };
POINT middle() const { return { rect.left + width() / 2, rect.top + height() / 2 }; };
POINT middle_right() const { return { rect.right, rect.top + height() / 2 }; };
POINT bottom_left() const { return { rect.left, rect.bottom }; };
POINT bottm_midle() const { return { rect.left + width() / 2, rect.bottom }; };
POINT bottom_right() const { return { rect.right, rect.bottom }; };
struct ScreenSize
{
explicit ScreenSize(RECT rect) :
rect(rect) {}
RECT rect;
int left() const { return rect.left; }
int right() const { return rect.right; }
int top() const { return rect.top; }
int bottom() const { return rect.bottom; }
int height() const { return rect.bottom - rect.top; };
int width() const { return rect.right - rect.left; };
POINT top_left() const { return { rect.left, rect.top }; };
POINT top_middle() const { return { rect.left + width() / 2, rect.top }; };
POINT top_right() const { return { rect.right, rect.top }; };
POINT middle_left() const { return { rect.left, rect.top + height() / 2 }; };
POINT middle() const { return { rect.left + width() / 2, rect.top + height() / 2 }; };
POINT middle_right() const { return { rect.right, rect.top + height() / 2 }; };
POINT bottom_left() const { return { rect.left, rect.bottom }; };
POINT bottm_midle() const { return { rect.left + width() / 2, rect.bottom }; };
POINT bottom_right() const { return { rect.right, rect.bottom }; };
};
struct MonitorInfo : ScreenSize {
explicit MonitorInfo(HMONITOR monitor, RECT rect) : handle(monitor), ScreenSize(rect) {}
HMONITOR handle;
struct MonitorInfo : ScreenSize
{
explicit MonitorInfo(HMONITOR monitor, RECT rect) :
handle(monitor), ScreenSize(rect) {}
HMONITOR handle;
// Returns monitor rects ordered from left to right
static std::vector<MonitorInfo> GetMonitors(bool include_toolbar);
// Return primary display
static MonitorInfo GetPrimaryMonitor();
// Return monitor on which hwnd window is displayed
static MonitorInfo GetFromWindow(HWND hwnd);
// Return monitor nearest to a point
static MonitorInfo GetFromPoint(POINT p);
// Return monitor info given a HMONITOR
static MonitorInfo GetFromHandle(HMONITOR monitor);
// Returns monitor rects ordered from left to right
static std::vector<MonitorInfo> GetMonitors(bool include_toolbar);
// Return primary display
static MonitorInfo GetPrimaryMonitor();
// Return monitor on which hwnd window is displayed
static MonitorInfo GetFromWindow(HWND hwnd);
// Return monitor nearest to a point
static MonitorInfo GetFromPoint(POINT p);
// Return monitor info given a HMONITOR
static MonitorInfo GetFromHandle(HMONITOR monitor);
};
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs);

View file

@ -1,2 +1 @@
#include "pch.h"

View file

@ -189,7 +189,7 @@ void notifications::show_toast_with_activations(std::wstring_view message, std::
std::wstring toast_xml;
toast_xml.reserve(1024);
std::wstring title{L"PowerToys"};
std::wstring title{ L"PowerToys" };
if (winstore::running_as_packaged())
{
title += L" (Experimental)";

View file

@ -2,38 +2,42 @@
#include "on_thread_executor.h"
OnThreadExecutor::OnThreadExecutor()
: _shutdown_request{false}
, _worker_thread{[this] { worker_thread(); }}
{}
std::future<void> OnThreadExecutor::submit(task_t task) {
auto future = task.get_future();
std::lock_guard lock{_task_mutex};
_task_queue.emplace(std::move(task));
_task_cv.notify_one();
return future;
OnThreadExecutor::OnThreadExecutor() :
_shutdown_request{ false }, _worker_thread{ [this] { worker_thread(); } }
{
}
void OnThreadExecutor::worker_thread() {
while(!_shutdown_request) {
task_t task;
std::future<void> OnThreadExecutor::submit(task_t task)
{
auto future = task.get_future();
std::lock_guard lock{ _task_mutex };
_task_queue.emplace(std::move(task));
_task_cv.notify_one();
return future;
}
void OnThreadExecutor::worker_thread()
{
while (!_shutdown_request)
{
std::unique_lock task_lock{_task_mutex};
_task_cv.wait(task_lock, [this] { return !_task_queue.empty() || _shutdown_request; });
if(_shutdown_request) {
return;
}
task = std::move(_task_queue.front());
_task_queue.pop();
task_t task;
{
std::unique_lock task_lock{ _task_mutex };
_task_cv.wait(task_lock, [this] { return !_task_queue.empty() || _shutdown_request; });
if (_shutdown_request)
{
return;
}
task = std::move(_task_queue.front());
_task_queue.pop();
}
task();
}
task();
}
}
OnThreadExecutor::~OnThreadExecutor() {
_shutdown_request = true;
_task_cv.notify_one();
_worker_thread.join();
OnThreadExecutor::~OnThreadExecutor()
{
_shutdown_request = true;
_task_cv.notify_one();
_worker_thread.join();
}

View file

@ -10,21 +10,22 @@
// This might come in handy if you use the API which sets thread-wide global state and the state needs
// to be isolated.
class OnThreadExecutor final {
class OnThreadExecutor final
{
public:
using task_t = std::packaged_task<void()>;
using task_t = std::packaged_task<void()>;
OnThreadExecutor();
~OnThreadExecutor();
std::future<void> submit(task_t task);
OnThreadExecutor();
~OnThreadExecutor();
std::future<void> submit(task_t task);
private:
void worker_thread();
void worker_thread();
std::thread _worker_thread;
std::thread _worker_thread;
std::mutex _task_mutex;
std::condition_variable _task_cv;
std::atomic_bool _shutdown_request;
std::queue<std::packaged_task<void()>> _task_queue;
std::mutex _task_mutex;
std::condition_variable _task_cv;
std::atomic_bool _shutdown_request;
std::queue<std::packaged_task<void()>> _task_queue;
};

View file

@ -22,4 +22,3 @@
#include <unordered_set>
#include <string>
#include <vector>

View file

@ -3,62 +3,72 @@
#include <filesystem>
#include <fstream>
namespace PTSettingsHelper {
namespace PTSettingsHelper
{
constexpr inline const wchar_t* settings_filename = L"\\settings.json";
constexpr inline const wchar_t * settings_filename = L"\\settings.json";
std::wstring get_root_save_folder_location()
{
PWSTR local_app_path;
winrt::check_hresult(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &local_app_path));
std::wstring result{ local_app_path };
CoTaskMemFree(local_app_path);
std::wstring get_root_save_folder_location() {
PWSTR local_app_path;
winrt::check_hresult(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &local_app_path));
std::wstring result{local_app_path};
CoTaskMemFree(local_app_path);
result += L"\\Microsoft\\PowerToys";
std::filesystem::path save_path(result);
if (!std::filesystem::exists(save_path)) {
std::filesystem::create_directories(save_path);
result += L"\\Microsoft\\PowerToys";
std::filesystem::path save_path(result);
if (!std::filesystem::exists(save_path))
{
std::filesystem::create_directories(save_path);
}
return result;
}
return result;
}
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name) {
std::wstring result = get_root_save_folder_location();
result += L"\\";
result += powertoy_name;
std::filesystem::path save_path(result);
if (!std::filesystem::exists(save_path)) {
std::filesystem::create_directories(save_path);
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name)
{
std::wstring result = get_root_save_folder_location();
result += L"\\";
result += powertoy_name;
std::filesystem::path save_path(result);
if (!std::filesystem::exists(save_path))
{
std::filesystem::create_directories(save_path);
}
return result;
}
return result;
}
std::wstring get_module_save_file_location(std::wstring_view powertoy_name) {
return get_module_save_folder_location(powertoy_name) + settings_filename;
}
std::wstring get_module_save_file_location(std::wstring_view powertoy_name)
{
return get_module_save_folder_location(powertoy_name) + settings_filename;
}
std::wstring get_powertoys_general_save_file_location() {
return get_root_save_folder_location() + settings_filename;
}
std::wstring get_powertoys_general_save_file_location()
{
return get_root_save_folder_location() + settings_filename;
}
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings) {
const std::wstring save_file_location = get_module_save_file_location(powertoy_name);
json::to_file(save_file_location, settings);
}
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings)
{
const std::wstring save_file_location = get_module_save_file_location(powertoy_name);
json::to_file(save_file_location, settings);
}
json::JsonObject load_module_settings(std::wstring_view powertoy_name) {
const std::wstring save_file_location = get_module_save_file_location(powertoy_name);
auto saved_settings = json::from_file(save_file_location);
return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{};
}
json::JsonObject load_module_settings(std::wstring_view powertoy_name)
{
const std::wstring save_file_location = get_module_save_file_location(powertoy_name);
auto saved_settings = json::from_file(save_file_location);
return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{};
}
void save_general_settings(const json::JsonObject& settings) {
const std::wstring save_file_location = get_powertoys_general_save_file_location();
json::to_file(save_file_location, settings);
}
void save_general_settings(const json::JsonObject& settings)
{
const std::wstring save_file_location = get_powertoys_general_save_file_location();
json::to_file(save_file_location, settings);
}
json::JsonObject load_general_settings() {
const std::wstring save_file_location = get_powertoys_general_save_file_location();
auto saved_settings = json::from_file(save_file_location);
return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{};
}
json::JsonObject load_general_settings()
{
const std::wstring save_file_location = get_powertoys_general_save_file_location();
auto saved_settings = json::from_file(save_file_location);
return saved_settings.has_value() ? std::move(*saved_settings) : json::JsonObject{};
}
}

View file

@ -4,14 +4,14 @@
#include "json.h"
namespace PTSettingsHelper {
namespace PTSettingsHelper
{
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
std::wstring get_root_save_folder_location();
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
std::wstring get_root_save_folder_location();
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings);
json::JsonObject load_module_settings(std::wstring_view powertoy_name);
void save_general_settings(const json::JsonObject& settings);
json::JsonObject load_general_settings();
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings);
json::JsonObject load_module_settings(std::wstring_view powertoy_name);
void save_general_settings(const json::JsonObject& settings);
json::JsonObject load_general_settings();
}

View file

@ -2,298 +2,350 @@
#include "settings_objects.h"
#include "settings_helpers.h"
namespace PowerToysSettings {
Settings::Settings(const HINSTANCE hinstance, std::wstring_view powertoy_name) {
m_instance = hinstance;
m_json.SetNamedValue(L"version", json::value(L"1.0"));
m_json.SetNamedValue(L"name", json::value(powertoy_name));
m_json.SetNamedValue(L"properties", json::JsonObject{});
}
void Settings::set_description(UINT resource_id) {
m_json.SetNamedValue(L"description", json::value(get_resource(resource_id)));
}
void Settings::set_description(std::wstring_view description) {
m_json.SetNamedValue(L"description", json::value(description));
}
void Settings::set_icon_key(std::wstring_view icon_key) {
m_json.SetNamedValue(L"icon_key", json::value(icon_key));
}
void Settings::set_overview_link(std::wstring_view overview_link) {
m_json.SetNamedValue(L"overview_link", json::value(overview_link));
}
void Settings::set_video_link(std::wstring_view video_link) {
m_json.SetNamedValue(L"video_link", json::value(video_link));
}
// add_bool_toogle overloads.
void Settings::add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value) {
add_bool_toogle(name, get_resource(description_resource_id), value);
}
void Settings::add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value) {
json::JsonObject toggle;
toggle.SetNamedValue(L"display_name", json::value(description));
toggle.SetNamedValue(L"editor_type", json::value(L"bool_toggle"));
toggle.SetNamedValue(L"value", json::value(value));
toggle.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, toggle);
}
// add_int_spinner overloads.
void Settings::add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step) {
add_int_spinner(name, get_resource(description_resource_id), value, min, max, step);
}
void Settings::add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step) {
json::JsonObject spinner;
spinner.SetNamedValue(L"display_name", json::value(description));
spinner.SetNamedValue(L"editor_type", json::value(L"int_spinner"));
spinner.SetNamedValue(L"value", json::value(value));
spinner.SetNamedValue(L"min", json::value(min));
spinner.SetNamedValue(L"max", json::value(max));
spinner.SetNamedValue(L"step", json::value(step));
spinner.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, spinner);
}
// add_string overloads.
void Settings::add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value) {
add_string(name, get_resource(description_resource_id), value);
}
void Settings::add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value) {
json::JsonObject string;
string.SetNamedValue(L"display_name", json::value(description));
string.SetNamedValue(L"editor_type", json::value(L"string_text"));
string.SetNamedValue(L"value", json::value(value));
string.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, string);
}
// add_multiline_string overloads.
void Settings::add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value) {
add_multiline_string(name, get_resource(description_resource_id), value);
}
void Settings::add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value) {
json::JsonObject ml_string;
ml_string.SetNamedValue(L"display_name", json::value(description));
ml_string.SetNamedValue(L"editor_type", json::value(L"string_text"));
ml_string.SetNamedValue(L"value", json::value(value));
ml_string.SetNamedValue(L"order", json::value(++m_curr_priority));
ml_string.SetNamedValue(L"multiline", json::value(true));
m_json.GetNamedObject(L"properties").SetNamedValue(name, ml_string);
}
// add_color_picker overloads.
void Settings::add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value) {
add_color_picker(name, get_resource(description_resource_id), value);
}
void Settings::add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value) {
json::JsonObject picker;
picker.SetNamedValue(L"display_name", json::value(description));
picker.SetNamedValue(L"editor_type", json::value(L"color_picker"));
picker.SetNamedValue(L"value", json::value(value));
picker.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, picker);
}
void Settings::add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey) {
add_hotkey(name, get_resource(description_resource_id), hotkey);
}
void Settings::add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey_obj) {
json::JsonObject hotkey;
hotkey.SetNamedValue(L"display_name", json::value(description));
hotkey.SetNamedValue(L"editor_type", json::value(L"hotkey"));
hotkey.SetNamedValue(L"value", hotkey_obj.get_json());
hotkey.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, hotkey);
}
void Settings::add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids) {
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids) {
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_choice_group(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts) {
json::JsonObject choice_group;
choice_group.SetNamedValue(L"display_name", json::value(description));
choice_group.SetNamedValue(L"editor_type", json::value(L"choice_group"));
json::JsonArray options;
for(const auto & [key, text] : keys_and_texts) {
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
choice_group.SetNamedValue(L"options", std::move(options));
choice_group.SetNamedValue(L"value", json::value(value));
choice_group.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, choice_group);
}
void Settings::add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids) {
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids) {
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_dropdown(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts) {
json::JsonObject dropdown;
dropdown.SetNamedValue(L"display_name", json::value(description));
dropdown.SetNamedValue(L"editor_type", json::value(L"dropdown"));
json::JsonArray options;
for(const auto & [key, text] : keys_and_texts) {
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
dropdown.SetNamedValue(L"options", std::move(options));
dropdown.SetNamedValue(L"value", json::value(value));
dropdown.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, dropdown);
}
// add_custom_action overloads.
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id) {
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), get_resource(ext_description_resource_id));
}
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value) {
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), value);
}
void Settings::add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value) {
json::JsonObject custom_action;
custom_action.SetNamedValue(L"display_name", json::value(description));
custom_action.SetNamedValue(L"button_text", json::value(button_text));
custom_action.SetNamedValue(L"editor_type", json::value(L"custom_action"));
custom_action.SetNamedValue(L"value", json::value(value));
custom_action.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, custom_action);
}
// Serialization methods.
std::wstring Settings::serialize() {
return m_json.Stringify().c_str();
}
bool Settings::serialize_to_buffer(wchar_t* buffer, int *buffer_size) {
auto result = m_json.Stringify();
const int result_len = (int)result.size() + 1;
if (buffer == nullptr || *buffer_size < result_len) {
*buffer_size = result_len;
return false;
} else {
wcscpy_s(buffer, *buffer_size, result.c_str());
return true;
}
}
// Resource helper.
std::wstring Settings::get_resource(UINT resource_id) {
if (resource_id != 0) {
wchar_t* res_ptr;
const size_t resource_length = LoadStringW(m_instance, resource_id, reinterpret_cast<wchar_t *>(&res_ptr), 0);
if (resource_length != 0) {
return {*reinterpret_cast<wchar_t **>(&res_ptr), resource_length};
}
namespace PowerToysSettings
{
Settings::Settings(const HINSTANCE hinstance, std::wstring_view powertoy_name)
{
m_instance = hinstance;
m_json.SetNamedValue(L"version", json::value(L"1.0"));
m_json.SetNamedValue(L"name", json::value(powertoy_name));
m_json.SetNamedValue(L"properties", json::JsonObject{});
}
return L"RESOURCE ID NOT FOUND: " + std::to_wstring(resource_id);
}
PowerToyValues::PowerToyValues(std::wstring_view powertoy_name) {
_name = powertoy_name;
set_version();
m_json.SetNamedValue(L"name", json::value(powertoy_name));
m_json.SetNamedValue(L"properties", json::JsonObject{});
}
PowerToyValues PowerToyValues::from_json_string(std::wstring_view json) {
PowerToyValues result = PowerToyValues();
result.m_json = json::JsonValue::Parse(json).GetObjectW();
result._name = result.m_json.GetNamedString(L"name");
return result;
}
PowerToyValues PowerToyValues::load_from_settings_file(std::wstring_view powertoy_name) {
PowerToyValues result = PowerToyValues();
result.m_json = PTSettingsHelper::load_module_settings(powertoy_name);
result._name = powertoy_name;
return result;
}
inline bool has_property(const json::JsonObject& o, std::wstring_view name, const json::JsonValueType type) {
const json::JsonObject props = o.GetNamedObject(L"properties", json::JsonObject{});
return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type);
}
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name) {
if (!has_property(m_json, property_name, json::JsonValueType::Boolean)) {
return std::nullopt;
void Settings::set_description(UINT resource_id)
{
m_json.SetNamedValue(L"description", json::value(get_resource(resource_id)));
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedBoolean(L"value");
}
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name) {
if (!has_property(m_json, property_name, json::JsonValueType::Number)) {
return std::nullopt;
void Settings::set_description(std::wstring_view description)
{
m_json.SetNamedValue(L"description", json::value(description));
}
return static_cast<int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value"));
}
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name) {
if (!has_property(m_json, property_name, json::JsonValueType::String)) {
return std::nullopt;
void Settings::set_icon_key(std::wstring_view icon_key)
{
m_json.SetNamedValue(L"icon_key", json::value(icon_key));
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedString(L"value").c_str();
}
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name) {
if (!has_property(m_json, property_name, json::JsonValueType::Object)) {
return std::nullopt;
void Settings::set_overview_link(std::wstring_view overview_link)
{
m_json.SetNamedValue(L"overview_link", json::value(overview_link));
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedObject(L"value");
}
std::wstring PowerToyValues::serialize() {
set_version();
return m_json.Stringify().c_str();
}
void Settings::set_video_link(std::wstring_view video_link)
{
m_json.SetNamedValue(L"video_link", json::value(video_link));
}
void PowerToyValues::save_to_settings_file() {
set_version();
PTSettingsHelper::save_module_settings(_name, m_json);
}
// add_bool_toogle overloads.
void Settings::add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value)
{
add_bool_toogle(name, get_resource(description_resource_id), value);
}
void PowerToyValues::set_version() {
m_json.SetNamedValue(L"version", json::value(m_version));
}
void Settings::add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value)
{
json::JsonObject toggle;
toggle.SetNamedValue(L"display_name", json::value(description));
toggle.SetNamedValue(L"editor_type", json::value(L"bool_toggle"));
toggle.SetNamedValue(L"value", json::value(value));
toggle.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, toggle);
}
// add_int_spinner overloads.
void Settings::add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step)
{
add_int_spinner(name, get_resource(description_resource_id), value, min, max, step);
}
void Settings::add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step)
{
json::JsonObject spinner;
spinner.SetNamedValue(L"display_name", json::value(description));
spinner.SetNamedValue(L"editor_type", json::value(L"int_spinner"));
spinner.SetNamedValue(L"value", json::value(value));
spinner.SetNamedValue(L"min", json::value(min));
spinner.SetNamedValue(L"max", json::value(max));
spinner.SetNamedValue(L"step", json::value(step));
spinner.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, spinner);
}
// add_string overloads.
void Settings::add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value)
{
add_string(name, get_resource(description_resource_id), value);
}
void Settings::add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value)
{
json::JsonObject string;
string.SetNamedValue(L"display_name", json::value(description));
string.SetNamedValue(L"editor_type", json::value(L"string_text"));
string.SetNamedValue(L"value", json::value(value));
string.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, string);
}
// add_multiline_string overloads.
void Settings::add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value)
{
add_multiline_string(name, get_resource(description_resource_id), value);
}
void Settings::add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value)
{
json::JsonObject ml_string;
ml_string.SetNamedValue(L"display_name", json::value(description));
ml_string.SetNamedValue(L"editor_type", json::value(L"string_text"));
ml_string.SetNamedValue(L"value", json::value(value));
ml_string.SetNamedValue(L"order", json::value(++m_curr_priority));
ml_string.SetNamedValue(L"multiline", json::value(true));
m_json.GetNamedObject(L"properties").SetNamedValue(name, ml_string);
}
// add_color_picker overloads.
void Settings::add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value)
{
add_color_picker(name, get_resource(description_resource_id), value);
}
void Settings::add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value)
{
json::JsonObject picker;
picker.SetNamedValue(L"display_name", json::value(description));
picker.SetNamedValue(L"editor_type", json::value(L"color_picker"));
picker.SetNamedValue(L"value", json::value(value));
picker.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, picker);
}
void Settings::add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey)
{
add_hotkey(name, get_resource(description_resource_id), hotkey);
}
void Settings::add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey_obj)
{
json::JsonObject hotkey;
hotkey.SetNamedValue(L"display_name", json::value(description));
hotkey.SetNamedValue(L"editor_type", json::value(L"hotkey"));
hotkey.SetNamedValue(L"value", hotkey_obj.get_json());
hotkey.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, hotkey);
}
void Settings::add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids)
{
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids)
{
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_choice_group(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts)
{
json::JsonObject choice_group;
choice_group.SetNamedValue(L"display_name", json::value(description));
choice_group.SetNamedValue(L"editor_type", json::value(L"choice_group"));
json::JsonArray options;
for (const auto& [key, text] : keys_and_texts)
{
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
choice_group.SetNamedValue(L"options", std::move(options));
choice_group.SetNamedValue(L"value", json::value(value));
choice_group.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, choice_group);
}
void Settings::add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids)
{
std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts;
keys_and_texts.reserve(keys_and_text_ids.size());
for (const auto& kv : keys_and_text_ids)
{
keys_and_texts.emplace_back(kv.first, get_resource(kv.second));
}
add_dropdown(name, get_resource(description_resource_id), value, keys_and_texts);
}
void Settings::add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts)
{
json::JsonObject dropdown;
dropdown.SetNamedValue(L"display_name", json::value(description));
dropdown.SetNamedValue(L"editor_type", json::value(L"dropdown"));
json::JsonArray options;
for (const auto& [key, text] : keys_and_texts)
{
json::JsonObject entry;
entry.SetNamedValue(L"key", json::value(key));
entry.SetNamedValue(L"text", json::value(text));
options.Append(std::move(entry));
}
dropdown.SetNamedValue(L"options", std::move(options));
dropdown.SetNamedValue(L"value", json::value(value));
dropdown.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, dropdown);
}
// add_custom_action overloads.
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id)
{
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), get_resource(ext_description_resource_id));
}
void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value)
{
add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), value);
}
void Settings::add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value)
{
json::JsonObject custom_action;
custom_action.SetNamedValue(L"display_name", json::value(description));
custom_action.SetNamedValue(L"button_text", json::value(button_text));
custom_action.SetNamedValue(L"editor_type", json::value(L"custom_action"));
custom_action.SetNamedValue(L"value", json::value(value));
custom_action.SetNamedValue(L"order", json::value(++m_curr_priority));
m_json.GetNamedObject(L"properties").SetNamedValue(name, custom_action);
}
// Serialization methods.
std::wstring Settings::serialize()
{
return m_json.Stringify().c_str();
}
bool Settings::serialize_to_buffer(wchar_t* buffer, int* buffer_size)
{
auto result = m_json.Stringify();
const int result_len = (int)result.size() + 1;
if (buffer == nullptr || *buffer_size < result_len)
{
*buffer_size = result_len;
return false;
}
else
{
wcscpy_s(buffer, *buffer_size, result.c_str());
return true;
}
}
// Resource helper.
std::wstring Settings::get_resource(UINT resource_id)
{
if (resource_id != 0)
{
wchar_t* res_ptr;
const size_t resource_length = LoadStringW(m_instance, resource_id, reinterpret_cast<wchar_t*>(&res_ptr), 0);
if (resource_length != 0)
{
return { *reinterpret_cast<wchar_t**>(&res_ptr), resource_length };
}
}
return L"RESOURCE ID NOT FOUND: " + std::to_wstring(resource_id);
}
PowerToyValues::PowerToyValues(std::wstring_view powertoy_name)
{
_name = powertoy_name;
set_version();
m_json.SetNamedValue(L"name", json::value(powertoy_name));
m_json.SetNamedValue(L"properties", json::JsonObject{});
}
PowerToyValues PowerToyValues::from_json_string(std::wstring_view json)
{
PowerToyValues result = PowerToyValues();
result.m_json = json::JsonValue::Parse(json).GetObjectW();
result._name = result.m_json.GetNamedString(L"name");
return result;
}
PowerToyValues PowerToyValues::load_from_settings_file(std::wstring_view powertoy_name)
{
PowerToyValues result = PowerToyValues();
result.m_json = PTSettingsHelper::load_module_settings(powertoy_name);
result._name = powertoy_name;
return result;
}
inline bool has_property(const json::JsonObject& o, std::wstring_view name, const json::JsonValueType type)
{
const json::JsonObject props = o.GetNamedObject(L"properties", json::JsonObject{});
return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type);
}
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Boolean))
{
return std::nullopt;
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedBoolean(L"value");
}
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Number))
{
return std::nullopt;
}
return static_cast<int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value"));
}
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::String))
{
return std::nullopt;
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedString(L"value").c_str();
}
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name)
{
if (!has_property(m_json, property_name, json::JsonValueType::Object))
{
return std::nullopt;
}
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedObject(L"value");
}
std::wstring PowerToyValues::serialize()
{
set_version();
return m_json.Stringify().c_str();
}
void PowerToyValues::save_to_settings_file()
{
set_version();
PTSettingsHelper::save_module_settings(_name, m_json);
}
void PowerToyValues::set_version()
{
m_json.SetNamedValue(L"version", json::value(m_version));
}
}

View file

@ -2,184 +2,220 @@
#include "json.h"
namespace PowerToysSettings {
namespace PowerToysSettings
{
class HotkeyObject;
class HotkeyObject;
class Settings {
public:
Settings(
const HINSTANCE hinstance, // Module handle of the PowerToy DLL 'IMAGE_DOS_HEADER __ImageBase'
std::wstring_view powertoy_name
);
// Add additional general information to the PowerToy settings.
void set_description(UINT resource_id);
void set_description(std::wstring_view description);
void set_icon_key(std::wstring_view icon_key);
void set_overview_link(std::wstring_view overview_link);
void set_video_link(std::wstring_view video_link);
// Add properties to the PowerToy settings.
void add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value);
void add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value);
void add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step);
void add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step);
void add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
void add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
void add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value);
void add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey);
void add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey);
void add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
void add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
void add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
void add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id);
void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value);
void add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value);
// Serialize the internal json to a string.
std::wstring serialize();
// Serialize the internal json to the input buffer.
bool serialize_to_buffer(wchar_t* buffer, int* buffer_size);
private:
json::JsonObject m_json;
int m_curr_priority = 0; // For keeping order when adding elements.
HINSTANCE m_instance;
std::wstring get_resource(UINT resource_id);
};
class PowerToyValues {
public:
PowerToyValues(std::wstring_view powertoy_name);
static PowerToyValues from_json_string(std::wstring_view json);
static PowerToyValues load_from_settings_file(std::wstring_view powertoy_name);
template <typename T>
inline void add_property(std::wstring_view name, T value)
class Settings
{
json::JsonObject prop_value;
prop_value.SetNamedValue(L"value", json::value(value));
m_json.GetNamedObject(L"properties").SetNamedValue(name, prop_value);
}
public:
Settings(
const HINSTANCE hinstance, // Module handle of the PowerToy DLL 'IMAGE_DOS_HEADER __ImageBase'
std::wstring_view powertoy_name);
std::optional<bool> get_bool_value(std::wstring_view property_name);
std::optional<int> get_int_value(std::wstring_view property_name);
std::optional<std::wstring> get_string_value(std::wstring_view property_name);
std::optional<json::JsonObject> get_json(std::wstring_view property_name);
// Add additional general information to the PowerToy settings.
void set_description(UINT resource_id);
void set_description(std::wstring_view description);
std::wstring serialize();
void save_to_settings_file();
void set_icon_key(std::wstring_view icon_key);
void set_overview_link(std::wstring_view overview_link);
void set_video_link(std::wstring_view video_link);
private:
const std::wstring m_version = L"1.0";
void set_version();
json::JsonObject m_json;
std::wstring _name;
PowerToyValues() {}
};
// Add properties to the PowerToy settings.
void add_bool_toogle(std::wstring_view name, UINT description_resource_id, bool value);
void add_bool_toogle(std::wstring_view name, std::wstring_view description, bool value);
class CustomActionObject {
public:
static CustomActionObject from_json_string(std::wstring_view json) {
return CustomActionObject(json::JsonValue::Parse(json).GetObjectW());
}
void add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step);
void add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step);
std::wstring get_name() { return m_json.GetNamedString(L"action_name").c_str(); }
std::wstring get_value() { return m_json.GetNamedString(L"value").c_str(); }
void add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
protected:
CustomActionObject(json::JsonObject action_json) : m_json(std::move(action_json)) {};
json::JsonObject m_json;
};
class HotkeyObject {
public:
static HotkeyObject from_json(json::JsonObject json) {
return HotkeyObject(std::move(json));
}
static HotkeyObject from_json_string(std::wstring_view json) {
return HotkeyObject(json::JsonValue::Parse(json).GetObjectW());
}
static HotkeyObject from_settings(bool win_pressed, bool ctrl_pressed, bool alt_pressed, bool shift_pressed, UINT vk_code) {
json::JsonObject json;
json.SetNamedValue(L"win", json::value(win_pressed));
json.SetNamedValue(L"ctrl", json::value(ctrl_pressed));
json.SetNamedValue(L"alt", json::value(alt_pressed));
json.SetNamedValue(L"shift", json::value(shift_pressed));
json.SetNamedValue(L"code", json::value(vk_code));
json.SetNamedValue(L"key", json::value(key_from_code(vk_code)));
return std::move(json);
}
const json::JsonObject& get_json() const { return m_json; }
void add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value);
std::wstring get_key() const { return m_json.GetNamedString(L"key").c_str(); }
UINT get_code() const { return static_cast<UINT>(m_json.GetNamedNumber(L"code")); }
bool win_pressed() const { return m_json.GetNamedBoolean(L"win"); }
bool ctrl_pressed() const { return m_json.GetNamedBoolean(L"ctrl"); }
bool alt_pressed() const { return m_json.GetNamedBoolean(L"alt"); }
bool shift_pressed() const { return m_json.GetNamedBoolean(L"shift"); }
UINT get_modifiers_repeat() const {
return (win_pressed() ? MOD_WIN : 0) |
(ctrl_pressed() ? MOD_CONTROL : 0) |
(alt_pressed() ? MOD_ALT : 0) |
(shift_pressed() ? MOD_SHIFT : 0);
}
UINT get_modifiers() const {
return get_modifiers_repeat() | MOD_NOREPEAT;
}
protected:
static std::wstring key_from_code(UINT key_code) {
auto layout = GetKeyboardLayout(0);
auto scan_code = MapVirtualKeyExW(key_code, MAPVK_VK_TO_VSC_EX, layout);
// Determinate if vk is an extended key. Unfortunatly MAPVK_VK_TO_VSC_EX
// does not return correct values.
static std::vector<UINT> extended_keys = {
VK_APPS, VK_CANCEL, VK_SNAPSHOT, VK_DIVIDE, VK_NUMLOCK, VK_LWIN, VK_RWIN, VK_RMENU,
VK_RCONTROL, VK_RSHIFT, VK_RETURN, VK_INSERT, VK_DELETE, VK_PRIOR, VK_NEXT,
VK_HOME, VK_END, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT,
};
if (find(begin(extended_keys), end(extended_keys), key_code) != end(extended_keys)) {
scan_code |= 0x100;
}
std::array<BYTE, 256> key_states{}; // Zero-initialize
std::array<wchar_t, 256> output;
auto output_bytes = ToUnicodeEx(key_code, scan_code, key_states.data(), output.data(), (int)output.size() - 1, 0, layout);
if (output_bytes <= 0) {
// If ToUnicodeEx fails (e.g. for F1-F12 keys) use GetKeyNameTextW
output_bytes = GetKeyNameTextW(scan_code << 16, output.data(), static_cast<int>(output.size()));
}
if (output_bytes > 0) {
output[output_bytes] = 0;
if (output_bytes == 1 && output[0] >= 'a' && output[0] <= 'z') {
// Make Latin letters keys capital, as it looks better
output[0] = toupper(output[0]);
}
return output.data();
}
return L"(Key " + std::to_wstring(key_code) + L")";
}
HotkeyObject(json::JsonObject hotkey_json) : m_json(std::move(hotkey_json)) {
if (get_key() == L"~" && get_modifiers_repeat() == MOD_WIN) {
m_json.SetNamedValue(L"key", json::value(key_from_code(get_code())));
}
void add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value);
void add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value);
void add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey);
void add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey);
void add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
void add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
void add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids);
void add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts);
void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id);
void add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value);
void add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value);
// Serialize the internal json to a string.
std::wstring serialize();
// Serialize the internal json to the input buffer.
bool serialize_to_buffer(wchar_t* buffer, int* buffer_size);
private:
json::JsonObject m_json;
int m_curr_priority = 0; // For keeping order when adding elements.
HINSTANCE m_instance;
std::wstring get_resource(UINT resource_id);
};
class PowerToyValues
{
public:
PowerToyValues(std::wstring_view powertoy_name);
static PowerToyValues from_json_string(std::wstring_view json);
static PowerToyValues load_from_settings_file(std::wstring_view powertoy_name);
template<typename T>
inline void add_property(std::wstring_view name, T value)
{
json::JsonObject prop_value;
prop_value.SetNamedValue(L"value", json::value(value));
m_json.GetNamedObject(L"properties").SetNamedValue(name, prop_value);
}
std::optional<bool> get_bool_value(std::wstring_view property_name);
std::optional<int> get_int_value(std::wstring_view property_name);
std::optional<std::wstring> get_string_value(std::wstring_view property_name);
std::optional<json::JsonObject> get_json(std::wstring_view property_name);
std::wstring serialize();
void save_to_settings_file();
private:
const std::wstring m_version = L"1.0";
void set_version();
json::JsonObject m_json;
std::wstring _name;
PowerToyValues() {}
};
class CustomActionObject
{
public:
static CustomActionObject from_json_string(std::wstring_view json)
{
return CustomActionObject(json::JsonValue::Parse(json).GetObjectW());
}
std::wstring get_name() { return m_json.GetNamedString(L"action_name").c_str(); }
std::wstring get_value() { return m_json.GetNamedString(L"value").c_str(); }
protected:
CustomActionObject(json::JsonObject action_json) :
m_json(std::move(action_json)){};
json::JsonObject m_json;
};
class HotkeyObject
{
public:
static HotkeyObject from_json(json::JsonObject json)
{
return HotkeyObject(std::move(json));
}
static HotkeyObject from_json_string(std::wstring_view json)
{
return HotkeyObject(json::JsonValue::Parse(json).GetObjectW());
}
static HotkeyObject from_settings(bool win_pressed, bool ctrl_pressed, bool alt_pressed, bool shift_pressed, UINT vk_code)
{
json::JsonObject json;
json.SetNamedValue(L"win", json::value(win_pressed));
json.SetNamedValue(L"ctrl", json::value(ctrl_pressed));
json.SetNamedValue(L"alt", json::value(alt_pressed));
json.SetNamedValue(L"shift", json::value(shift_pressed));
json.SetNamedValue(L"code", json::value(vk_code));
json.SetNamedValue(L"key", json::value(key_from_code(vk_code)));
return std::move(json);
}
const json::JsonObject& get_json() const { return m_json; }
std::wstring get_key() const { return m_json.GetNamedString(L"key").c_str(); }
UINT get_code() const { return static_cast<UINT>(m_json.GetNamedNumber(L"code")); }
bool win_pressed() const { return m_json.GetNamedBoolean(L"win"); }
bool ctrl_pressed() const { return m_json.GetNamedBoolean(L"ctrl"); }
bool alt_pressed() const { return m_json.GetNamedBoolean(L"alt"); }
bool shift_pressed() const { return m_json.GetNamedBoolean(L"shift"); }
UINT get_modifiers_repeat() const
{
return (win_pressed() ? MOD_WIN : 0) |
(ctrl_pressed() ? MOD_CONTROL : 0) |
(alt_pressed() ? MOD_ALT : 0) |
(shift_pressed() ? MOD_SHIFT : 0);
}
UINT get_modifiers() const
{
return get_modifiers_repeat() | MOD_NOREPEAT;
}
protected:
static std::wstring key_from_code(UINT key_code)
{
auto layout = GetKeyboardLayout(0);
auto scan_code = MapVirtualKeyExW(key_code, MAPVK_VK_TO_VSC_EX, layout);
// Determinate if vk is an extended key. Unfortunatly MAPVK_VK_TO_VSC_EX
// does not return correct values.
static std::vector<UINT> extended_keys = {
VK_APPS,
VK_CANCEL,
VK_SNAPSHOT,
VK_DIVIDE,
VK_NUMLOCK,
VK_LWIN,
VK_RWIN,
VK_RMENU,
VK_RCONTROL,
VK_RSHIFT,
VK_RETURN,
VK_INSERT,
VK_DELETE,
VK_PRIOR,
VK_NEXT,
VK_HOME,
VK_END,
VK_UP,
VK_DOWN,
VK_LEFT,
VK_RIGHT,
};
if (find(begin(extended_keys), end(extended_keys), key_code) != end(extended_keys))
{
scan_code |= 0x100;
}
std::array<BYTE, 256> key_states{}; // Zero-initialize
std::array<wchar_t, 256> output;
auto output_bytes = ToUnicodeEx(key_code, scan_code, key_states.data(), output.data(), (int)output.size() - 1, 0, layout);
if (output_bytes <= 0)
{
// If ToUnicodeEx fails (e.g. for F1-F12 keys) use GetKeyNameTextW
output_bytes = GetKeyNameTextW(scan_code << 16, output.data(), static_cast<int>(output.size()));
}
if (output_bytes > 0)
{
output[output_bytes] = 0;
if (output_bytes == 1 && output[0] >= 'a' && output[0] <= 'z')
{
// Make Latin letters keys capital, as it looks better
output[0] = toupper(output[0]);
}
return output.data();
}
return L"(Key " + std::to_wstring(key_code) + L")";
}
HotkeyObject(json::JsonObject hotkey_json) :
m_json(std::move(hotkey_json))
{
if (get_key() == L"~" && get_modifiers_repeat() == MOD_WIN)
{
m_json.SetNamedValue(L"key", json::value(key_from_code(get_code())));
}
};
json::JsonObject m_json;
};
json::JsonObject m_json;
};
}

View file

@ -1,16 +1,18 @@
#include "pch.h"
#include "start_visible.h"
bool is_start_visible() {
static winrt::com_ptr<IAppVisibility> app_visibility;
if (!app_visibility) {
winrt::check_hresult(CoCreateInstance(CLSID_AppVisibility,
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(app_visibility),
app_visibility.put_void()));
}
BOOL visible;
auto result = app_visibility->IsLauncherVisible(&visible);
return SUCCEEDED(result) && visible;
bool is_start_visible()
{
static winrt::com_ptr<IAppVisibility> app_visibility;
if (!app_visibility)
{
winrt::check_hresult(CoCreateInstance(CLSID_AppVisibility,
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(app_visibility),
app_visibility.put_void()));
}
BOOL visible;
auto result = app_visibility->IsLauncherVisible(&visible);
return SUCCEEDED(result) && visible;
}

View file

@ -1,4 +1,3 @@
#pragma once
bool is_start_visible();

View file

@ -1,93 +1,116 @@
#include "pch.h"
#include "tasklist_positions.h"
void Tasklist::update() {
// Get HWND of the tasklist
auto tasklist_hwnd = FindWindowA("Shell_TrayWnd", nullptr);
if (!tasklist_hwnd) return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "ReBarWindow32", nullptr);
if (!tasklist_hwnd) return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskSwWClass", nullptr);
if (!tasklist_hwnd) return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskListWClass", nullptr);
if (!tasklist_hwnd) return;
if (!automation) {
winrt::check_hresult(CoCreateInstance(CLSID_CUIAutomation,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
automation.put_void()));
winrt::check_hresult(automation->CreateTrueCondition(true_condition.put()));
}
element = nullptr;
winrt::check_hresult(automation->ElementFromHandle(tasklist_hwnd, element.put()));
void Tasklist::update()
{
// Get HWND of the tasklist
auto tasklist_hwnd = FindWindowA("Shell_TrayWnd", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "ReBarWindow32", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskSwWClass", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskListWClass", nullptr);
if (!tasklist_hwnd)
return;
if (!automation)
{
winrt::check_hresult(CoCreateInstance(CLSID_CUIAutomation,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
automation.put_void()));
winrt::check_hresult(automation->CreateTrueCondition(true_condition.put()));
}
element = nullptr;
winrt::check_hresult(automation->ElementFromHandle(tasklist_hwnd, element.put()));
}
bool Tasklist::update_buttons(std::vector<TasklistButton>& buttons) {
if (!automation || !element) {
return false;
}
winrt::com_ptr<IUIAutomationElementArray> elements;
if (element->FindAll(TreeScope_Children, true_condition.get(), elements.put()) < 0)
return false;
if (!elements)
return false;
int count;
if (elements->get_Length(&count) < 0)
return false;
winrt::com_ptr<IUIAutomationElement> child;
std::vector<TasklistButton> found_butttons;
found_butttons.reserve(count);
for (int i = 0; i < count; ++i) {
child = nullptr;
if (elements->GetElement(i, child.put()) < 0)
return false;
TasklistButton button;
if (VARIANT var_rect; child->GetCurrentPropertyValue(UIA_BoundingRectanglePropertyId, &var_rect) >= 0) {
if (var_rect.vt == (VT_R8 | VT_ARRAY)) {
LONG pos;
double value;
pos = 0; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.x = (long)value;
pos = 1; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.y = (long)value;
pos = 2; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.width = (long)value;
pos = 3; SafeArrayGetElement(var_rect.parray, &pos, &value);
button.height = (long)value;
}
VariantClear(&var_rect);
} else {
return false;
bool Tasklist::update_buttons(std::vector<TasklistButton>& buttons)
{
if (!automation || !element)
{
return false;
}
if (BSTR automation_id; child->get_CurrentAutomationId(&automation_id) >= 0) {
button.name = automation_id;
SysFreeString(automation_id);
winrt::com_ptr<IUIAutomationElementArray> elements;
if (element->FindAll(TreeScope_Children, true_condition.get(), elements.put()) < 0)
return false;
if (!elements)
return false;
int count;
if (elements->get_Length(&count) < 0)
return false;
winrt::com_ptr<IUIAutomationElement> child;
std::vector<TasklistButton> found_butttons;
found_butttons.reserve(count);
for (int i = 0; i < count; ++i)
{
child = nullptr;
if (elements->GetElement(i, child.put()) < 0)
return false;
TasklistButton button;
if (VARIANT var_rect; child->GetCurrentPropertyValue(UIA_BoundingRectanglePropertyId, &var_rect) >= 0)
{
if (var_rect.vt == (VT_R8 | VT_ARRAY))
{
LONG pos;
double value;
pos = 0;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.x = (long)value;
pos = 1;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.y = (long)value;
pos = 2;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.width = (long)value;
pos = 3;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.height = (long)value;
}
VariantClear(&var_rect);
}
else
{
return false;
}
if (BSTR automation_id; child->get_CurrentAutomationId(&automation_id) >= 0)
{
button.name = automation_id;
SysFreeString(automation_id);
}
found_butttons.push_back(button);
}
found_butttons.push_back(button);
}
// assign keynums
buttons.clear();
for (auto& button : found_butttons) {
if (buttons.empty()) {
button.keynum = 1;
buttons.push_back(std::move(button));
} else {
if (button.x < buttons.back().x || button.y < buttons.back().y) // skip 2nd row
break;
if (button.name == buttons.back().name)
continue; // skip buttons from the same app
button.keynum = buttons.back().keynum + 1;
buttons.push_back(std::move(button));
if (buttons.back().keynum == 10)
break; // no more than 10 buttons
// assign keynums
buttons.clear();
for (auto& button : found_butttons)
{
if (buttons.empty())
{
button.keynum = 1;
buttons.push_back(std::move(button));
}
else
{
if (button.x < buttons.back().x || button.y < buttons.back().y) // skip 2nd row
break;
if (button.name == buttons.back().name)
continue; // skip buttons from the same app
button.keynum = buttons.back().keynum + 1;
buttons.push_back(std::move(button));
if (buttons.back().keynum == 10)
break; // no more than 10 buttons
}
}
}
return true;
return true;
}
std::vector<TasklistButton> Tasklist::get_buttons() {
std::vector<TasklistButton> buttons;
update_buttons(buttons);
return buttons;
std::vector<TasklistButton> Tasklist::get_buttons()
{
std::vector<TasklistButton> buttons;
update_buttons(buttons);
return buttons;
}

View file

@ -5,18 +5,21 @@
#include <Windows.h>
#include <UIAutomationClient.h>
struct TasklistButton {
std::wstring name;
long x, y, width, height, keynum;
struct TasklistButton
{
std::wstring name;
long x, y, width, height, keynum;
};
class Tasklist {
class Tasklist
{
public:
void update();
std::vector<TasklistButton> get_buttons();
bool update_buttons(std::vector<TasklistButton>& buttons);
void update();
std::vector<TasklistButton> get_buttons();
bool update_buttons(std::vector<TasklistButton>& buttons);
private:
winrt::com_ptr<IUIAutomation> automation;
winrt::com_ptr<IUIAutomationElement> element;
winrt::com_ptr<IUIAutomationCondition> true_condition;
winrt::com_ptr<IUIAutomation> automation;
winrt::com_ptr<IUIAutomationElement> element;
winrt::com_ptr<IUIAutomationCondition> true_condition;
};

View file

@ -6,424 +6,471 @@
#include <accctrl.h>
#include <aclapi.h>
class TwoWayPipeMessageIPC {
class TwoWayPipeMessageIPC
{
public:
typedef void(*callback_function)(const std::wstring&);
void send(std::wstring msg) {
output_queue.queue_message(msg);
}
TwoWayPipeMessageIPC(std::wstring _input_pipe_name, std::wstring _output_pipe_name, callback_function p_func) {
input_pipe_name = _input_pipe_name;
output_pipe_name = _output_pipe_name;
dispatch_inc_message_function = p_func;
}
void start(HANDLE _restricted_pipe_token) {
output_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_output_queue_thread, this);
input_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_input_queue_thread, this);
input_pipe_thread = std::thread(&TwoWayPipeMessageIPC::start_named_pipe_server, this, _restricted_pipe_token);
}
void end() {
closed = true;
input_queue.interrupt();
input_queue_thread.join();
output_queue.interrupt();
output_queue_thread.join();
pipe_connect_handle_mutex.lock();
if (current_connect_pipe_handle != NULL) {
//Cancels the Pipe currently waiting for a connection.
CancelIoEx(current_connect_pipe_handle,NULL);
typedef void (*callback_function)(const std::wstring&);
void send(std::wstring msg)
{
output_queue.queue_message(msg);
}
TwoWayPipeMessageIPC(std::wstring _input_pipe_name, std::wstring _output_pipe_name, callback_function p_func)
{
input_pipe_name = _input_pipe_name;
output_pipe_name = _output_pipe_name;
dispatch_inc_message_function = p_func;
}
void start(HANDLE _restricted_pipe_token)
{
output_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_output_queue_thread, this);
input_queue_thread = std::thread(&TwoWayPipeMessageIPC::consume_input_queue_thread, this);
input_pipe_thread = std::thread(&TwoWayPipeMessageIPC::start_named_pipe_server, this, _restricted_pipe_token);
}
void end()
{
closed = true;
input_queue.interrupt();
input_queue_thread.join();
output_queue.interrupt();
output_queue_thread.join();
pipe_connect_handle_mutex.lock();
if (current_connect_pipe_handle != NULL)
{
//Cancels the Pipe currently waiting for a connection.
CancelIoEx(current_connect_pipe_handle, NULL);
}
pipe_connect_handle_mutex.unlock();
input_pipe_thread.join();
}
pipe_connect_handle_mutex.unlock();
input_pipe_thread.join();
}
private:
AsyncMessageQueue input_queue;
AsyncMessageQueue output_queue;
std::wstring output_pipe_name;
std::wstring input_pipe_name;
std::thread input_queue_thread;
std::thread output_queue_thread;
std::thread input_pipe_thread;
std::mutex pipe_connect_handle_mutex; // For manipulating the current_connect_pipe
AsyncMessageQueue input_queue;
AsyncMessageQueue output_queue;
std::wstring output_pipe_name;
std::wstring input_pipe_name;
std::thread input_queue_thread;
std::thread output_queue_thread;
std::thread input_pipe_thread;
std::mutex pipe_connect_handle_mutex; // For manipulating the current_connect_pipe
HANDLE current_connect_pipe_handle = NULL;
bool closed = false;
TwoWayPipeMessageIPC::callback_function dispatch_inc_message_function;
const DWORD BUFSIZE = 1024;
HANDLE current_connect_pipe_handle = NULL;
bool closed = false;
TwoWayPipeMessageIPC::callback_function dispatch_inc_message_function;
const DWORD BUFSIZE = 1024;
void send_pipe_message(std::wstring message) {
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-client
HANDLE output_pipe_handle;
const wchar_t* message_send = message.c_str();
BOOL fSuccess = FALSE;
DWORD cbToWrite, cbWritten, dwMode;
const wchar_t* lpszPipename = output_pipe_name.c_str();
void send_pipe_message(std::wstring message)
{
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-client
HANDLE output_pipe_handle;
const wchar_t* message_send = message.c_str();
BOOL fSuccess = FALSE;
DWORD cbToWrite, cbWritten, dwMode;
const wchar_t* lpszPipename = output_pipe_name.c_str();
// Try to open a named pipe; wait for it, if necessary.
// Try to open a named pipe; wait for it, if necessary.
while (1) {
output_pipe_handle = CreateFile(
lpszPipename, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
while (1)
{
output_pipe_handle = CreateFile(
lpszPipename, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// Break if the pipe handle is valid.
// Break if the pipe handle is valid.
if (output_pipe_handle != INVALID_HANDLE_VALUE)
break;
if (output_pipe_handle != INVALID_HANDLE_VALUE)
break;
// Exit if an error other than ERROR_PIPE_BUSY occurs.
DWORD curr_error = 0;
if ((curr_error = GetLastError()) != ERROR_PIPE_BUSY) {
// Exit if an error other than ERROR_PIPE_BUSY occurs.
DWORD curr_error = 0;
if ((curr_error = GetLastError()) != ERROR_PIPE_BUSY)
{
return;
}
// All pipe instances are busy, so wait for 20 seconds.
if (!WaitNamedPipe(lpszPipename, 20000))
{
return;
}
}
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
output_pipe_handle, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!fSuccess)
{
return;
}
// Send a message to the pipe server.
cbToWrite = (lstrlen(message_send)) * sizeof(WCHAR); // no need to send final '\0'. Pipe is in message mode.
fSuccess = WriteFile(
output_pipe_handle, // pipe handle
message_send, // message
cbToWrite, // message length
&cbWritten, // bytes written
NULL); // not overlapped
if (!fSuccess)
{
return;
}
CloseHandle(output_pipe_handle);
return;
}
// All pipe instances are busy, so wait for 20 seconds.
if (!WaitNamedPipe(lpszPipename, 20000)) {
return;
}
}
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
output_pipe_handle, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!fSuccess) {
return;
}
// Send a message to the pipe server.
cbToWrite = (lstrlen(message_send)) * sizeof(WCHAR); // no need to send final '\0'. Pipe is in message mode.
fSuccess = WriteFile(
output_pipe_handle, // pipe handle
message_send, // message
cbToWrite, // message length
&cbWritten, // bytes written
NULL); // not overlapped
if (!fSuccess) {
return;
}
CloseHandle(output_pipe_handle);
return;
}
void consume_output_queue_thread() {
while (!closed) {
std::wstring message = output_queue.pop_message();
if (message.length() == 0) {
break;
}
send_pipe_message(message);
}
}
BOOL GetLogonSID(HANDLE hToken, PSID *ppsid) {
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
BOOL bSuccess = FALSE;
DWORD dwIndex;
DWORD dwLength = 0;
PTOKEN_GROUPS ptg = NULL;
// Verify the parameter passed in is not NULL.
if (NULL == ppsid)
goto Cleanup;
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
if (!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
0, // size of buffer
&dwLength // receives required buffer size
)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptg == NULL)
goto Cleanup;
}
// Get the token group information from the access token.
if (!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
)) {
goto Cleanup;
}
// Loop through the groups to find the logon SID.
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
== SE_GROUP_LOGON_ID) {
// Found the logon SID; make a copy of it.
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
*ppsid = (PSID)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (*ppsid == NULL)
goto Cleanup;
if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid)) {
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
goto Cleanup;
void consume_output_queue_thread()
{
while (!closed)
{
std::wstring message = output_queue.pop_message();
if (message.length() == 0)
{
break;
}
send_pipe_message(message);
}
break;
}
bSuccess = TRUE;
Cleanup:
// Free the buffer for the token groups.
if (ptg != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
return bSuccess;
}
VOID FreeLogonSID(PSID *ppsid) {
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
}
int change_pipe_security_allow_restricted_token(HANDLE handle, HANDLE token) {
PACL old_dacl, new_dacl;
PSECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS ea;
PSID user_restricted;
int error;
if (!GetLogonSID(token, &user_restricted)) {
error = 5; // No access error.
goto Ldone;
}
if (GetSecurityInfo(handle,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&old_dacl,
NULL,
&sd)) {
error = GetLastError();
goto Lclean_sid;
}
BOOL GetLogonSID(HANDLE hToken, PSID* ppsid)
{
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
BOOL bSuccess = FALSE;
DWORD dwIndex;
DWORD dwLength = 0;
PTOKEN_GROUPS ptg = NULL;
memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
ea.grfAccessPermissions |= SYNCHRONIZE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = (LPTSTR)user_restricted;
// Verify the parameter passed in is not NULL.
if (NULL == ppsid)
goto Cleanup;
if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) {
error = GetLastError();
goto Lclean_sd;
}
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
if (SetSecurityInfo(handle,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
new_dacl,
NULL)) {
error = GetLastError();
goto Lclean_dacl;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
error = 0;
ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength);
Lclean_dacl:
LocalFree((HLOCAL)new_dacl);
Lclean_sd:
LocalFree((HLOCAL)sd);
Lclean_sid:
FreeLogonSID(&user_restricted);
Ldone:
return error;
}
HANDLE create_medium_integrity_token() {
HANDLE restricted_token_handle;
SAFER_LEVEL_HANDLE level_handle = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
BYTE medium_sid[SECURITY_MAX_SID_SIZE];
if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &level_handle, NULL)) {
return NULL;
}
if (!SaferComputeTokenFromLevel(level_handle, NULL, &restricted_token_handle, 0, NULL)) {
SaferCloseLevel(level_handle);
return NULL;
}
SaferCloseLevel(level_handle);
if (!CreateWellKnownSid(WinMediumLabelSid, nullptr, medium_sid, &sid_size)) {
CloseHandle(restricted_token_handle);
return NULL;
}
TOKEN_MANDATORY_LABEL integrity_level = { 0 };
integrity_level.Label.Attributes = SE_GROUP_INTEGRITY;
integrity_level.Label.Sid = reinterpret_cast<PSID>(medium_sid);
if (!SetTokenInformation(restricted_token_handle, TokenIntegrityLevel, &integrity_level, sizeof(integrity_level))) {
CloseHandle(restricted_token_handle);
return NULL;
}
return restricted_token_handle;
}
void handle_pipe_connection(HANDLE input_pipe_handle) {
//Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
HANDLE hHeap = GetProcessHeap();
uint8_t* pchRequest = (uint8_t*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(uint8_t));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
// Do some extra error checking since the app will keep running even if this thread fails.
std::list<std::vector<uint8_t>> message_parts;
if (input_pipe_handle == NULL) {
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return;
}
if (pchRequest == NULL) {
return;
}
// Loop until done reading
do {
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
ZeroMemory(pchRequest, BUFSIZE * sizeof(uint8_t));
fSuccess = ReadFile(
input_pipe_handle, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE * sizeof(uint8_t), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess && GetLastError() != ERROR_MORE_DATA) {
break;
}
std::vector<uint8_t> part_vector;
part_vector.reserve(cbBytesRead);
std::copy(pchRequest, pchRequest + cbBytesRead, std::back_inserter(part_vector));
message_parts.push_back(part_vector);
} while (!fSuccess);
if (fSuccess) {
// Reconstruct the total_message.
std::vector<uint8_t> reconstructed_message;
size_t total_size = 0;
for (auto& part_vector : message_parts) {
total_size += part_vector.size();
}
reconstructed_message.reserve(total_size);
for (auto& part_vector : message_parts) {
std::move(part_vector.begin(), part_vector.end(), std::back_inserter(reconstructed_message));
}
std::wstring unicode_msg;
unicode_msg.assign(reinterpret_cast<std::wstring::const_pointer>(reconstructed_message.data()), reconstructed_message.size() / sizeof(std::wstring::value_type));
input_queue.queue_message(unicode_msg);
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(input_pipe_handle);
DisconnectNamedPipe(input_pipe_handle);
CloseHandle(input_pipe_handle);
HeapFree(hHeap, 0, pchRequest);
printf("InstanceThread exitting.\n");
}
void start_named_pipe_server(HANDLE token) {
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
const wchar_t* pipe_name = input_pipe_name.c_str();
BOOL connected = FALSE;
HANDLE connect_pipe_handle = INVALID_HANDLE_VALUE;
while(!closed) {
{
std::unique_lock lock(pipe_connect_handle_mutex);
connect_pipe_handle = CreateNamedPipe(
pipe_name,
PIPE_ACCESS_DUPLEX |
WRITE_DAC,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
0,
NULL
);
if (connect_pipe_handle == INVALID_HANDLE_VALUE) {
return;
if (ptg == NULL)
goto Cleanup;
}
if (token != NULL) {
int err = change_pipe_security_allow_restricted_token(connect_pipe_handle, token);
// Get the token group information from the access token.
if (!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID)ptg, // pointer to TOKEN_GROUPS buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
}
current_connect_pipe_handle = connect_pipe_handle;
}
connected = ConnectNamedPipe(connect_pipe_handle, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
{
std::unique_lock lock(pipe_connect_handle_mutex);
current_connect_pipe_handle = NULL;
}
if (connected) {
std::thread(&TwoWayPipeMessageIPC::handle_pipe_connection, this, connect_pipe_handle).detach();
} else {
// Client could not connect.
CloseHandle(connect_pipe_handle);
}
}
}
void consume_input_queue_thread() {
while (!closed) {
std::wstring message = input_queue.pop_message();
if (message.length() == 0) {
break;
}
dispatch_inc_message_function(message);
}
}
// Loop through the groups to find the logon SID.
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
{
// Found the logon SID; make a copy of it.
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
*ppsid = (PSID)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength);
if (*ppsid == NULL)
goto Cleanup;
if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
{
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
goto Cleanup;
}
break;
}
bSuccess = TRUE;
Cleanup:
// Free the buffer for the token groups.
if (ptg != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
return bSuccess;
}
VOID FreeLogonSID(PSID* ppsid)
{
// From https://docs.microsoft.com/en-us/previous-versions/aa446670(v=vs.85)
HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
}
int change_pipe_security_allow_restricted_token(HANDLE handle, HANDLE token)
{
PACL old_dacl, new_dacl;
PSECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS ea;
PSID user_restricted;
int error;
if (!GetLogonSID(token, &user_restricted))
{
error = 5; // No access error.
goto Ldone;
}
if (GetSecurityInfo(handle,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&old_dacl,
NULL,
&sd))
{
error = GetLastError();
goto Lclean_sid;
}
memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
ea.grfAccessPermissions |= SYNCHRONIZE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = (LPTSTR)user_restricted;
if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl))
{
error = GetLastError();
goto Lclean_sd;
}
if (SetSecurityInfo(handle,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
new_dacl,
NULL))
{
error = GetLastError();
goto Lclean_dacl;
}
error = 0;
Lclean_dacl:
LocalFree((HLOCAL)new_dacl);
Lclean_sd:
LocalFree((HLOCAL)sd);
Lclean_sid:
FreeLogonSID(&user_restricted);
Ldone:
return error;
}
HANDLE create_medium_integrity_token()
{
HANDLE restricted_token_handle;
SAFER_LEVEL_HANDLE level_handle = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
BYTE medium_sid[SECURITY_MAX_SID_SIZE];
if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &level_handle, NULL))
{
return NULL;
}
if (!SaferComputeTokenFromLevel(level_handle, NULL, &restricted_token_handle, 0, NULL))
{
SaferCloseLevel(level_handle);
return NULL;
}
SaferCloseLevel(level_handle);
if (!CreateWellKnownSid(WinMediumLabelSid, nullptr, medium_sid, &sid_size))
{
CloseHandle(restricted_token_handle);
return NULL;
}
TOKEN_MANDATORY_LABEL integrity_level = { 0 };
integrity_level.Label.Attributes = SE_GROUP_INTEGRITY;
integrity_level.Label.Sid = reinterpret_cast<PSID>(medium_sid);
if (!SetTokenInformation(restricted_token_handle, TokenIntegrityLevel, &integrity_level, sizeof(integrity_level)))
{
CloseHandle(restricted_token_handle);
return NULL;
}
return restricted_token_handle;
}
void handle_pipe_connection(HANDLE input_pipe_handle)
{
//Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
HANDLE hHeap = GetProcessHeap();
uint8_t* pchRequest = (uint8_t*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(uint8_t));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
// Do some extra error checking since the app will keep running even if this thread fails.
std::list<std::vector<uint8_t>> message_parts;
if (input_pipe_handle == NULL)
{
if (pchRequest != NULL)
HeapFree(hHeap, 0, pchRequest);
return;
}
if (pchRequest == NULL)
{
return;
}
// Loop until done reading
do
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
ZeroMemory(pchRequest, BUFSIZE * sizeof(uint8_t));
fSuccess = ReadFile(
input_pipe_handle, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE * sizeof(uint8_t), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess && GetLastError() != ERROR_MORE_DATA)
{
break;
}
std::vector<uint8_t> part_vector;
part_vector.reserve(cbBytesRead);
std::copy(pchRequest, pchRequest + cbBytesRead, std::back_inserter(part_vector));
message_parts.push_back(part_vector);
} while (!fSuccess);
if (fSuccess)
{
// Reconstruct the total_message.
std::vector<uint8_t> reconstructed_message;
size_t total_size = 0;
for (auto& part_vector : message_parts)
{
total_size += part_vector.size();
}
reconstructed_message.reserve(total_size);
for (auto& part_vector : message_parts)
{
std::move(part_vector.begin(), part_vector.end(), std::back_inserter(reconstructed_message));
}
std::wstring unicode_msg;
unicode_msg.assign(reinterpret_cast<std::wstring::const_pointer>(reconstructed_message.data()), reconstructed_message.size() / sizeof(std::wstring::value_type));
input_queue.queue_message(unicode_msg);
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(input_pipe_handle);
DisconnectNamedPipe(input_pipe_handle);
CloseHandle(input_pipe_handle);
HeapFree(hHeap, 0, pchRequest);
printf("InstanceThread exitting.\n");
}
void start_named_pipe_server(HANDLE token)
{
// Adapted from https://docs.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server
const wchar_t* pipe_name = input_pipe_name.c_str();
BOOL connected = FALSE;
HANDLE connect_pipe_handle = INVALID_HANDLE_VALUE;
while (!closed)
{
{
std::unique_lock lock(pipe_connect_handle_mutex);
connect_pipe_handle = CreateNamedPipe(
pipe_name,
PIPE_ACCESS_DUPLEX |
WRITE_DAC,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
0,
NULL);
if (connect_pipe_handle == INVALID_HANDLE_VALUE)
{
return;
}
if (token != NULL)
{
int err = change_pipe_security_allow_restricted_token(connect_pipe_handle, token);
}
current_connect_pipe_handle = connect_pipe_handle;
}
connected = ConnectNamedPipe(connect_pipe_handle, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
{
std::unique_lock lock(pipe_connect_handle_mutex);
current_connect_pipe_handle = NULL;
}
if (connected)
{
std::thread(&TwoWayPipeMessageIPC::handle_pipe_connection, this, connect_pipe_handle).detach();
}
else
{
// Client could not connect.
CloseHandle(connect_pipe_handle);
}
}
}
void consume_input_queue_thread()
{
while (!closed)
{
std::wstring message = input_queue.pop_message();
if (message.length() == 0)
{
break;
}
dispatch_inc_message_function(message);
}
}
};

View file

@ -2,17 +2,18 @@
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 0
#define VERSION_MINOR 15
#define VERSION_REVISION 2
#define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, 0
#define FILE_VERSION_STRING STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_REVISION) ".0"
#define PRODUCT_VERSION FILE_VERSION
#define PRODUCT_VERSION_STRING FILE_VERSION_STRING
#define VERSION_MAJOR 0
#define VERSION_MINOR 15
#define VERSION_REVISION 2
#define COMPANY_NAME "Microsoft Corporation"
#define COPYRIGHT_NOTE "Copyright (C) 2019 Microsoft Corporation"
#define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, 0
#define FILE_VERSION_STRING \
STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_REVISION) ".0"
#define PRODUCT_VERSION FILE_VERSION
#define PRODUCT_VERSION_STRING FILE_VERSION_STRING
#define COMPANY_NAME "Microsoft Corporation"
#define COPYRIGHT_NOTE "Copyright (C) 2019 Microsoft Corporation"

View file

@ -4,7 +4,7 @@
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
{
WNDCLASS wc = { 0 };
PCWSTR wndClassName = L"MsgWindow";
wc.lpfnWndProc = DefWindowProc;

View file

@ -1,75 +1,89 @@
#include "pch.h"
#include "windows_colors.h"
DWORD WindowsColors::rgb_color(DWORD abgr_color) {
// registry keeps the colors in ABGR format, we want RGB
auto r = (abgr_color & 0xFF);
auto g = (abgr_color & 0xFF00) >> 8;
auto b = (abgr_color & 0xFF0000) >> 16;
return (r << 16) | (g << 8) | b;
DWORD WindowsColors::rgb_color(DWORD abgr_color)
{
// registry keeps the colors in ABGR format, we want RGB
auto r = (abgr_color & 0xFF);
auto g = (abgr_color & 0xFF00) >> 8;
auto b = (abgr_color & 0xFF0000) >> 16;
return (r << 16) | (g << 8) | b;
}
DWORD WindowsColors::rgb_color(winrt::Windows::UI::Color color) {
return ((DWORD)color.R << 16) | ((DWORD)color.G << 8) | ((DWORD)color.B);
DWORD WindowsColors::rgb_color(winrt::Windows::UI::Color color)
{
return ((DWORD)color.R << 16) | ((DWORD)color.G << 8) | ((DWORD)color.B);
}
WindowsColors::Color WindowsColors::get_button_face_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace);
WindowsColors::Color WindowsColors::get_button_face_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace);
}
WindowsColors::Color WindowsColors::get_button_text_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonText);
WindowsColors::Color WindowsColors::get_button_text_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::ButtonText);
}
WindowsColors::Color WindowsColors::get_highlight_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Highlight);
WindowsColors::Color WindowsColors::get_highlight_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Highlight);
}
WindowsColors::Color WindowsColors::get_hotlight_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Hotlight);
WindowsColors::Color WindowsColors::get_hotlight_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::Hotlight);
}
WindowsColors::Color WindowsColors::get_highlight_text_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::HighlightText);
WindowsColors::Color WindowsColors::get_highlight_text_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.UIElementColor(winrt::Windows::UI::ViewManagement::UIElementType::HighlightText);
}
WindowsColors::Color WindowsColors::get_accent_light_1_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight1);
WindowsColors::Color WindowsColors::get_accent_light_1_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight1);
}
WindowsColors::Color WindowsColors::get_accent_light_2_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight2);
WindowsColors::Color WindowsColors::get_accent_light_2_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentLight2);
}
WindowsColors::Color WindowsColors::get_accent_dark_1_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentDark1);
WindowsColors::Color WindowsColors::get_accent_dark_1_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::AccentDark1);
}
WindowsColors::Color WindowsColors::get_accent_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent);
WindowsColors::Color WindowsColors::get_accent_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent);
}
WindowsColors::Color WindowsColors::get_background_color() {
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Background);
}
bool WindowsColors::is_dark_mode() {
return rgb_color(get_background_color()) == 0;
WindowsColors::Color WindowsColors::get_background_color()
{
winrt::Windows::UI::ViewManagement::UISettings uiSettings;
return uiSettings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Background);
}
bool WindowsColors::update() {
auto new_accent_color_menu = rgb_color(get_accent_color());
auto new_start_color_menu = new_accent_color_menu;
auto new_desktop_fill_color = rgb_color(GetSysColor(COLOR_DESKTOP));
auto new_light_mode = rgb_color(get_background_color()) != 0; //Dark mode will have black as the background color.
bool changed = new_accent_color_menu != accent_color_menu ||
new_start_color_menu != start_color_menu ||
new_light_mode != light_mode ||
new_desktop_fill_color != desktop_fill_color;
accent_color_menu = new_accent_color_menu;
start_color_menu = new_start_color_menu;
light_mode = new_light_mode;
desktop_fill_color = new_desktop_fill_color;
return changed;
bool WindowsColors::is_dark_mode()
{
return rgb_color(get_background_color()) == 0;
}
bool WindowsColors::update()
{
auto new_accent_color_menu = rgb_color(get_accent_color());
auto new_start_color_menu = new_accent_color_menu;
auto new_desktop_fill_color = rgb_color(GetSysColor(COLOR_DESKTOP));
auto new_light_mode = rgb_color(get_background_color()) != 0; //Dark mode will have black as the background color.
bool changed = new_accent_color_menu != accent_color_menu ||
new_start_color_menu != start_color_menu ||
new_light_mode != light_mode ||
new_desktop_fill_color != desktop_fill_color;
accent_color_menu = new_accent_color_menu;
start_color_menu = new_start_color_menu;
light_mode = new_light_mode;
desktop_fill_color = new_desktop_fill_color;
return changed;
}

View file

@ -1,27 +1,28 @@
#pragma once
#include <winrt/Windows.UI.ViewManagement.h>
struct WindowsColors {
using Color = winrt::Windows::UI::Color;
static DWORD rgb_color(DWORD abgr_color);
static DWORD rgb_color(Color color);
static Color get_button_face_color();
static Color get_button_text_color();
static Color get_highlight_color();
static Color get_hotlight_color();
static Color get_highlight_text_color();
static Color get_accent_light_1_color();
static Color get_accent_light_2_color();
static Color get_accent_dark_1_color();
static Color get_accent_color();
static Color get_background_color();
static bool is_dark_mode();
// Update colors - returns true if the values where changed
bool update();
struct WindowsColors
{
using Color = winrt::Windows::UI::Color;
DWORD accent_color_menu = 0,
start_color_menu = 0,
desktop_fill_color = 0;
bool light_mode = true;
static DWORD rgb_color(DWORD abgr_color);
static DWORD rgb_color(Color color);
static Color get_button_face_color();
static Color get_button_text_color();
static Color get_highlight_color();
static Color get_hotlight_color();
static Color get_highlight_text_color();
static Color get_accent_light_1_color();
static Color get_accent_light_2_color();
static Color get_accent_dark_1_color();
static Color get_accent_color();
static Color get_background_color();
static bool is_dark_mode();
// Update colors - returns true if the values where changed
bool update();
DWORD accent_color_menu = 0,
start_color_menu = 0,
desktop_fill_color = 0;
bool light_mode = true;
};

View file

@ -4,7 +4,6 @@
#include <winrt/Windows.ApplicationModel.h>
namespace winstore
{
using winrt::Windows::ApplicationModel::StartupTaskState;

View file

@ -317,7 +317,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
int result = 0;
try
{
std::thread{ [] {
github_update_checking_worker();
} }.detach();

View file

@ -99,7 +99,8 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
// Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it.
// We'll also never receive wm_taskbar_restart message if the first call to Shell_NotifyIcon failed, so we use
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
case WM_WINDOWPOSCHANGING: {
case WM_WINDOWPOSCHANGING:
{
if (!tray_icon_created)
{
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
@ -111,12 +112,14 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
{
switch (lparam)
{
case WM_LBUTTONUP: {
case WM_LBUTTONUP:
{
open_settings_window();
break;
}
case WM_RBUTTONUP:
case WM_CONTEXTMENU: {
case WM_CONTEXTMENU:
{
if (!h_menu)
{
h_menu = LoadMenu(reinterpret_cast<HINSTANCE>(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU));

View file

@ -248,7 +248,7 @@ void initialize_webview(int nShowCmd)
// WebView doesn't let us to open ms-settings:protocol links directly, so we translate it
// from a https placeholder
if (uri.AbsoluteUri() == L"https://ms_settings_startupapps/")
uri = Uri{L"ms-settings:startupapps"};
uri = Uri{ L"ms-settings:startupapps" };
winrt::Windows::System::Launcher::LaunchUriAsync(uri);
});
@ -339,7 +339,8 @@ LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM
wm_data_for_webview = RegisterWindowMessageW(L"PTSettingsCopyDataWebView");
wm_destroy_window = RegisterWindowMessageW(L"PTSettingsParentTerminated");
break;
case WM_DPICHANGED: {
case WM_DPICHANGED:
{
// Resize the window using the suggested rect
RECT* const prcNewWindow = (RECT*)lParam;
SetWindowPos(hWnd,
@ -351,7 +352,8 @@ LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM
SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
case WM_NCCREATE: {
case WM_NCCREATE:
{
// Enable auto-resizing the title bar
EnableNonClientDpiScaling(hWnd);
}