mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
[KBM]Launch apps / URI with keyboard shortcuts, support chords (#30121)
* Working UI update with just runProgram Path and isRunProgram * First working, basic. no args or path, or setting change detections. * Revert and fixed. * Some clean up, working with config file monitor * Args and Start-in should be working. * File monitor, quotes, xaml screens one * Fixed enable/disable toogle from XAML * Code cleanup. * Betting logging. * Cleanup, start of RunProgramDescriptor and usage of run_non_elevated/run_elevated * Code moved to KeyboardEventHandlers, but not enabled since it won't build as is, needs elevation.h. Other testing.. * Key chords working, pretty much * Added gui for elevation level, need to refresh on change... * f: include shellapi.h and reference wil in KBMEL * run_elevated/run_non_elevated sorted out. Working! * Removed lots of old temp code. * Fix some speling errors. * Cleanup before trying to add a UI for the chord * Added "DifferentUser" option * Closer on UI for chords. * Better UI, lots working. * Clean up * Text for “Allow chords” – needs to look better… * Bugs and clean-up * Cleanup * Refactor and clean up. * More clean up * Some localization. * Don’t show “Allow chords“ to the “to” shortcut * Maybe better foreground after opening new app * Better chord matching. * Runprogram fix for stealing existing shortcut. * Better runProgram stuff * Temp commit * Working well * Toast test * More toast * Added File and Folder picker UI * Pre-check on run program file exists. * Refactor to SetupRunProgramControls * Open URI UI is going. * Open URI working well * Open URI stuff working well * Allowed AppSpecific shortcut and fixed backup/restore shortcut dups * Fixed settings screen * Start of code to find by name... * UI fixed * Small fixes * Some single edit code working. * UI getting better. * Fixes * Fixed and merge from main * UI updates * UI updates. * UI stuff * Fixed crash from move ui item locations. * Fixed crash from move ui item locations. * Added delete confirm * Basic sound working. * Localized some stuff * Added sounds * Better experiance when shortcut is in use. * UI tweaks * Fixed KBM ui for unicode shortcut not having "," * Some clean up * Cleanup * Cleanup * Fixed applyXamlStyling * Added back stuff lost in merge * applyXamlStyling, again * Fixed crash on change from non shortcut to shortcut * Update src/modules/keyboardmanager/KeyboardManagerEngineTest/KeyboardManagerEngineTest.vcxproj * Fixed some spelling type issues. * ImplementationLibrary 231216 * Comment bump to see if the Microsoft.Windows.ImplementationLibrary version thing gets picked up * Correct, Microsoft.Windows.ImplementationLibrary, finally? * Fixed two test that failed because we now allow key-chords. * Removed shortcut sounds. * use original behavior when "allow chords" is off in shortcut window * fix crash when editing a shortcut that has apps specified for it * split KBM chords with comma on dashboard page * Fix some spelling items. * More "spelling" * Fix XAML styling * align TextBlock and ToggleSwitch * fix cutoff issue at the top * increase ComboBox width * Added *Unsupported* for backwards compat on config of KBM * fix spellcheck * Fix crash on Remap key screen * Fixed Remap Keys ComboBox width too short. * Removed KBM Single Edit mode, fixed crash. * Fix Xaml with xaml cops * Fix crash on setting "target app" for some types of shortcuts. * Space to toggle chord, combobox back * fix spellcheck * fix some code nits * Code review updates. * Add exclusions to the bug report tool * Code review and kill CloseAndEndTask * Fix alignment / 3 comboboxes per row * Fix daily telemetry events to exclude start app and open URI * Add chords and remove app start and open uri from config telemetry * comma instead of plus in human readable shortcut telemetry data * Code review, restore default-old state when new row added in KBM * Code review, restore default-old state when new row added in KBM, part 2 * Still show target app on Settings * Only allow enabling chords for origin shortcuts --------- Co-authored-by: Andrey Nekrasov <yuyoyuppe@users.noreply.github.com> Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
This commit is contained in:
@@ -18,9 +18,29 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return base.GetMappedOriginalKeys();
|
||||
}
|
||||
|
||||
public new List<string> GetMappedNewRemapKeys()
|
||||
public new List<string> GetMappedOriginalKeysWithSplitChord()
|
||||
{
|
||||
return base.GetMappedNewRemapKeys();
|
||||
return base.GetMappedOriginalKeysWithSplitChord();
|
||||
}
|
||||
|
||||
public List<string> GetMappedOriginalKeys(bool ignoreSecondKeyInChord)
|
||||
{
|
||||
return base.GetMappedOriginalKeys(ignoreSecondKeyInChord);
|
||||
}
|
||||
|
||||
public List<string> GetMappedOriginalKeysWithoutChord()
|
||||
{
|
||||
return base.GetMappedOriginalKeys(true);
|
||||
}
|
||||
|
||||
public new List<string> GetMappedOriginalKeysOnlyChord()
|
||||
{
|
||||
return base.GetMappedOriginalKeysOnlyChord();
|
||||
}
|
||||
|
||||
public new List<string> GetMappedNewRemapKeys(int runProgramMaxLength)
|
||||
{
|
||||
return base.GetMappedNewRemapKeys(runProgramMaxLength);
|
||||
}
|
||||
|
||||
public bool Compare(AppSpecificKeysDataModel arg)
|
||||
|
||||
@@ -2,42 +2,312 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class KeysDataModel
|
||||
public class KeysDataModel : INotifyPropertyChanged
|
||||
{
|
||||
[JsonPropertyName("originalKeys")]
|
||||
public string OriginalKeys { get; set; }
|
||||
|
||||
[JsonPropertyName("secondKeyOfChord")]
|
||||
public int SecondKeyOfChord { get; set; }
|
||||
|
||||
[JsonPropertyName("newRemapKeys")]
|
||||
public string NewRemapKeys { get; set; }
|
||||
|
||||
[JsonPropertyName("unicodeText")]
|
||||
public string NewRemapString { get; set; }
|
||||
|
||||
[JsonPropertyName("runProgramFilePath")]
|
||||
public string RunProgramFilePath { get; set; }
|
||||
|
||||
[JsonPropertyName("runProgramArgs")]
|
||||
public string RunProgramArgs { get; set; }
|
||||
|
||||
[JsonPropertyName("openUri")]
|
||||
public string OpenUri { get; set; }
|
||||
|
||||
[JsonPropertyName("operationType")]
|
||||
public int OperationType { get; set; }
|
||||
|
||||
private enum KeyboardManagerEditorType
|
||||
{
|
||||
KeyEditor = 0,
|
||||
ShortcutEditor,
|
||||
}
|
||||
|
||||
public const string CommaSeparator = "<comma>";
|
||||
|
||||
private static Process editor;
|
||||
private ICommand _editShortcutItemCommand;
|
||||
|
||||
public ICommand EditShortcutItem => _editShortcutItemCommand ?? (_editShortcutItemCommand = new RelayCommand<object>(OnEditShortcutItem));
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public void OnEditShortcutItem(object parameter)
|
||||
{
|
||||
OpenEditor((int)KeyboardManagerEditorType.ShortcutEditor);
|
||||
}
|
||||
|
||||
private async void OpenEditor(int type)
|
||||
{
|
||||
if (editor != null)
|
||||
{
|
||||
BringProcessToFront(editor);
|
||||
return;
|
||||
}
|
||||
|
||||
const string PowerToyName = KeyboardManagerSettings.ModuleName;
|
||||
const string KeyboardManagerEditorPath = "KeyboardManagerEditor\\PowerToys.KeyboardManagerEditor.exe";
|
||||
try
|
||||
{
|
||||
if (editor != null && editor.HasExited)
|
||||
{
|
||||
Logger.LogInfo($"Previous instance of {PowerToyName} editor exited");
|
||||
editor = null;
|
||||
}
|
||||
|
||||
if (editor != null)
|
||||
{
|
||||
Logger.LogInfo($"The {PowerToyName} editor instance {editor.Id} exists. Bringing the process to the front");
|
||||
BringProcessToFront(editor);
|
||||
return;
|
||||
}
|
||||
|
||||
string path = Path.Combine(Environment.CurrentDirectory, KeyboardManagerEditorPath);
|
||||
Logger.LogInfo($"Starting {PowerToyName} editor from {path}");
|
||||
|
||||
// InvariantCulture: type represents the KeyboardManagerEditorType enum value
|
||||
editor = Process.Start(path, $"{type.ToString(CultureInfo.InvariantCulture)} {Environment.ProcessId}");
|
||||
|
||||
await editor.WaitForExitAsync();
|
||||
|
||||
editor = null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
editor = null;
|
||||
Logger.LogError($"Exception encountered when opening an {PowerToyName} editor", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void BringProcessToFront(Process process)
|
||||
{
|
||||
if (process == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr handle = process.MainWindowHandle;
|
||||
if (NativeMethods.IsIconic(handle))
|
||||
{
|
||||
NativeMethods.ShowWindow(handle, NativeMethods.SWRESTORE);
|
||||
}
|
||||
|
||||
NativeMethods.SetForegroundWindow(handle);
|
||||
}
|
||||
|
||||
private static List<string> MapKeysOnlyChord(int secondKeyOfChord)
|
||||
{
|
||||
var result = new List<string>();
|
||||
if (secondKeyOfChord <= 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Add(Helper.GetKeyName((uint)secondKeyOfChord));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<string> MapKeys(string stringOfKeys, int secondKeyOfChord, bool splitChordsWithComma = false)
|
||||
{
|
||||
if (stringOfKeys == null)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
if (secondKeyOfChord > 0)
|
||||
{
|
||||
var keys = stringOfKeys.Split(';');
|
||||
return keys.Take(keys.Length - 1)
|
||||
.Select(uint.Parse)
|
||||
.Select(Helper.GetKeyName)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (splitChordsWithComma)
|
||||
{
|
||||
var keys = stringOfKeys.Split(';')
|
||||
.Select(uint.Parse)
|
||||
.Select(Helper.GetKeyName)
|
||||
.ToList();
|
||||
keys.Insert(keys.Count - 1, CommaSeparator);
|
||||
return keys;
|
||||
}
|
||||
else
|
||||
{
|
||||
return stringOfKeys
|
||||
.Split(';')
|
||||
.Select(uint.Parse)
|
||||
.Select(Helper.GetKeyName)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> MapKeys(string stringOfKeys)
|
||||
{
|
||||
return stringOfKeys
|
||||
.Split(';')
|
||||
.Select(uint.Parse)
|
||||
.Select(Helper.GetKeyName)
|
||||
.ToList();
|
||||
return MapKeys(stringOfKeys, 0);
|
||||
}
|
||||
|
||||
public List<string> GetMappedOriginalKeys(bool ignoreSecondKeyInChord, bool splitChordsWithComma = false)
|
||||
{
|
||||
if (ignoreSecondKeyInChord && SecondKeyOfChord > 0)
|
||||
{
|
||||
return MapKeys(OriginalKeys, SecondKeyOfChord);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MapKeys(OriginalKeys, -1, splitChordsWithComma);
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetMappedOriginalKeysOnlyChord()
|
||||
{
|
||||
return MapKeysOnlyChord(SecondKeyOfChord);
|
||||
}
|
||||
|
||||
public List<string> GetMappedOriginalKeys()
|
||||
{
|
||||
return MapKeys(OriginalKeys);
|
||||
return GetMappedOriginalKeys(false);
|
||||
}
|
||||
|
||||
public List<string> GetMappedNewRemapKeys()
|
||||
public List<string> GetMappedOriginalKeysWithSplitChord()
|
||||
{
|
||||
return string.IsNullOrEmpty(NewRemapString) ? MapKeys(NewRemapKeys) : new List<string> { NewRemapString };
|
||||
return GetMappedOriginalKeys(false, true);
|
||||
}
|
||||
|
||||
public bool IsRunProgram
|
||||
{
|
||||
get
|
||||
{
|
||||
return OperationType == 1;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOpenURI
|
||||
{
|
||||
get
|
||||
{
|
||||
return OperationType == 2;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOpenUriOrIsRunProgram
|
||||
{
|
||||
get
|
||||
{
|
||||
return IsOpenURI || IsRunProgram;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasChord
|
||||
{
|
||||
get
|
||||
{
|
||||
return SecondKeyOfChord > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetMappedNewRemapKeys(int runProgramMaxLength)
|
||||
{
|
||||
if (IsRunProgram)
|
||||
{
|
||||
// we're going to just pretend this is a "key" if we have a RunProgramFilePath
|
||||
if (string.IsNullOrEmpty(RunProgramFilePath))
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<string> { FormatFakeKeyForDisplay(runProgramMaxLength) };
|
||||
}
|
||||
}
|
||||
else if (IsOpenURI)
|
||||
{
|
||||
// we're going to just pretend this is a "key" if we have a RunProgramFilePath
|
||||
if (string.IsNullOrEmpty(OpenUri))
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OpenUri.Length > runProgramMaxLength)
|
||||
{
|
||||
return new List<string> { $"{OpenUri.Substring(0, runProgramMaxLength - 3)}..." };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<string> { OpenUri };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (string.IsNullOrEmpty(NewRemapString) || NewRemapString == "*Unsupported*") ? MapKeys(NewRemapKeys) : new List<string> { NewRemapString };
|
||||
}
|
||||
|
||||
// Instead of doing something fancy pants, we 'll just display the RunProgramFilePath data when it's IsRunProgram
|
||||
// It truncates the start of the program to run, if it's long and truncates the end of the args if it's long
|
||||
// e.g.: c:\MyCool\PathIs\Long\software.exe myArg1 myArg2 myArg3 -> (something like) "...ng\software.exe myArg1..."
|
||||
// the idea is you get the most important part of the program to run and some of the args in case that the only thing thats different,
|
||||
// e.g: "...path\software.exe cool1.txt" and "...path\software.exe cool3.txt"
|
||||
private string FormatFakeKeyForDisplay(int runProgramMaxLength)
|
||||
{
|
||||
// was going to use this:
|
||||
var fakeKey = Environment.ExpandEnvironmentVariables(RunProgramFilePath);
|
||||
try
|
||||
{
|
||||
if (File.Exists(fakeKey))
|
||||
{
|
||||
fakeKey = Path.GetFileName(Environment.ExpandEnvironmentVariables(RunProgramFilePath));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
fakeKey = $"{fakeKey} {RunProgramArgs}".Trim();
|
||||
|
||||
if (fakeKey.Length > runProgramMaxLength)
|
||||
{
|
||||
fakeKey = $"{fakeKey.Substring(0, runProgramMaxLength - 3)}...";
|
||||
}
|
||||
|
||||
return fakeKey;
|
||||
}
|
||||
|
||||
public string ToJsonString()
|
||||
|
||||
@@ -324,8 +324,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
// the settings file needs to be updated, update the real one with non-excluded stuff...
|
||||
Logger.LogInfo($"Settings file {currentFile.Key} is different and is getting updated from backup");
|
||||
|
||||
var newCurrentSettingsFile = JsonMergeHelper.Merge(File.ReadAllText(currentSettingsFiles[currentFile.Key]), settingsToRestoreJson);
|
||||
File.WriteAllText(currentSettingsFiles[currentFile.Key], newCurrentSettingsFile);
|
||||
// we needed a new "CustomRestoreSettings" for now, to overwrite because some settings don't merge well (like KBM shortcuts)
|
||||
var overwrite = false;
|
||||
if (backupRestoreSettings["CustomRestoreSettings"] != null && backupRestoreSettings["CustomRestoreSettings"][currentFile.Key] != null)
|
||||
{
|
||||
var customRestoreSettings = backupRestoreSettings["CustomRestoreSettings"][currentFile.Key];
|
||||
overwrite = customRestoreSettings["overwrite"] != null && (bool)customRestoreSettings["overwrite"];
|
||||
}
|
||||
|
||||
if (overwrite)
|
||||
{
|
||||
File.WriteAllText(currentSettingsFiles[currentFile.Key], settingsToRestoreJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newCurrentSettingsFile = JsonMergeHelper.Merge(File.ReadAllText(currentSettingsFiles[currentFile.Key]), settingsToRestoreJson);
|
||||
File.WriteAllText(currentSettingsFiles[currentFile.Key], newCurrentSettingsFile);
|
||||
}
|
||||
|
||||
anyFilesUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"CustomRestoreSettings": {
|
||||
"\\Keyboard Manager\\default.json": {
|
||||
"overwrite": true
|
||||
}
|
||||
},
|
||||
"IgnoredSettings": {
|
||||
"backup-restore_settings.json": [
|
||||
"RestartAfterRestore"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
internal sealed class KeyVisualTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public DataTemplate KeyVisualTemplate { get; set; }
|
||||
|
||||
public DataTemplate CommaTemplate { get; set; }
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
var stringValue = item as string;
|
||||
return stringValue == KeysDataModel.CommaSeparator ? CommaTemplate : KeyVisualTemplate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,26 @@
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="KeyVisualTemplate">
|
||||
<controls:KeyVisual
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Content="{Binding}"
|
||||
IsTabStop="False"
|
||||
VisualType="TextOnly" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="CommaTemplate">
|
||||
<StackPanel Background="{ThemeResource SystemFillColorSolidAttentionBackground}">
|
||||
<TextBlock
|
||||
Margin="4,0"
|
||||
VerticalAlignment="Bottom"
|
||||
Text="," />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<converters:KeyVisualTemplateSelector
|
||||
x:Key="KeyVisualTemplateSelector"
|
||||
CommaTemplate="{StaticResource CommaTemplate}"
|
||||
KeyVisualTemplate="{StaticResource KeyVisualTemplate}" />
|
||||
<converters:ModuleItemTemplateSelector
|
||||
x:Key="ModuleItemTemplateSelector"
|
||||
ButtonTemplate="{StaticResource ModuleItemButtonTemplate}"
|
||||
@@ -156,7 +176,7 @@
|
||||
<ItemsControl
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
IsTabStop="False"
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys()}">
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys(15)}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="12" />
|
||||
@@ -190,7 +210,7 @@
|
||||
<DataTemplate x:DataType="Lib:AppSpecificKeysDataModel">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border
|
||||
Padding="8,4"
|
||||
Padding="8,0"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
@@ -198,29 +218,27 @@
|
||||
<ItemsControl
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
IsTabStop="False"
|
||||
ItemsSource="{x:Bind GetMappedOriginalKeys()}">
|
||||
ItemTemplateSelector="{StaticResource KeyVisualTemplateSelector}"
|
||||
ItemsSource="{x:Bind GetMappedOriginalKeysWithSplitChord()}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="12" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:KeyVisual
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Content="{Binding}"
|
||||
IsTabStop="False"
|
||||
VisualType="TextOnly" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
<controls:IsEnabledTextBlock
|
||||
x:Uid="To"
|
||||
Margin="8,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SecondaryIsEnabledTextBlockStyle}" />
|
||||
Style="{StaticResource SecondaryIsEnabledTextBlockStyle}"
|
||||
Visibility="{x:Bind Path=IsOpenUriOrIsRunProgram, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
|
||||
<controls:IsEnabledTextBlock
|
||||
x:Uid="Starts"
|
||||
Margin="8,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SecondaryIsEnabledTextBlockStyle}"
|
||||
Visibility="{x:Bind Path=IsOpenUriOrIsRunProgram, Mode=OneWay}" />
|
||||
<Border
|
||||
Padding="8,4"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
@@ -230,7 +248,7 @@
|
||||
<ItemsControl
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
IsTabStop="False"
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys()}">
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys(15)}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="12" />
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
|
||||
<Page.Resources>
|
||||
<tkconverters:CollectionVisibilityConverter x:Key="CollectionVisibilityConverter" />
|
||||
<tkconverters:BoolToVisibilityConverter
|
||||
x:Key="BoolToInvertedVisibilityConverter"
|
||||
FalseValue="Visible"
|
||||
TrueValue="Collapsed" />
|
||||
<tkconverters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
|
||||
<Style x:Name="KeysListViewContainerStyle" TargetType="ListViewItem">
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
</Style>
|
||||
@@ -105,7 +111,7 @@
|
||||
x:Uid="KeyboardManager_RemappedTo"
|
||||
IsTabStop="False"
|
||||
ItemTemplate="{StaticResource RemappedKeyTemplate}"
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys()}">
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys(50)}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4" />
|
||||
@@ -124,7 +130,7 @@
|
||||
x:Uid="KeyboardManager_RemapShortcutsButton"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{Binding Path=EditShortcutCommand}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsClickEnabled="True" />
|
||||
|
||||
<ListView
|
||||
@@ -136,47 +142,79 @@
|
||||
Visibility="{x:Bind Path=ViewModel.RemapShortcuts, Mode=OneWay, Converter={StaticResource CollectionVisibilityConverter}}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="Lib:AppSpecificKeysDataModel">
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ItemsControl
|
||||
IsTabStop="False"
|
||||
ItemTemplate="{StaticResource OriginalKeyTemplate}"
|
||||
ItemsSource="{x:Bind GetMappedOriginalKeys()}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
<controls:IsEnabledTextBlock
|
||||
x:Uid="To"
|
||||
Margin="8,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SecondaryIsEnabledTextBlockStyle}" />
|
||||
|
||||
<ItemsControl
|
||||
Name="KeyboardManager_RemappedTo"
|
||||
x:Uid="KeyboardManager_RemappedTo"
|
||||
IsTabStop="False"
|
||||
ItemTemplate="{StaticResource RemappedKeyTemplate}"
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys()}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
<Border
|
||||
Margin="16,0,0,0"
|
||||
Padding="12,4,12,6"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="12">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Opacity="0.3" Color="{ThemeResource SystemAccentColor}" />
|
||||
</Border.Background>
|
||||
<TextBlock Text="{x:Bind TargetApp}" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard.Description>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ItemsControl
|
||||
IsTabStop="False"
|
||||
ItemTemplate="{StaticResource OriginalKeyTemplate}"
|
||||
ItemsSource="{x:Bind GetMappedOriginalKeysWithoutChord()}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
<TextBlock
|
||||
Padding="6,0,6,6"
|
||||
VerticalAlignment="Bottom"
|
||||
Text=","
|
||||
Visibility="{x:Bind Path=HasChord, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
|
||||
<ItemsControl
|
||||
IsTabStop="False"
|
||||
ItemTemplate="{StaticResource OriginalKeyTemplate}"
|
||||
ItemsSource="{x:Bind GetMappedOriginalKeysOnlyChord()}"
|
||||
Visibility="{x:Bind Path=HasChord, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
<controls:IsEnabledTextBlock
|
||||
x:Uid="To"
|
||||
Margin="8,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SecondaryIsEnabledTextBlockStyle}"
|
||||
Visibility="{x:Bind Path=IsOpenUriOrIsRunProgram, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
|
||||
|
||||
<controls:IsEnabledTextBlock
|
||||
x:Uid="Starts"
|
||||
Margin="8,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SecondaryIsEnabledTextBlockStyle}"
|
||||
Visibility="{x:Bind Path=IsOpenUriOrIsRunProgram, Mode=OneWay}" />
|
||||
|
||||
|
||||
<ItemsControl
|
||||
Name="KeyboardManager_RemappedTo"
|
||||
x:Uid="KeyboardManager_RemappedTo"
|
||||
IsTabStop="False"
|
||||
ItemTemplate="{StaticResource RemappedKeyTemplate}"
|
||||
ItemsSource="{x:Bind GetMappedNewRemapKeys(50)}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
<Border
|
||||
Margin="16,0,0,0"
|
||||
Padding="12,4,12,6"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="12">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Opacity="0.3" Color="{ThemeResource SystemAccentColor}" />
|
||||
</Border.Background>
|
||||
<TextBlock Text="{x:Bind TargetApp}" />
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
</tkcontrols:SettingsCard>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
|
||||
@@ -2367,6 +2367,10 @@ From there, simply click on one of the supported files in the File Explorer and
|
||||
<value>to</value>
|
||||
<comment>as in: from x to y</comment>
|
||||
</data>
|
||||
<data name="Starts.Text" xml:space="preserve">
|
||||
<value>starts</value>
|
||||
<comment>as in: doing x will start y</comment>
|
||||
</data>
|
||||
<data name="LearnMore_Awake.Text" xml:space="preserve">
|
||||
<value>Learn more about Awake</value>
|
||||
<comment>Awake is a product name, do not loc</comment>
|
||||
|
||||
@@ -190,11 +190,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
else if (appSpecificShortcutList == null)
|
||||
{
|
||||
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, NewRemapString = x.NewRemapString, TargetApp = allAppsDescription }).ToList();
|
||||
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, NewRemapString = x.NewRemapString, RunProgramFilePath = x.RunProgramFilePath, OperationType = x.OperationType, OpenUri = x.OpenUri, SecondKeyOfChord = x.SecondKeyOfChord, RunProgramArgs = x.RunProgramArgs, TargetApp = allAppsDescription }).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, NewRemapString = x.NewRemapString, TargetApp = allAppsDescription }).Concat(appSpecificShortcutList).ToList();
|
||||
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, NewRemapString = x.NewRemapString, RunProgramFilePath = x.RunProgramFilePath, OperationType = x.OperationType, OpenUri = x.OpenUri, SecondKeyOfChord = x.SecondKeyOfChord, RunProgramArgs = x.RunProgramArgs, TargetApp = allAppsDescription }).Concat(appSpecificShortcutList).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user