From c508cc29ed2e4c53c39deb167ea1b375702f95f1 Mon Sep 17 00:00:00 2001 From: Matt Cooley Date: Thu, 3 Sep 2020 12:27:27 -0700 Subject: [PATCH 1/5] Update internals package to 0.0.49 (#1364) --- build/pipelines/templates/build-app-internal.yaml | 2 +- build/pipelines/templates/prepare-release-internalonly.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pipelines/templates/build-app-internal.yaml b/build/pipelines/templates/build-app-internal.yaml index 41b0cc7a..4418395d 100644 --- a/build/pipelines/templates/build-app-internal.yaml +++ b/build/pipelines/templates/build-app-internal.yaml @@ -29,7 +29,7 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsInboxApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.45 + vstsPackageVersion: 0.0.49 - template: ./build-single-architecture.yaml parameters: diff --git a/build/pipelines/templates/prepare-release-internalonly.yaml b/build/pipelines/templates/prepare-release-internalonly.yaml index b13441f8..945de53a 100644 --- a/build/pipelines/templates/prepare-release-internalonly.yaml +++ b/build/pipelines/templates/prepare-release-internalonly.yaml @@ -80,7 +80,7 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsInboxApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.45 + vstsPackageVersion: 0.0.49 - powershell: | # Just modify this line to indicate where your en-us PDP file is. Leave the other lines alone. From d256fb6c1944df3d954aac1226b6203e5af76bbd Mon Sep 17 00:00:00 2001 From: Jack Rainy Date: Tue, 15 Sep 2020 01:11:17 +0300 Subject: [PATCH 2/5] Take the boundary of signed negative values into account( Fix issue 1301) (#1336) * Take the high boundary of signed negative values into account * UI unit tests for the Copy/Paste menu are added * Additional corner case for the number notations without negative values --- src/CalcViewModel/Common/CopyPasteManager.cpp | 9 +- .../CalculatorResults.cs | 31 +++++++ .../ProgrammerModeFunctionalTests.cs | 92 ++++++++++++++++++- .../CopyPasteManagerTest.cpp | 26 +++++- 4 files changed, 151 insertions(+), 7 deletions(-) diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp index dbcded54..ae24aad1 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.cpp +++ b/src/CalcViewModel/Common/CopyPasteManager.cpp @@ -310,6 +310,9 @@ bool CopyPasteManager::ExpressionRegExMatch( if (operandMatched) { + // Remember the sign of the operand + bool isNegativeValue = operand->Data()[0] == L'-'; + // Remove characters that are valid in the expression but we do not want to include in length calculations // or which will break conversion from string-to-ULL. auto operandValue = SanitizeOperand(operand); @@ -332,7 +335,11 @@ bool CopyPasteManager::ExpressionRegExMatch( break; } - if (operandAsULL->Value > maxOperandLengthAndValue.maxValue) + // Calculate how much we exceed the maxValue. + // In case we exceed it for 1 only, and working with negative number - that's a corner case for max signed values (e.g. -32768) + bool isOverflow = operandAsULL->Value > maxOperandLengthAndValue.maxValue; + bool isMaxNegativeValue = operandAsULL->Value - 1 == maxOperandLengthAndValue.maxValue; + if (isOverflow && !(isNegativeValue && isMaxNegativeValue)) { expMatched = false; break; diff --git a/src/CalculatorUITestFramework/CalculatorResults.cs b/src/CalculatorUITestFramework/CalculatorResults.cs index a2c23ada..9371fa11 100644 --- a/src/CalculatorUITestFramework/CalculatorResults.cs +++ b/src/CalculatorUITestFramework/CalculatorResults.cs @@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using OpenQA.Selenium.Appium.Windows; using System; +using OpenQA.Selenium.Interactions; namespace CalculatorUITestFramework { @@ -12,6 +13,8 @@ namespace CalculatorUITestFramework private WindowsElement CalculatorAlwaysOnTopResults => this.session.TryFindElementByAccessibilityId("CalculatorAlwaysOnTopResults"); private WindowsElement CalculatorResult => this.session.TryFindElementByAccessibilityId("CalculatorResults"); private WindowsElement CalculatorExpression => this.session.TryFindElementByAccessibilityId("CalculatorExpression"); + private WindowsElement MenuItemCopy => this.session.TryFindElementByAccessibilityId("CopyMenuItem"); + private WindowsElement MenuItemPaste => this.session.TryFindElementByAccessibilityId("PasteMenuItem"); /// /// Gets the text from the display control in AoT mode and removes the narrator text that is not displayed in the UI. @@ -61,5 +64,33 @@ namespace CalculatorUITestFramework throw new Exception("The Calculator Expression is not clear"); } } + + /// + /// Opens the context menu in order to be able to click its items + /// + private void OpenContextMenu() + { + Actions actions = new Actions(CalculatorResult.WrappedDriver); + // It is important to move not to the centre in order to avoid click on the text + actions.MoveToElement(CalculatorResult, 1,1).ContextClick().Perform(); + } + + /// + /// Opens the context menu and clicks the "Copy" item there + /// + public void ContextMenuItemCopyClick() + { + OpenContextMenu(); + MenuItemCopy.Click(); + } + + /// + /// Opens the context menu and clicks the "Paste" item there + /// + public void ContextMenuItemPasteClick() + { + OpenContextMenu(); + MenuItemPaste.Click(); + } } } diff --git a/src/CalculatorUITests/ProgrammerModeFunctionalTests.cs b/src/CalculatorUITests/ProgrammerModeFunctionalTests.cs index 004292a3..e5ca991d 100644 --- a/src/CalculatorUITests/ProgrammerModeFunctionalTests.cs +++ b/src/CalculatorUITests/ProgrammerModeFunctionalTests.cs @@ -4,9 +4,7 @@ using CalculatorUITestFramework; using Microsoft.VisualStudio.TestTools.UnitTesting; using OpenQA.Selenium; -using OpenQA.Selenium.Appium.Windows; using System; -using System.Collections.Generic; namespace CalculatorUITests { @@ -890,5 +888,95 @@ namespace CalculatorUITests Assert.AreEqual("8 0 8", page.CalculatorResults.GetCalculatorResultText()); } #endregion + + /// + /// Copy and Paste the numbers into/from the calculator + /// + #region Copy-Paste operations + [TestMethod] + [Priority(1)] + public void Copy_And_Paste_Simple_Number() + { + page.ProgrammerOperators.BitFlip.Click(); + page.ProgrammerOperators.Bit1.Click(); + page.CalculatorResults.ContextMenuItemCopyClick(); + page.ProgrammerOperators.FullKeypad.Click(); + page.StandardOperators.ClearEntryButton.Click(); + page.CalculatorResults.ContextMenuItemPasteClick(); + Assert.AreEqual("2", page.CalculatorResults.GetCalculatorResultText()); + } + + [TestMethod] + [Priority(1)] + public void Copy_And_Paste_Invalid_Number() + { + page.ProgrammerOperators.BitFlip.Click(); + page.ProgrammerOperators.Bit63.Click(); + page.CalculatorResults.ContextMenuItemCopyClick(); + page.ProgrammerOperators.FullKeypad.Click(); + page.StandardOperators.ClearEntryButton.Click(); + page.ProgrammerOperators.QWordButton.Click(); + page.CalculatorResults.ContextMenuItemPasteClick(); + Assert.AreEqual("Invalid input", page.CalculatorResults.GetCalculatorResultText()); + } + + [TestMethod] + [Priority(1)] + public void Copy_And_Paste_Big_QWord_Number() + { + page.ProgrammerOperators.BitFlip.Click(); + page.ProgrammerOperators.Bit63.Click(); + page.CalculatorResults.ContextMenuItemCopyClick(); + page.ProgrammerOperators.FullKeypad.Click(); + page.StandardOperators.ClearEntryButton.Click(); + page.CalculatorResults.ContextMenuItemPasteClick(); + Assert.AreEqual("-9,223,372,036,854,775,808", page.CalculatorResults.GetCalculatorResultText()); + } + + [TestMethod] + [Priority(1)] + public void Copy_And_Paste_Big_DWord_Number() + { + page.ProgrammerOperators.QWordButton.Click(); + page.ProgrammerOperators.BitFlip.Click(); + page.ProgrammerOperators.Bit31.Click(); + page.CalculatorResults.ContextMenuItemCopyClick(); + page.ProgrammerOperators.FullKeypad.Click(); + page.StandardOperators.ClearEntryButton.Click(); + page.CalculatorResults.ContextMenuItemPasteClick(); + Assert.AreEqual("-2,147,483,648", page.CalculatorResults.GetCalculatorResultText()); + } + + [TestMethod] + [Priority(1)] + public void Copy_And_Paste_Big_Word_Number() + { + page.ProgrammerOperators.QWordButton.Click(); + page.ProgrammerOperators.DWordButton.Click(); + page.ProgrammerOperators.BitFlip.Click(); + page.ProgrammerOperators.Bit15.Click(); + page.CalculatorResults.ContextMenuItemCopyClick(); + page.ProgrammerOperators.FullKeypad.Click(); + page.StandardOperators.ClearEntryButton.Click(); + page.CalculatorResults.ContextMenuItemPasteClick(); + Assert.AreEqual("-32,768", page.CalculatorResults.GetCalculatorResultText()); + } + + [TestMethod] + [Priority(1)] + public void Copy_And_Paste_Big_Byte_Number() + { + page.ProgrammerOperators.QWordButton.Click(); + page.ProgrammerOperators.DWordButton.Click(); + page.ProgrammerOperators.WordButton.Click(); + page.ProgrammerOperators.BitFlip.Click(); + page.ProgrammerOperators.Bit7.Click(); + page.CalculatorResults.ContextMenuItemCopyClick(); + page.ProgrammerOperators.FullKeypad.Click(); + page.StandardOperators.ClearEntryButton.Click(); + page.CalculatorResults.ContextMenuItemPasteClick(); + Assert.AreEqual("-128", page.CalculatorResults.GetCalculatorResultText()); + } + #endregion } } diff --git a/src/CalculatorUnitTests/CopyPasteManagerTest.cpp b/src/CalculatorUnitTests/CopyPasteManagerTest.cpp index ee9eb1d7..1b800f8e 100644 --- a/src/CalculatorUnitTests/CopyPasteManagerTest.cpp +++ b/src/CalculatorUnitTests/CopyPasteManagerTest.cpp @@ -261,6 +261,14 @@ namespace CalculatorUnitTests NumberBase::DecBase, BitLength::BitLengthQWord), L"Verify operand values == max return true."); + VERIFY_IS_TRUE( + m_CopyPasteManager->ExpressionRegExMatch( + ref new Vector({ L"-9223372036854775808" }), + ViewMode::Programmer, + CategoryGroupType::Calculator, + NumberBase::DecBase, + BitLength::BitLengthQWord), + L"Verify operand values == max negative return true."); Logger::WriteMessage(L"Verify all operands must match patterns."); VERIFY_IS_TRUE(m_CopyPasteManager->ExpressionRegExMatch( @@ -950,6 +958,7 @@ namespace CalculatorUnitTests L"aef", L"ABab", L"A1a3" /*within boundary*/, + L"FFFF" /*boundary condition: max allowed number*/, L"0x1234", L"0xab12", L"0X1234", @@ -1046,7 +1055,7 @@ namespace CalculatorUnitTests L"123*4*-3", L"123*+4*-3", L"9223372036854775807", - L"-9223372036854775807" /*boundary condition: max/min allowed number*/, + L"-9223372036854775808" /*boundary condition: max/min allowed number*/, L"0n1234", L"0N1234", L"1234u", @@ -1069,6 +1078,7 @@ namespace CalculatorUnitTests L"xyz", L"ABab", L"e+234", + L"9223372036854775808" /*boundary condition: greater than max allowed number 9223372036854775807*/, L"9223372036854775809" /*boundary condition: greater than max allowed number 9223372036854775807*/, L"SIN(2)", L"-0n123", @@ -1145,7 +1155,8 @@ namespace CalculatorUnitTests L"123*4*-3", L"123*+4*-3", L"32767", - L"-32767" /*boundary condition: max/min allowed number*/, + L"-32767", + L"-32768" /*boundary condition: max/min allowed number*/, L"0n1234", L"0N1234", L"1234u", @@ -1208,7 +1219,8 @@ namespace CalculatorUnitTests { String ^ qwordPositiveInput[] = { L"123", L"123+456", L"1,234", L"1 2 3", L"1'2'3'4", L"1_2_3_4", L"\n\r1,234\n", L"\f\n1+2\t\r\v\x85", L"\n 1+\n2 ", L"1\"2", L"(123)+(456)", L"0t1234", L"0T1234", L"0o1234", L"0O1234", L"1234u", - L"1234ul", L"1234ULL", L"2+2=", L"2+2= ", L"127%71" }; + L"1234ul", L"1234ULL", L"2+2=", L"2+2= ", + L"127%71", L"1777777777777777777777" /*boundary condition: the max allowed number*/ }; String ^ qwordNegativeInput[] = { L"+123", L"1.23", L"1''2", @@ -1226,6 +1238,7 @@ namespace CalculatorUnitTests L"ABab", L"e+234", L"12345678901234567890123" /*boundary condition: greater than max allowed digits 22*/, + L"2000000000000000000000" /*boundary condition: greater than max allowed number*/, L"SIN(2)", L"123+-234", L"0ot1234", @@ -1260,6 +1273,7 @@ namespace CalculatorUnitTests L"ABab", L"e+234", L"377777777771" /*boundary condition: greater than max allowed number 37777777777*/, + L"40000000000" /*boundary condition: greater than max allowed number 37777777777*/, L"SIN(2)", L"123+-234", L"0ot1234", @@ -1303,6 +1317,7 @@ namespace CalculatorUnitTests L"ABab", L"e+234", L"1777771" /*boundary condition: greater than max allowed number 177777*/, + L"200000" /*boundary condition: greater than max allowed number 177777*/, L"SIN(2)", L"123+-234", L"0ot1234", @@ -1332,6 +1347,7 @@ namespace CalculatorUnitTests L"ABab", L"e+24", L"477" /*boundary condition: greater than max allowed number 377*/, + L"400" /*boundary condition: greater than max allowed number 377*/, L"SIN(2)", L"123+-34", L"0ot123", @@ -1497,7 +1513,8 @@ namespace CalculatorUnitTests String ^ bytePositiveInput[] = { L"100", L"100+101", L"1,001", L"1 0 1", L"1'0'0'1", L"1_0_0_1", L"\n\r1,010\n", L"\n 1+\n1 ", L"1\"1", L"(101)+(10)", L"0b1001", L"0B1111", L"0y1001", L"0Y1001", - L"1100b", L"1101B", L"1111u", L"1111ul", L"1111ULL", L"10100010" /*boundary condition: max allowed number*/ }; + L"1100b", L"1101B", L"1111u", L"1111ul", L"1111ULL", L"10100010", + L"11111111" /*boundary condition: max allowed number*/ }; String ^ byteNegativeInput[] = { L"+10101", L"1.01", L"1''0", @@ -1524,6 +1541,7 @@ namespace CalculatorUnitTests L"1111uu", L"1111ulll", L"101000101" /*boundary condition: greater than max allowed digits 8*/, + L"100000000" /*boundary condition: greater than max allowed value*/, L"SIN(01010)", L"10+-1010101" }; From 6d059aa12604bfa00070e2c2be96e675ade2f9bf Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 15 Sep 2020 11:08:22 -0700 Subject: [PATCH 3/5] Fix Race condition in tests involving context menu (#1373) * Fix Race condition in tests involving context menu * remove extraneous logging --- .../CalculatorResults.cs | 4 +- .../WindowsDriverExtensions.cs | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/CalculatorUITestFramework/CalculatorResults.cs b/src/CalculatorUITestFramework/CalculatorResults.cs index 9371fa11..6e6815d9 100644 --- a/src/CalculatorUITestFramework/CalculatorResults.cs +++ b/src/CalculatorUITestFramework/CalculatorResults.cs @@ -13,8 +13,8 @@ namespace CalculatorUITestFramework private WindowsElement CalculatorAlwaysOnTopResults => this.session.TryFindElementByAccessibilityId("CalculatorAlwaysOnTopResults"); private WindowsElement CalculatorResult => this.session.TryFindElementByAccessibilityId("CalculatorResults"); private WindowsElement CalculatorExpression => this.session.TryFindElementByAccessibilityId("CalculatorExpression"); - private WindowsElement MenuItemCopy => this.session.TryFindElementByAccessibilityId("CopyMenuItem"); - private WindowsElement MenuItemPaste => this.session.TryFindElementByAccessibilityId("PasteMenuItem"); + private WindowsElement MenuItemCopy => this.session.WaitForElementByAccessibilityId("CopyMenuItem"); + private WindowsElement MenuItemPaste => this.session.WaitForElementByAccessibilityId("PasteMenuItem"); /// /// Gets the text from the display control in AoT mode and removes the narrator text that is not displayed in the UI. diff --git a/src/CalculatorUITestFramework/WindowsDriverExtensions.cs b/src/CalculatorUITestFramework/WindowsDriverExtensions.cs index 399584a5..af36507b 100644 --- a/src/CalculatorUITestFramework/WindowsDriverExtensions.cs +++ b/src/CalculatorUITestFramework/WindowsDriverExtensions.cs @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.VisualStudio.TestTools.UnitTesting.Logging; using OpenQA.Selenium; using OpenQA.Selenium.Appium.Windows; +using System.Diagnostics; +using System.Threading; namespace CalculatorUITestFramework { @@ -68,5 +71,43 @@ namespace CalculatorUITestFramework // process id (any entry of allWindowHandles) driver.SwitchTo().Window(allWindowHandles[0]); } + + /// + /// Waits for an element to be created. + /// + /// this + /// the automation id + /// optional timeout in ms + /// the element with the matching automation id + public static WindowsElement WaitForElementByAccessibilityId(this WindowsDriver driver, string id, int timeout = 1000) + { + Stopwatch timer = new Stopwatch(); + timer.Reset(); + timer.Start(); + while (timer.ElapsedMilliseconds < timeout) + { + try + { + var element = driver.TryFindElementByAccessibilityId(id); + return element; + } + catch(WebDriverException ex) + { + if (ex.Message.Contains("An element could not be located on the page using the given search parameters")) + { + Logger.LogMessage("Element not found. Waiting for 10ms in WaitForElementByAccessibilityId"); + } + else + { + throw; + } + } + Thread.Sleep(10); + } + timer.Stop(); + + // one last attempt. Throws the not found exception if this fails + return driver.TryFindElementByAccessibilityId(id); + } } } From bc473617ae05ceba9a8a3b7ed04848aa213c7cff Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Tue, 15 Sep 2020 12:43:50 -0700 Subject: [PATCH 4/5] Simplify KeyboardShortcutManager and correctly support Alt-Gr key (#1223) * Simplify KeyboardShortcutManager and correctly support Alt-Gr key * replace multimap with map move all global fields-functions to the class * feedback Co-authored-by: Eric Wong --- .../Common/KeyboardShortcutManager.cpp | 529 ++++++------------ .../Common/KeyboardShortcutManager.h | 28 +- src/Calculator/Resources/en-US/Resources.resw | 52 -- src/Calculator/Views/MainPage.xaml.cpp | 6 +- 4 files changed, 200 insertions(+), 415 deletions(-) diff --git a/src/Calculator/Common/KeyboardShortcutManager.cpp b/src/Calculator/Common/KeyboardShortcutManager.cpp index 378db341..bed0c4b2 100644 --- a/src/Calculator/Common/KeyboardShortcutManager.cpp +++ b/src/Calculator/Common/KeyboardShortcutManager.cpp @@ -10,7 +10,7 @@ using namespace Concurrency; using namespace Platform; using namespace std; -using namespace std::chrono; +using namespace chrono; using namespace Windows::ApplicationModel::Resources; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; @@ -32,30 +32,20 @@ DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlCho DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyShiftChord); DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyAltChord); DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlShiftChord); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyInverseChord); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlInverseChord); -static multimap> s_CharacterForButtons; -static multimap> s_VirtualKeysForButtons; -static multimap> s_VirtualKeyControlChordsForButtons; -static multimap> s_VirtualKeyShiftChordsForButtons; -static multimap> s_VirtualKeyAltChordsForButtons; -static multimap> s_VirtualKeyControlShiftChordsForButtons; -static multimap> s_VirtualKeyInverseChordsForButtons; -static multimap> s_VirtualKeyControlInverseChordsForButtons; +map> KeyboardShortcutManager::s_characterForButtons; +map> KeyboardShortcutManager::s_virtualKey; +map> KeyboardShortcutManager::s_VirtualKeyControlChordsForButtons; +map> KeyboardShortcutManager::s_VirtualKeyShiftChordsForButtons; +map> KeyboardShortcutManager::s_VirtualKeyAltChordsForButtons; +map> KeyboardShortcutManager::s_VirtualKeyControlShiftChordsForButtons; -static map s_ShiftKeyPressed; -static map s_ControlKeyPressed; -static map s_ShiftButtonChecked; -static map s_IsDropDownOpen; - -static map s_ignoreNextEscape; -static map s_keepIgnoringEscape; -static map s_fHonorShortcuts; -static map s_fDisableShortcuts; -static map s_AboutFlyout; - -static reader_writer_lock s_keyboardShortcutMapLock; +map KeyboardShortcutManager::s_IsDropDownOpen; +map KeyboardShortcutManager::s_ignoreNextEscape; +map KeyboardShortcutManager::s_keepIgnoringEscape; +map KeyboardShortcutManager::s_fHonorShortcuts; +map KeyboardShortcutManager::s_fDisableShortcuts; +reader_writer_lock KeyboardShortcutManager::s_keyboardShortcutMapLock; namespace CalculatorApp { @@ -156,7 +146,7 @@ namespace CalculatorApp auto toggle = dynamic_cast(button); if (toggle) { - toggle->IsChecked = !toggle->IsChecked->Value; + toggle->IsChecked = !(toggle->IsChecked != nullptr && toggle->IsChecked->Value); return; } } @@ -208,9 +198,9 @@ void KeyboardShortcutManager::OnCharacterPropertyChanged(DependencyObject ^ targ auto button = safe_cast(target); int viewId = Utils::GetWindowId(); - auto iterViewMap = s_CharacterForButtons.find(viewId); + auto iterViewMap = s_characterForButtons.find(viewId); - if (iterViewMap != s_CharacterForButtons.end()) + if (iterViewMap != s_characterForButtons.end()) { if (oldValue) { @@ -222,26 +212,26 @@ void KeyboardShortcutManager::OnCharacterPropertyChanged(DependencyObject ^ targ if (newValue == L".") { wchar_t decSep = LocalizationSettings::GetInstance().GetDecimalSeparator(); - iterViewMap->second.insert(std::make_pair(decSep, WeakReference(button))); + iterViewMap->second.insert(make_pair(decSep, WeakReference(button))); } else { - iterViewMap->second.insert(std::make_pair(newValue->Data()[0], WeakReference(button))); + iterViewMap->second.insert(make_pair(newValue->Data()[0], WeakReference(button))); } } } else { - s_CharacterForButtons.insert(std::make_pair(viewId, std::multimap())); + s_characterForButtons.insert(make_pair(viewId, multimap())); if (newValue == L".") { wchar_t decSep = LocalizationSettings::GetInstance().GetDecimalSeparator(); - s_CharacterForButtons.find(viewId)->second.insert(std::make_pair(decSep, WeakReference(button))); + s_characterForButtons.find(viewId)->second.insert(make_pair(decSep, WeakReference(button))); } else { - s_CharacterForButtons.find(viewId)->second.insert(std::make_pair(newValue->Data()[0], WeakReference(button))); + s_characterForButtons.find(viewId)->second.insert(make_pair(newValue->Data()[0], WeakReference(button))); } } } @@ -254,18 +244,18 @@ void KeyboardShortcutManager::OnVirtualKeyPropertyChanged(DependencyObject ^ tar auto button = static_cast(target); int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeysForButtons.find(viewId); + auto iterViewMap = s_virtualKey.find(viewId); // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeysForButtons.end()) + if (iterViewMap != s_virtualKey.end()) { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); + iterViewMap->second.insert(make_pair(newValue, WeakReference(button))); } else { // If the View Id is not already registered, then register it and make the entry - s_VirtualKeysForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeysForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); + s_virtualKey.insert(make_pair(viewId, multimap())); + s_virtualKey.find(viewId)->second.insert(make_pair(newValue, WeakReference(button))); } } @@ -288,13 +278,13 @@ void KeyboardShortcutManager::OnVirtualKeyControlChordPropertyChanged(Dependency // Check if the View Id has already been registered if (iterViewMap != s_VirtualKeyControlChordsForButtons.end()) { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(control))); + iterViewMap->second.insert(make_pair(newValue, WeakReference(control))); } else { // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyControlChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyControlChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(control))); + s_VirtualKeyControlChordsForButtons.insert(make_pair(viewId, multimap())); + s_VirtualKeyControlChordsForButtons.find(viewId)->second.insert(make_pair(newValue, WeakReference(control))); } } @@ -311,13 +301,13 @@ void KeyboardShortcutManager::OnVirtualKeyShiftChordPropertyChanged(DependencyOb // Check if the View Id has already been registered if (iterViewMap != s_VirtualKeyShiftChordsForButtons.end()) { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); + iterViewMap->second.insert(make_pair(newValue, WeakReference(button))); } else { // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyShiftChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyShiftChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); + s_VirtualKeyShiftChordsForButtons.insert(make_pair(viewId, multimap())); + s_VirtualKeyShiftChordsForButtons.find(viewId)->second.insert(make_pair(newValue, WeakReference(button))); } } @@ -334,13 +324,13 @@ void KeyboardShortcutManager::OnVirtualKeyAltChordPropertyChanged(DependencyObje // Check if the View Id has already been registered if (iterViewMap != s_VirtualKeyAltChordsForButtons.end()) { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(navView))); + iterViewMap->second.insert(make_pair(newValue, WeakReference(navView))); } else { // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyAltChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyAltChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(navView))); + s_VirtualKeyAltChordsForButtons.insert(make_pair(viewId, multimap())); + s_VirtualKeyAltChordsForButtons.find(viewId)->second.insert(make_pair(newValue, WeakReference(navView))); } } @@ -357,59 +347,13 @@ void KeyboardShortcutManager::OnVirtualKeyControlShiftChordPropertyChanged(Depen // Check if the View Id has already been registered if (iterViewMap != s_VirtualKeyControlShiftChordsForButtons.end()) { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); + iterViewMap->second.insert(make_pair(newValue, WeakReference(button))); } else { // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyInverseChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyInverseChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyInverseChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyInverseChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyControlInverseChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyControlInverseChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); + s_VirtualKeyControlShiftChordsForButtons.insert(make_pair(viewId, multimap())); + s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second.insert(make_pair(newValue, WeakReference(button))); } } @@ -421,218 +365,153 @@ void KeyboardShortcutManager::OnCharacterReceivedHandler(CoreWindow ^ sender, Ch int viewId = Utils::GetWindowId(); auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId); - if (currentHonorShortcuts != s_fHonorShortcuts.end()) + if (currentHonorShortcuts == s_fHonorShortcuts.end() || currentHonorShortcuts->second) { - if (currentHonorShortcuts->second) - { - wchar_t character = static_cast(args->KeyCode); - auto buttons = s_CharacterForButtons.find(viewId)->second.equal_range(character); - RunFirstEnabledButtonCommand(buttons); + wchar_t character = static_cast(args->KeyCode); + auto buttons = s_characterForButtons.find(viewId)->second.equal_range(character); + RunFirstEnabledButtonCommand(buttons); - LightUpButtons(buttons); - } + LightUpButtons(buttons); } } -const std::multimap& GetCurrentKeyDictionary(MyVirtualKey key, bool altPressed = false) +const multimap* KeyboardShortcutManager::GetCurrentKeyDictionary(bool controlKeyPressed, bool shiftKeyPressed, bool altPressed) { int viewId = Utils::GetWindowId(); - if (altPressed) + if (controlKeyPressed) { - return s_VirtualKeyAltChordsForButtons.find(viewId)->second; - } - else if ( - (s_ShiftKeyPressed.find(viewId)->second) - && ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down)) - { - return s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second; - } - else if (s_ShiftKeyPressed.find(viewId)->second) - { - return s_VirtualKeyShiftChordsForButtons.find(viewId)->second; - } - else if (s_ShiftButtonChecked.find(viewId)->second) - { - if ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down) + if (altPressed) { - auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId); - if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end()) + return nullptr; + } + else + { + if (shiftKeyPressed) { - for (auto iterator = iterViewMap->second.begin(); iterator != iterViewMap->second.end(); ++iterator) - { - if (key == iterator->first) - { - return s_VirtualKeyControlInverseChordsForButtons.find(viewId)->second; - } - } + return &s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second; + } + else + { + return &s_VirtualKeyControlChordsForButtons.find(viewId)->second; + } + } + } + else + { + if (altPressed) + { + if (!shiftKeyPressed) + { + return &s_VirtualKeyAltChordsForButtons.find(viewId)->second; + } + else + { + return nullptr; } } else { - auto iterViewMap = s_VirtualKeyInverseChordsForButtons.find(viewId); - if (iterViewMap != s_VirtualKeyInverseChordsForButtons.end()) + if (shiftKeyPressed) { - for (auto iterator = iterViewMap->second.begin(); iterator != iterViewMap->second.end(); ++iterator) - { - if (key == iterator->first) - { - return s_VirtualKeyInverseChordsForButtons.find(viewId)->second; - } - } + return &s_VirtualKeyShiftChordsForButtons.find(viewId)->second; + } + else + { + return &s_virtualKey.find(viewId)->second; } } } - if ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down) - { - return s_VirtualKeyControlChordsForButtons.find(viewId)->second; - } - else - { - return s_VirtualKeysForButtons.find(viewId)->second; - } } void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow ^ sender, KeyEventArgs ^ args) { - // If keyboard shortcuts like Ctrl+C or Ctrl+V are not handled - if (!args->Handled) + if (args->Handled) { - auto key = args->VirtualKey; - int viewId = Utils::GetWindowId(); + return; + } - auto currentControlKeyPressed = s_ControlKeyPressed.find(viewId); - auto currentShiftKeyPressed = s_ShiftKeyPressed.find(viewId); + auto key = args->VirtualKey; + int viewId = Utils::GetWindowId(); - bool isControlKeyPressed = (currentControlKeyPressed != s_ControlKeyPressed.end()) && (currentControlKeyPressed->second); - bool isShiftKeyPressed = (currentShiftKeyPressed != s_ShiftKeyPressed.end()) && (currentShiftKeyPressed->second); + const bool isControlKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down; + const bool isShiftKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Shift) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down; + const bool isAltKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Menu) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down; - // Handle Ctrl + E for DateCalculator - if ((key == VirtualKey::E) && isControlKeyPressed && !isShiftKeyPressed) + // Handle Ctrl + E for DateCalculator + if ((key == VirtualKey::E) && isControlKeyPressed && !isShiftKeyPressed && !isAltKeyPressed) + { + const auto lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, false); + if (lookupMap == nullptr) { - const auto& lookupMap = GetCurrentKeyDictionary(static_cast(key)); - auto buttons = lookupMap.equal_range(static_cast(key)); - auto navView = buttons.first->second.Resolve(); + return; + } - if (navView == nullptr) + auto buttons = lookupMap->equal_range(static_cast(key)); + auto navView = buttons.first->second.Resolve(); + auto appViewModel = safe_cast(navView->DataContext); + appViewModel->Mode = ViewMode::Date; + auto categoryName = AppResourceProvider::GetInstance()->GetResourceString(L"DateCalculationModeText"); + appViewModel->CategoryName = categoryName; + + auto menuItems = static_cast ^>(navView->MenuItemsSource); + auto flatIndex = NavCategory::GetFlatIndex(ViewMode::Date); + navView->SelectedItem = menuItems->GetAt(flatIndex); + return; + } + + auto currentIgnoreNextEscape = s_ignoreNextEscape.find(viewId); + if (currentIgnoreNextEscape != s_ignoreNextEscape.end()) + { + if (currentIgnoreNextEscape->second && key == VirtualKey::Escape) + { + auto currentKeepIgnoringEscape = s_keepIgnoringEscape.find(viewId); + + if (currentKeepIgnoringEscape != s_keepIgnoringEscape.end()) + { + if (!currentKeepIgnoringEscape->second) + { + HonorEscape(); + } + return; + } + } + } + + auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId); + if (currentHonorShortcuts != s_fHonorShortcuts.end()) + { + if (currentHonorShortcuts->second) + { + const auto myVirtualKey = static_cast(key); + const auto lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, isAltKeyPressed); + if (lookupMap == nullptr) { return; } - auto appViewModel = safe_cast(navView->DataContext); - appViewModel->Mode = ViewMode::Date; - auto categoryName = AppResourceProvider::GetInstance()->GetResourceString(L"DateCalculationModeText"); - appViewModel->CategoryName = categoryName; - - auto menuItems = static_cast ^>(navView->MenuItemsSource); - auto flatIndex = NavCategory::GetFlatIndex(ViewMode::Date); - navView->SelectedItem = menuItems->GetAt(flatIndex); - return; - } - - auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId); - - auto currentIgnoreNextEscape = s_ignoreNextEscape.find(viewId); - - if (currentIgnoreNextEscape != s_ignoreNextEscape.end()) - { - if (currentIgnoreNextEscape->second && key == VirtualKey::Escape) + auto buttons = lookupMap->equal_range(myVirtualKey); + if (buttons.first == buttons.second) { - auto currentKeepIgnoringEscape = s_keepIgnoringEscape.find(viewId); + return; + } - if (currentKeepIgnoringEscape != s_keepIgnoringEscape.end()) + RunFirstEnabledButtonCommand(buttons); + + // Ctrl+C and Ctrl+V shifts focus to some button because of which enter doesn't work after copy/paste. So don't shift focus if Ctrl+C or Ctrl+V + // is pressed. When drop down is open, pressing escape shifts focus to clear button. So dont's shift focus if drop down is open. Ctrl+Insert is + // equivalent to Ctrl+C and Shift+Insert is equivalent to Ctrl+V + auto currentIsDropDownOpen = s_IsDropDownOpen.find(viewId); + if (currentIsDropDownOpen == s_IsDropDownOpen.end() || !currentIsDropDownOpen->second) + { + // Do not Light Up Buttons when Ctrl+C, Ctrl+V, Ctrl+Insert or Shift+Insert is pressed + if (!(isControlKeyPressed && (key == VirtualKey::C || key == VirtualKey::V || key == VirtualKey::Insert)) + && !(isShiftKeyPressed && (key == VirtualKey::Insert))) { - if (!currentKeepIgnoringEscape->second) - { - HonorEscape(); - } - return; + LightUpButtons(buttons); } } } - - if (key == VirtualKey::Control) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currControlKeyPressed = s_ControlKeyPressed.find(viewId); - - if (currControlKeyPressed != s_ControlKeyPressed.end()) - { - s_ControlKeyPressed[viewId] = true; - } - return; - } - else if (key == VirtualKey::Shift) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currShiftKeyPressed = s_ShiftKeyPressed.find(viewId); - - if (currShiftKeyPressed != s_ShiftKeyPressed.end()) - { - s_ShiftKeyPressed[viewId] = true; - } - return; - } - - if (currentHonorShortcuts != s_fHonorShortcuts.end()) - { - if (currentHonorShortcuts->second) - { - const auto myVirtualKey = static_cast(key); - const auto& lookupMap = GetCurrentKeyDictionary(myVirtualKey); - auto buttons = lookupMap.equal_range(myVirtualKey); - RunFirstEnabledButtonCommand(buttons); - - // Ctrl+C and Ctrl+V shifts focus to some button because of which enter doesn't work after copy/paste. So don't shift focus if Ctrl+C or Ctrl+V - // is pressed. When drop down is open, pressing escape shifts focus to clear button. So dont's shift focus if drop down is open. Ctrl+Insert is - // equivalent to Ctrl+C and Shift+Insert is equivalent to Ctrl+V - auto currentIsDropDownOpen = s_IsDropDownOpen.find(viewId); - if (currentIsDropDownOpen != s_IsDropDownOpen.end() && !currentIsDropDownOpen->second) - { - // Do not Light Up Buttons when Ctrl+C, Ctrl+V, Ctrl+Insert or Shift+Insert is pressed - if (!(isControlKeyPressed && (key == VirtualKey::C || key == VirtualKey::V || key == VirtualKey::Insert)) - && !(isShiftKeyPressed && (key == VirtualKey::Insert))) - { - LightUpButtons(buttons); - } - } - } - } - } -} - -void KeyboardShortcutManager::OnKeyUpHandler(CoreWindow ^ sender, KeyEventArgs ^ args) -{ - int viewId = Utils::GetWindowId(); - auto key = args->VirtualKey; - - if (key == VirtualKey::Shift) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currentShiftKeyPressed = s_ShiftKeyPressed.find(viewId); - - if (currentShiftKeyPressed != s_ShiftKeyPressed.end()) - { - s_ShiftKeyPressed[viewId] = false; - } - } - else if (key == VirtualKey::Control) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currControlKeyPressed = s_ControlKeyPressed.find(viewId); - - if (currControlKeyPressed != s_ControlKeyPressed.end()) - { - s_ControlKeyPressed[viewId] = false; - } } } @@ -641,7 +520,7 @@ void KeyboardShortcutManager::OnAcceleratorKeyActivated(CoreDispatcher ^, Accele if (args->KeyStatus.IsKeyReleased) { auto key = args->VirtualKey; - bool altPressed = args->KeyStatus.IsMenuKeyDown; + const bool altPressed = args->KeyStatus.IsMenuKeyDown; // If the Alt/Menu key is not pressed then we don't care about the key anymore if (!altPressed) @@ -649,52 +528,45 @@ void KeyboardShortcutManager::OnAcceleratorKeyActivated(CoreDispatcher ^, Accele return; } + const bool controlKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down; // Ctrl is pressed in addition to alt, this means Alt Gr is intended. do not navigate. - if ((static_cast(Window::Current->CoreWindow->GetKeyState(VirtualKey::Control)) & static_cast(CoreVirtualKeyStates::Down)) - == static_cast(CoreVirtualKeyStates::Down)) + if (controlKeyPressed) { return; } - const auto& lookupMap = GetCurrentKeyDictionary(static_cast(key), altPressed); - auto listItems = lookupMap.equal_range(static_cast(key)); - for (auto listIterator = listItems.first; listIterator != listItems.second; ++listIterator) + const bool shiftKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Shift) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down; + const auto lookupMap = GetCurrentKeyDictionary(controlKeyPressed, shiftKeyPressed, altPressed); + if (lookupMap != nullptr) { - auto item = listIterator->second.Resolve(); - if (item != nullptr) + auto listItems = lookupMap->equal_range(static_cast(key)); + for (auto listIterator = listItems.first; listIterator != listItems.second; ++listIterator) { - auto navView = safe_cast(item); - - auto menuItems = static_cast ^>(navView->MenuItemsSource); - if (menuItems != nullptr) + auto item = listIterator->second.Resolve(); + if (item != nullptr) { - auto vm = safe_cast(navView->DataContext); - if (nullptr != vm) + auto navView = safe_cast(item); + + auto menuItems = static_cast ^>(navView->MenuItemsSource); + if (menuItems != nullptr) { - ViewMode toMode = NavCategory::GetViewModeForVirtualKey(static_cast(key)); - auto nvi = dynamic_cast(menuItems->GetAt(NavCategory::GetFlatIndex(toMode))); - if (nvi && nvi->IsEnabled && NavCategory::IsValidViewMode(toMode)) + auto vm = safe_cast(navView->DataContext); + if (nullptr != vm) { - vm->Mode = toMode; - navView->SelectedItem = nvi; + ViewMode toMode = NavCategory::GetViewModeForVirtualKey(static_cast(key)); + auto nvi = dynamic_cast(menuItems->GetAt(NavCategory::GetFlatIndex(toMode))); + if (nvi && nvi->IsEnabled && NavCategory::IsValidViewMode(toMode)) + { + vm->Mode = toMode; + navView->SelectedItem = nvi; + } } } + break; } - break; } } } - - if (args->VirtualKey == VirtualKey::Escape) - { - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_AboutFlyout.find(viewId); - - if ((iterViewMap != s_AboutFlyout.end()) && (iterViewMap->second != nullptr)) - { - iterViewMap->second->Hide(); - } - } } void KeyboardShortcutManager::Initialize() @@ -703,23 +575,12 @@ void KeyboardShortcutManager::Initialize() coreWindow->CharacterReceived += ref new TypedEventHandler(&KeyboardShortcutManager::OnCharacterReceivedHandler); coreWindow->KeyDown += ref new TypedEventHandler(&KeyboardShortcutManager::OnKeyDownHandler); - coreWindow->KeyUp += ref new TypedEventHandler(&KeyboardShortcutManager::OnKeyUpHandler); coreWindow->Dispatcher->AcceleratorKeyActivated += ref new TypedEventHandler(&KeyboardShortcutManager::OnAcceleratorKeyActivated); KeyboardShortcutManager::RegisterNewAppViewId(); } -void KeyboardShortcutManager::ShiftButtonChecked(bool checked) -{ - int viewId = Utils::GetWindowId(); - - if (s_ShiftButtonChecked.find(viewId) != s_ShiftButtonChecked.end()) - { - s_ShiftButtonChecked[viewId] = checked; - } -} - void KeyboardShortcutManager::UpdateDropDownState(bool isOpen) { int viewId = Utils::GetWindowId(); @@ -730,16 +591,6 @@ void KeyboardShortcutManager::UpdateDropDownState(bool isOpen) } } -void KeyboardShortcutManager::UpdateDropDownState(Flyout ^ aboutPageFlyout) -{ - int viewId = Utils::GetWindowId(); - - if (s_AboutFlyout.find(viewId) != s_AboutFlyout.end()) - { - s_AboutFlyout[viewId] = aboutPageFlyout; - } -} - void KeyboardShortcutManager::HonorShortcuts(bool allow) { // Writer lock for the static maps @@ -770,55 +621,41 @@ void KeyboardShortcutManager::RegisterNewAppViewId() int appViewId = Utils::GetWindowId(); // Check if the View Id has already been registered - if (s_CharacterForButtons.find(appViewId) == s_CharacterForButtons.end()) + if (s_characterForButtons.find(appViewId) == s_characterForButtons.end()) { - s_CharacterForButtons.insert(std::make_pair(appViewId, std::multimap())); + s_characterForButtons.insert(make_pair(appViewId, multimap())); } - if (s_VirtualKeysForButtons.find(appViewId) == s_VirtualKeysForButtons.end()) + if (s_virtualKey.find(appViewId) == s_virtualKey.end()) { - s_VirtualKeysForButtons.insert(std::make_pair(appViewId, std::multimap())); + s_virtualKey.insert(make_pair(appViewId, multimap())); } if (s_VirtualKeyControlChordsForButtons.find(appViewId) == s_VirtualKeyControlChordsForButtons.end()) { - s_VirtualKeyControlChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); + s_VirtualKeyControlChordsForButtons.insert(make_pair(appViewId, multimap())); } if (s_VirtualKeyShiftChordsForButtons.find(appViewId) == s_VirtualKeyShiftChordsForButtons.end()) { - s_VirtualKeyShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); + s_VirtualKeyShiftChordsForButtons.insert(make_pair(appViewId, multimap())); } if (s_VirtualKeyAltChordsForButtons.find(appViewId) == s_VirtualKeyAltChordsForButtons.end()) { - s_VirtualKeyAltChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); + s_VirtualKeyAltChordsForButtons.insert(make_pair(appViewId, multimap())); } if (s_VirtualKeyControlShiftChordsForButtons.find(appViewId) == s_VirtualKeyControlShiftChordsForButtons.end()) { - s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); + s_VirtualKeyControlShiftChordsForButtons.insert(make_pair(appViewId, multimap())); } - if (s_VirtualKeyInverseChordsForButtons.find(appViewId) == s_VirtualKeyInverseChordsForButtons.end()) - { - s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeyControlInverseChordsForButtons.find(appViewId) == s_VirtualKeyControlInverseChordsForButtons.end()) - { - s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - s_ShiftKeyPressed[appViewId] = false; - s_ControlKeyPressed[appViewId] = false; - s_ShiftButtonChecked[appViewId] = false; s_IsDropDownOpen[appViewId] = false; s_ignoreNextEscape[appViewId] = false; s_keepIgnoringEscape[appViewId] = false; s_fHonorShortcuts[appViewId] = true; s_fDisableShortcuts[appViewId] = false; - s_AboutFlyout[appViewId] = nullptr; } void KeyboardShortcutManager::OnWindowClosed(int viewId) @@ -826,25 +663,19 @@ void KeyboardShortcutManager::OnWindowClosed(int viewId) // Writer lock for the static maps reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - s_CharacterForButtons.erase(viewId); + s_characterForButtons.erase(viewId); - s_VirtualKeysForButtons.erase(viewId); + s_virtualKey.erase(viewId); s_VirtualKeyControlChordsForButtons.erase(viewId); s_VirtualKeyShiftChordsForButtons.erase(viewId); s_VirtualKeyAltChordsForButtons.erase(viewId); s_VirtualKeyControlShiftChordsForButtons.erase(viewId); - s_VirtualKeyInverseChordsForButtons.erase(viewId); - s_VirtualKeyControlInverseChordsForButtons.erase(viewId); - s_ShiftKeyPressed.erase(viewId); - s_ControlKeyPressed.erase(viewId); - s_ShiftButtonChecked.erase(viewId); s_IsDropDownOpen.erase(viewId); s_ignoreNextEscape.erase(viewId); s_keepIgnoringEscape.erase(viewId); s_fHonorShortcuts.erase(viewId); s_fDisableShortcuts.erase(viewId); - s_AboutFlyout.erase(viewId); } void KeyboardShortcutManager::DisableShortcuts(bool disable) diff --git a/src/Calculator/Common/KeyboardShortcutManager.h b/src/Calculator/Common/KeyboardShortcutManager.h index 32ace85b..1ca7e487 100644 --- a/src/Calculator/Common/KeyboardShortcutManager.h +++ b/src/Calculator/Common/KeyboardShortcutManager.h @@ -26,8 +26,6 @@ namespace CalculatorApp DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyShiftChord); DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyAltChord); DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyControlShiftChord); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyInverseChord); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyControlInverseChord); internal : @@ -45,8 +43,6 @@ namespace CalculatorApp static void HonorShortcuts(bool allow); static void DisableShortcuts(bool disable); static void UpdateDropDownState(bool); - static void ShiftButtonChecked(bool checked); - static void UpdateDropDownState(Windows::UI::Xaml::Controls::Flyout ^ aboutPageFlyout); static void RegisterNewAppViewId(); static void OnWindowClosed(int viewId); @@ -60,11 +56,6 @@ namespace CalculatorApp static void OnVirtualKeyShiftChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - static void OnVirtualKeyInverseChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void - OnVirtualKeyControlInverseChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - static void OnVirtualKeyAltChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); static void @@ -72,8 +63,25 @@ namespace CalculatorApp static void OnCharacterReceivedHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::CharacterReceivedEventArgs ^ args); static void OnKeyDownHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ args); - static void OnKeyUpHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ args); static void OnAcceleratorKeyActivated(Windows::UI::Core::CoreDispatcher ^, Windows::UI::Core::AcceleratorKeyEventArgs ^ args); + static const std::multimap* + KeyboardShortcutManager::GetCurrentKeyDictionary(bool controlKeyPressed, bool shiftKeyPressed, bool altPressed); + + private: + static std::map> s_characterForButtons; + static std::map> s_virtualKey; + static std::map> s_VirtualKeyControlChordsForButtons; + static std::map> s_VirtualKeyShiftChordsForButtons; + static std::map> s_VirtualKeyAltChordsForButtons; + static std::map> s_VirtualKeyControlShiftChordsForButtons; + + static std::map s_IsDropDownOpen; + static std::map s_ignoreNextEscape; + static std::map s_keepIgnoringEscape; + static std::map s_fHonorShortcuts; + static std::map s_fDisableShortcuts; + + static Concurrency::reader_writer_lock s_keyboardShortcutMapLock; }; } } diff --git a/src/Calculator/Resources/en-US/Resources.resw b/src/Calculator/Resources/en-US/Resources.resw index 296f790c..b4b9941e 100644 --- a/src/Calculator/Resources/en-US/Resources.resw +++ b/src/Calculator/Resources/en-US/Resources.resw @@ -481,50 +481,26 @@ O {Locked}The shortcut for the inverted cos button - - O - {Locked}The shortcut for the inverted cos button - O {Locked}The shortcut for the inverted cosh button - - O - {Locked}The shortcut for the inverted cosh button - S {Locked}This is the shortcut for the inverted sin button - - S - {Locked}This is the shortcut for the inverted sin button - S {Locked}This is the shortcut for the inverted sinh button - - S - {Locked}This is the shortcut for the inverted sinh button - T {Locked}This is the shortcut for the inverted tan button. - - T - {Locked}This is the shortcut for the inverted tan button. - T {Locked}This is the shortcut for the inverted tanh button - - T - {Locked}This is the shortcut for the inverted tanh button - N {Locked}This is the shortcut for the power x button. @@ -3587,10 +3563,6 @@ U {Locked}The shortcut for the inverted sec button - - U - {Locked}The shortcut for the inverted sec button - Hyperbolic Arc Secant Screen reader prompt for the Calculator button arc sec in the scientific flyout keypad @@ -3599,10 +3571,6 @@ U {Locked}The shortcut for the inverted sech button - - U - {Locked}The shortcut for the inverted sech button - Cosecant Screen reader prompt for the Calculator button csc in the scientific flyout keypad @@ -3623,14 +3591,6 @@ Arc Cosecant Screen reader prompt for the Calculator button arc csc in the scientific flyout keypad - - I - {Locked}The shortcut for the inverted sec button - - - I - {Locked}The shortcut for the inverted sec button - Hyperbolic Arc Cosecant Screen reader prompt for the Calculator button arc csc in the scientific flyout keypad @@ -3639,10 +3599,6 @@ I {Locked}The shortcut for the inverted sech button - - I - {Locked}The shortcut for the inverted sech button - Cotangent Screen reader prompt for the Calculator button cot in the scientific flyout keypad @@ -3667,18 +3623,10 @@ J {Locked}The shortcut for the inverted sec button - - J - {Locked}The shortcut for the inverted sec button - Hyperbolic Arc Cotangent Screen reader prompt for the Calculator button arc coth in the scientific flyout keypad - - J - {Locked}The shortcut for the inverted sech button - J {Locked}The shortcut for the inverted sech button diff --git a/src/Calculator/Views/MainPage.xaml.cpp b/src/Calculator/Views/MainPage.xaml.cpp index 5af8f4d0..f0c0b5e8 100644 --- a/src/Calculator/Views/MainPage.xaml.cpp +++ b/src/Calculator/Views/MainPage.xaml.cpp @@ -436,16 +436,14 @@ void MainPage::OnAboutFlyoutOpened(_In_ Object ^ sender, _In_ Object ^ e) { // Keep Ignoring Escape till the About page flyout is opened KeyboardShortcutManager::IgnoreEscape(false); - - KeyboardShortcutManager::UpdateDropDownState(this->AboutPageFlyout); + KeyboardShortcutManager::HonorShortcuts(false); } void MainPage::OnAboutFlyoutClosed(_In_ Object ^ sender, _In_ Object ^ e) { // Start Honoring Escape once the About page flyout is closed KeyboardShortcutManager::HonorEscape(); - - KeyboardShortcutManager::UpdateDropDownState(nullptr); + KeyboardShortcutManager::HonorShortcuts(!NavView->IsPaneOpen); } void MainPage::OnNavSelectionChanged(_In_ Object ^ sender, _In_ MUXC::NavigationViewSelectionChangedEventArgs ^ e) From a0f98ca76b674afd4b4399677c5e25fbb34c254d Mon Sep 17 00:00:00 2001 From: Stephanie Anderl <46726333+sanderl@users.noreply.github.com> Date: Tue, 15 Sep 2020 14:27:22 -0700 Subject: [PATCH 5/5] Improved error handing for function analysis for functions in the f(y) format (#1338) * Updated the CanFunctionAnalysisBePerformed api to use the updated one with variableIsNotX error handling. Updated the UI to reflect the new descriptive error case to show an informative error. * Fixed spacing and updated the moved the variableIsNotX check up into the parent if statement * Update the internals version to match the version needed to support this change --- build/pipelines/templates/build-app-internal.yaml | 2 +- .../templates/prepare-release-internalonly.yaml | 2 +- .../GraphingCalculator/EquationViewModel.cpp | 4 ++++ src/CalcViewModel/GraphingCalculatorEnums.h | 3 ++- src/Calculator/Resources/en-US/Resources.resw | 4 ++++ src/GraphControl/Control/Grapher.cpp | 8 ++++++-- src/GraphingInterfaces/IGraphAnalyzer.h | 12 ++++++------ 7 files changed, 24 insertions(+), 11 deletions(-) diff --git a/build/pipelines/templates/build-app-internal.yaml b/build/pipelines/templates/build-app-internal.yaml index 4418395d..08d38a1c 100644 --- a/build/pipelines/templates/build-app-internal.yaml +++ b/build/pipelines/templates/build-app-internal.yaml @@ -29,7 +29,7 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsInboxApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.49 + vstsPackageVersion: 0.0.50 - template: ./build-single-architecture.yaml parameters: diff --git a/build/pipelines/templates/prepare-release-internalonly.yaml b/build/pipelines/templates/prepare-release-internalonly.yaml index 945de53a..be286c65 100644 --- a/build/pipelines/templates/prepare-release-internalonly.yaml +++ b/build/pipelines/templates/prepare-release-internalonly.yaml @@ -80,7 +80,7 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsInboxApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.49 + vstsPackageVersion: 0.0.50 - powershell: | # Just modify this line to indicate where your en-us PDP file is. Leave the other lines alone. diff --git a/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp index 666f55ec..50592aa4 100644 --- a/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp +++ b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp @@ -63,6 +63,10 @@ namespace CalculatorApp::ViewModel { AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisNotSupported"); } + else if (graphEquation->AnalysisError == static_cast(AnalysisErrorType::VariableIsNotX)) + { + AnalysisErrorString = m_resourceLoader->GetString(L"KGFVariableIsNotX"); + } return; } diff --git a/src/CalcViewModel/GraphingCalculatorEnums.h b/src/CalcViewModel/GraphingCalculatorEnums.h index 5cf136a5..8093f4a6 100644 --- a/src/CalcViewModel/GraphingCalculatorEnums.h +++ b/src/CalcViewModel/GraphingCalculatorEnums.h @@ -23,6 +23,7 @@ namespace CalculatorApp { NoError, AnalysisCouldNotBePerformed, - AnalysisNotSupported + AnalysisNotSupported, + VariableIsNotX }; } diff --git a/src/Calculator/Resources/en-US/Resources.resw b/src/Calculator/Resources/en-US/Resources.resw index b4b9941e..d8ec8d59 100644 --- a/src/Calculator/Resources/en-US/Resources.resw +++ b/src/Calculator/Resources/en-US/Resources.resw @@ -4019,6 +4019,10 @@ Analysis is not supported for this function. Error displayed when graph analysis is not supported or had an error. + + Analysis is only supported for functions in the f(x) format. Example: y=x + Error displayed when graph analysis detects the function format is not f(x). + Maxima Title for KeyGraphFeatures Maxima Property diff --git a/src/GraphControl/Control/Grapher.cpp b/src/GraphControl/Control/Grapher.cpp index 2c75e207..1132edad 100644 --- a/src/GraphControl/Control/Grapher.cpp +++ b/src/GraphControl/Control/Grapher.cpp @@ -254,8 +254,8 @@ namespace GraphControl vector equationVector; equationVector.push_back(equation); UpdateGraphOptions(graph->GetOptions(), equationVector); - - if (analyzer->CanFunctionAnalysisBePerformed()) + bool variableIsNotX; + if (analyzer->CanFunctionAnalysisBePerformed(variableIsNotX) && !variableIsNotX) { if (S_OK == analyzer->PerformFunctionAnalysis( @@ -265,6 +265,10 @@ namespace GraphControl return KeyGraphFeaturesInfo::Create(functionAnalysisData); } } + else if (variableIsNotX) + { + return KeyGraphFeaturesInfo::Create(CalculatorApp::AnalysisErrorType::VariableIsNotX); + } else { return KeyGraphFeaturesInfo::Create(CalculatorApp::AnalysisErrorType::AnalysisNotSupported); diff --git a/src/GraphingInterfaces/IGraphAnalyzer.h b/src/GraphingInterfaces/IGraphAnalyzer.h index 4bd962c4..5b5e012f 100644 --- a/src/GraphingInterfaces/IGraphAnalyzer.h +++ b/src/GraphingInterfaces/IGraphAnalyzer.h @@ -15,10 +15,10 @@ namespace Graphing::Analyzer struct IGraphAnalyzer : public NonCopyable, public NonMoveable { - virtual ~IGraphAnalyzer() = default; - virtual bool CanFunctionAnalysisBePerformed() = 0; - virtual HRESULT PerformFunctionAnalysis(NativeAnalysisType analysisType) = 0; - virtual HRESULT GetAnalysisTypeCaption(const AnalysisType type, std::wstring& captionOut) const = 0; - virtual HRESULT GetMessage(const GraphAnalyzerMessage msg, std::wstring& msgOut) const = 0; + virtual ~IGraphAnalyzer() = default; + virtual bool CanFunctionAnalysisBePerformed(bool& variableIsNotX) = 0; + virtual HRESULT PerformFunctionAnalysis(NativeAnalysisType analysisType) = 0; + virtual HRESULT GetAnalysisTypeCaption(const AnalysisType type, std::wstring& captionOut) const = 0; + virtual HRESULT GetMessage(const GraphAnalyzerMessage msg, std::wstring& msgOut) const = 0; }; -} \ No newline at end of file +}