[Keyboard Manager] Confirmation Dialog for orphaned keys and partial remappings. (#2811)

* WIP Confirmation dialog for orphaned keys

* Confirmation Dialog for orphaned keys

* White OK button, Anyways capitalizef

* Change Apply to Ok for shortcuts

* Validate that mappings can be made before changing keyboardManagerState

* Set fixed MinWidth for OK button

* Fix typo

* Partial remappings confirmation dialog

Both for Shortcuts and SingleKey

* Remove warning icon callback in OnClickAccept

* Add text wrapping for OrphanKeys dialog
This commit is contained in:
Tomas Agustin Raies 2020-05-11 12:45:55 -07:00 committed by GitHub
parent c39be3dbc9
commit 8c04421387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 239 additions and 26 deletions

View File

@ -73,4 +73,7 @@ namespace KeyboardManagerConstants
inline const long TableArrowColWidth = 20;
inline const long TableRemoveColWidth = 20;
inline const long TableWarningColWidth = 20;
// Shared style constants for both Remap Table and Shortcut Table
inline const double HeaderButtonWidth = 100;
}

View File

@ -0,0 +1,17 @@
#include "pch.h"
#include "Dialog.h"
IAsyncOperation<bool> Dialog::PartialRemappingConfirmationDialog(XamlRoot root)
{
ContentDialog confirmationDialog;
confirmationDialog.XamlRoot(root);
confirmationDialog.Title(box_value(L"Some of the keys could not be remapped. Do you want to continue anyway?"));
confirmationDialog.IsPrimaryButtonEnabled(true);
confirmationDialog.DefaultButton(ContentDialogButton::Primary);
confirmationDialog.PrimaryButtonText(winrt::hstring(L"Continue Anyway"));
confirmationDialog.IsSecondaryButtonEnabled(true);
confirmationDialog.SecondaryButtonText(winrt::hstring(L"Cancel"));
ContentDialogResult res = co_await confirmationDialog.ShowAsync();
co_return res == ContentDialogResult::Primary;
}

View File

@ -0,0 +1,41 @@
#pragma once
#include <vector>
#include <functional>
#include <keyboardmanager/common/Helpers.h>
#include <set>
#include <winrt/Windows.UI.Xaml.h>
using namespace winrt::Windows::Foundation;
namespace Dialog
{
template<typename T>
KeyboardManagerHelper::ErrorType CheckIfRemappingsAreValid(
const std::vector<std::vector<T>>& remappings,
std::function<bool(T)> isValid)
{
KeyboardManagerHelper::ErrorType isSuccess = KeyboardManagerHelper::ErrorType::NoError;
std::set<T> ogKeys;
for (int i = 0; i < remappings.size(); i++)
{
T ogKey = remappings[i][0];
T newKey = remappings[i][1];
if (isValid(ogKey) && isValid(newKey) && ogKeys.find(ogKey) == ogKeys.end())
{
ogKeys.insert(ogKey);
}
else if (isValid(ogKey) && isValid(newKey) && ogKeys.find(ogKey) != ogKeys.end())
{
isSuccess = KeyboardManagerHelper::ErrorType::RemapUnsuccessful;
}
else
{
isSuccess = KeyboardManagerHelper::ErrorType::RemapUnsuccessful;
}
}
return isSuccess;
}
IAsyncOperation<bool> PartialRemappingConfirmationDialog(winrt::Windows::UI::Xaml::XamlRoot root);
};

View File

@ -4,6 +4,13 @@
#include "KeyDropDownControl.h"
#include "XamlBridge.h"
#include <keyboardmanager/common/trace.h>
#include <keyboardmanager/common/KeyboardManagerConstants.h>
#include <set>
#include <common/windows_colors.h>
#include "Styles.h"
#include "Dialog.h"
using namespace winrt::Windows::Foundation;
LRESULT CALLBACK EditKeyboardWindowProc(HWND, UINT, WPARAM, LPARAM);
@ -17,6 +24,88 @@ std::mutex editKeyboardWindowMutex;
// Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure
static XamlBridge* xamlBridgePtr = nullptr;
static std::vector<DWORD> GetOrphanedKeys()
{
std::set<DWORD> ogKeys;
std::set<DWORD> newKeys;
for (int i = 0; i < SingleKeyRemapControl::singleKeyRemapBuffer.size(); i++)
{
DWORD ogKey = SingleKeyRemapControl::singleKeyRemapBuffer[i][0];
DWORD newKey = SingleKeyRemapControl::singleKeyRemapBuffer[i][1];
if (ogKey != 0 && newKey != 0)
{
ogKeys.insert(ogKey);
newKeys.insert(newKey);
}
}
for (auto& k : newKeys)
{
ogKeys.erase(k);
}
return std::vector(ogKeys.begin(), ogKeys.end());
}
static IAsyncOperation<bool> OrphanKeysConfirmationDialog(
KeyboardManagerState& state,
const std::vector<DWORD>& keys,
XamlRoot root)
{
ContentDialog confirmationDialog;
confirmationDialog.XamlRoot(root);
confirmationDialog.Title(box_value(L"The following keys are unassigned and you won't be able to use them:"));
confirmationDialog.Content(nullptr);
confirmationDialog.IsPrimaryButtonEnabled(true);
confirmationDialog.DefaultButton(ContentDialogButton::Primary);
confirmationDialog.PrimaryButtonText(winrt::hstring(L"Continue Anyway"));
confirmationDialog.IsSecondaryButtonEnabled(true);
confirmationDialog.SecondaryButtonText(winrt::hstring(L"Cancel"));
TextBlock orphanKeysBlock;
std::wstring orphanKeyString;
for (auto k : keys)
{
orphanKeyString.append(state.keyboardMap.GetKeyName(k));
orphanKeyString.append(L", ");
}
orphanKeyString = orphanKeyString.substr(0, max(0, orphanKeyString.length() - 2));
orphanKeysBlock.Text(winrt::hstring(orphanKeyString));
orphanKeysBlock.TextWrapping(TextWrapping::Wrap);
confirmationDialog.Content(orphanKeysBlock);
ContentDialogResult res = co_await confirmationDialog.ShowAsync();
co_return res == ContentDialogResult::Primary;
}
static IAsyncAction OnClickAccept(KeyboardManagerState& keyboardManagerState, XamlRoot root, std::function<void()> ApplyRemappings)
{
KeyboardManagerHelper::ErrorType isSuccess = Dialog::CheckIfRemappingsAreValid<DWORD>(
SingleKeyRemapControl::singleKeyRemapBuffer,
[](DWORD key) {
return key != 0;
});
if (isSuccess != KeyboardManagerHelper::ErrorType::NoError)
{
if (!co_await Dialog::PartialRemappingConfirmationDialog(root))
{
co_return;
}
}
// Check for orphaned keys
// Draw content Dialog
std::vector<DWORD> orphanedKeys = GetOrphanedKeys();
if (orphanedKeys.size() > 0)
{
if (!co_await OrphanKeysConfirmationDialog(keyboardManagerState, orphanedKeys, root))
{
co_return;
}
}
ApplyRemappings();
}
// Function to create the Edit Keyboard Window
void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
{
@ -100,7 +189,7 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
// Header Cancel button
Button cancelButton;
cancelButton.Content(winrt::box_value(L"Cancel"));
cancelButton.Margin({ 0, 0, 10, 0 });
cancelButton.Margin({ 10, 0, 0, 0 });
cancelButton.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
// Close the window since settings do not need to be saved
PostMessage(_hWndEditKeyboardWindow, WM_CLOSE, 0, 0);
@ -159,11 +248,6 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
keyRemapTable.Children().Append(originalKeyRemapHeader);
keyRemapTable.Children().Append(newKeyRemapHeader);
// Message to display success/failure of saving settings.
Flyout applyFlyout;
TextBlock settingsMessage;
applyFlyout.Content(settingsMessage);
// Store handle of edit keyboard window
SingleKeyRemapControl::EditKeyboardWindowHandle = _hWndEditKeyboardWindow;
// Store keyboard manager state
@ -231,11 +315,14 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
// Main Header Apply button
Button applyButton;
applyButton.Content(winrt::box_value(L"Apply"));
header.SetAlignRightWithPanel(applyButton, true);
header.SetLeftOf(cancelButton, applyButton);
applyButton.Flyout(applyFlyout);
applyButton.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
applyButton.Content(winrt::box_value(L"OK"));
applyButton.Style(AccentButtonStyle());
applyButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
cancelButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
header.SetAlignRightWithPanel(cancelButton, true);
header.SetLeftOf(applyButton, cancelButton);
auto ApplyRemappings = [&keyboardManagerState, _hWndEditKeyboardWindow]() {
KeyboardManagerHelper::ErrorType isSuccess = KeyboardManagerHelper::ErrorType::NoError;
// Clear existing Key Remaps
keyboardManagerState.ClearSingleKeyRemaps();
@ -292,14 +379,19 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
}
}
Trace::KeyRemapCount(successfulRemapCount);
// Save the updated shortcuts remaps to file.
bool saveResult = keyboardManagerState.SaveConfigToFile();
if (!saveResult)
{
isSuccess = KeyboardManagerHelper::ErrorType::SaveFailed;
}
Trace::KeyRemapCount(successfulRemapCount);
settingsMessage.Text(KeyboardManagerHelper::GetErrorMessage(isSuccess));
PostMessage(_hWndEditKeyboardWindow, WM_CLOSE, 0, 0);
};
applyButton.Click([&keyboardManagerState, ApplyRemappings, applyButton](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
OnClickAccept(keyboardManagerState, applyButton.XamlRoot(), ApplyRemappings);
});
header.Children().Append(headerText);

View File

@ -4,6 +4,12 @@
#include "KeyDropDownControl.h"
#include "XamlBridge.h"
#include <keyboardmanager/common/trace.h>
#include <keyboardmanager/common/KeyboardManagerConstants.h>
#include <common/windows_colors.h>
#include "Styles.h"
#include "Dialog.h"
using namespace winrt::Windows::Foundation;
LRESULT CALLBACK EditShortcutsWindowProc(HWND, UINT, WPARAM, LPARAM);
@ -17,6 +23,26 @@ std::mutex editShortcutsWindowMutex;
// Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure
static XamlBridge* xamlBridgePtr = nullptr;
static IAsyncAction OnClickAccept(
KeyboardManagerState& keyboardManagerState,
XamlRoot root,
std::function<void()> ApplyRemappings)
{
KeyboardManagerHelper::ErrorType isSuccess = Dialog::CheckIfRemappingsAreValid<Shortcut>(
ShortcutControl::shortcutRemapBuffer,
[](Shortcut shortcut) {
return shortcut.IsValidShortcut();
});
if (isSuccess != KeyboardManagerHelper::ErrorType::NoError)
{
if (!co_await Dialog::PartialRemappingConfirmationDialog(root))
{
co_return;
}
}
ApplyRemappings();
}
// Function to create the Edit Shortcuts Window
void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
{
@ -101,7 +127,7 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
// Cancel button
Button cancelButton;
cancelButton.Content(winrt::box_value(L"Cancel"));
cancelButton.Margin({ 0, 0, 10, 0 });
cancelButton.Margin({ 10, 0, 0, 0 });
cancelButton.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
// Close the window since settings do not need to be saved
PostMessage(_hWndEditShortcutsWindow, WM_CLOSE, 0, 0);
@ -161,11 +187,6 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
shortcutTable.Children().Append(originalShortcutHeader);
shortcutTable.Children().Append(newShortcutHeader);
// Message to display success/failure of saving settings.
Flyout applyFlyout;
TextBlock settingsMessage;
applyFlyout.Content(settingsMessage);
// Store handle of edit shortcuts window
ShortcutControl::EditShortcutsWindowHandle = _hWndEditShortcutsWindow;
// Store keyboard manager state
@ -189,11 +210,14 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
// Apply button
Button applyButton;
applyButton.Content(winrt::box_value(L"Apply"));
header.SetAlignRightWithPanel(applyButton, true);
header.SetLeftOf(cancelButton, applyButton);
applyButton.Flyout(applyFlyout);
applyButton.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
applyButton.Content(winrt::box_value(L"OK"));
applyButton.Style(AccentButtonStyle());
applyButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
cancelButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
header.SetAlignRightWithPanel(cancelButton, true);
header.SetLeftOf(applyButton, cancelButton);
auto ApplyRemappings = [&keyboardManagerState, _hWndEditShortcutsWindow]() {
KeyboardManagerHelper::ErrorType isSuccess = KeyboardManagerHelper::ErrorType::NoError;
// Clear existing shortcuts
keyboardManagerState.ClearOSLevelShortcuts();
@ -223,14 +247,19 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
}
}
Trace::OSLevelShortcutRemapCount(successfulRemapCount);
// Save the updated key remaps to file.
bool saveResult = keyboardManagerState.SaveConfigToFile();
if (!saveResult)
{
isSuccess = KeyboardManagerHelper::ErrorType::SaveFailed;
}
Trace::OSLevelShortcutRemapCount(successfulRemapCount);
settingsMessage.Text(KeyboardManagerHelper::GetErrorMessage(isSuccess));
PostMessage(_hWndEditShortcutsWindow, WM_CLOSE, 0, 0);
};
applyButton.Click([&keyboardManagerState, applyButton, ApplyRemappings](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
OnClickAccept(keyboardManagerState, applyButton.XamlRoot(), ApplyRemappings);
});
header.Children().Append(headerText);

View File

@ -98,6 +98,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Dialog.cpp" />
<ClCompile Include="EditKeyboardWindow.cpp" />
<ClCompile Include="EditShortcutsWindow.cpp" />
<ClCompile Include="KeyDropDownControl.cpp" />
@ -107,11 +108,14 @@
</ClCompile>
<ClCompile Include="ShortcutControl.cpp" />
<ClCompile Include="SingleKeyRemapControl.cpp" />
<ClCompile Include="Styles.cpp" />
<ClCompile Include="XamlBridge.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Dialog.h" />
<ClInclude Include="EditKeyboardWindow.h" />
<ClInclude Include="EditShortcutsWindow.h" />
<ClInclude Include="Styles.h" />
<ClInclude Include="KeyDropDownControl.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ShortcutControl.h" />

View File

@ -8,6 +8,8 @@
<ClCompile Include="SingleKeyRemapControl.cpp" />
<ClCompile Include="KeyDropDownControl.cpp" />
<ClCompile Include="XamlBridge.cpp" />
<ClCompile Include="Styles.cpp" />
<ClCompile Include="Dialog.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="EditKeyboardWindow.h" />
@ -17,6 +19,8 @@
<ClInclude Include="SingleKeyRemapControl.h" />
<ClInclude Include="KeyDropDownControl.h" />
<ClInclude Include="XamlBridge.h" />
<ClInclude Include="Styles.h" />
<ClInclude Include="Dialog.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -0,0 +1,17 @@
#include "pch.h"
#include "Styles.h"
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <common/windows_colors.h>
Style AccentButtonStyle()
{
Style style{ winrt::xaml_typename<Controls::Button>() };
style.Setters().Append(Setter{
Controls::Control::BackgroundProperty(),
winrt::Windows::UI::Xaml::Media::SolidColorBrush{ WindowsColors::get_accent_color() } });
style.Setters().Append(Setter{
Controls::Control::ForegroundProperty(),
winrt::Windows::UI::Xaml::Media::SolidColorBrush{ winrt::Windows::UI::Colors::White() } });
return style;
}

View File

@ -0,0 +1,6 @@
#pragma once
#include <winrt/Windows.UI.Xaml.h>
using namespace winrt::Windows::UI::Xaml;
Style AccentButtonStyle();