PowerToys/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/KeyboardManagerViewModel.cs

205 lines
7.4 KiB
C#
Raw Normal View History

2020-08-18 01:00:56 +08:00
// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.PowerToys.Settings.UI.Lib.Helpers;
2020-08-18 01:00:56 +08:00
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
using Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands;
2020-08-18 01:00:56 +08:00
namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels
2020-08-18 01:00:56 +08:00
{
public class KeyboardManagerViewModel : Observable
{
private readonly ISettingsUtils _settingsUtils;
2020-08-18 01:00:56 +08:00
private const string PowerToyName = "Keyboard Manager";
private const string RemapKeyboardActionName = "RemapKeyboard";
private const string RemapKeyboardActionValue = "Open Remap Keyboard Window";
private const string EditShortcutActionName = "EditShortcut";
private const string EditShortcutActionValue = "Open Edit Shortcut Window";
private const string JsonFileType = ".json";
private const string ProfileFileMutexName = "PowerToys.KeyboardManager.ConfigMutex";
private const int ProfileFileMutexWaitTimeoutMilliseconds = 1000;
public KeyboardManagerSettings Settings { get; set; }
2020-08-18 01:00:56 +08:00
private ICommand _remapKeyboardCommand;
private ICommand _editShortcutCommand;
private KeyboardManagerProfile _profile;
private GeneralSettings _generalSettings;
2020-08-18 01:00:56 +08:00
private Func<string, int> SendConfigMSG { get; }
private Func<List<KeysDataModel>, int> FilterRemapKeysList { get; }
public KeyboardManagerViewModel(ISettingsUtils settingsUtils, Func<string, int> ipcMSGCallBackFunc, Func<List<KeysDataModel>, int> filterRemapKeysList)
2020-08-18 01:00:56 +08:00
{
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
FilterRemapKeysList = filterRemapKeysList;
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
if (_settingsUtils.SettingsExists(PowerToyName))
2020-08-18 01:00:56 +08:00
{
// Todo: Be more resilient while reading and saving settings.
Settings = _settingsUtils.GetSettings<KeyboardManagerSettings>(PowerToyName);
2020-08-18 01:00:56 +08:00
// Load profile.
if (!LoadProfile())
{
_profile = new KeyboardManagerProfile();
2020-08-18 01:00:56 +08:00
}
}
else
{
Settings = new KeyboardManagerSettings(PowerToyName);
_settingsUtils.SaveSettings(Settings.ToJsonString(), PowerToyName);
2020-08-18 01:00:56 +08:00
}
if (_settingsUtils.SettingsExists())
2020-08-18 01:00:56 +08:00
{
_generalSettings = _settingsUtils.GetSettings<GeneralSettings>(string.Empty);
2020-08-18 01:00:56 +08:00
}
else
{
_generalSettings = new GeneralSettings();
_settingsUtils.SaveSettings(_generalSettings.ToJsonString(), string.Empty);
2020-08-18 01:00:56 +08:00
}
}
public bool Enabled
{
get
{
return _generalSettings.Enabled.KeyboardManager;
2020-08-18 01:00:56 +08:00
}
set
{
if (_generalSettings.Enabled.KeyboardManager != value)
2020-08-18 01:00:56 +08:00
{
_generalSettings.Enabled.KeyboardManager = value;
2020-08-18 01:00:56 +08:00
OnPropertyChanged(nameof(Enabled));
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(_generalSettings);
2020-08-18 01:00:56 +08:00
SendConfigMSG(outgoing.ToString());
2020-08-18 01:00:56 +08:00
}
}
}
// store remappings
public List<KeysDataModel> RemapKeys
{
get
{
if (_profile != null)
2020-08-18 01:00:56 +08:00
{
return _profile.RemapKeys.InProcessRemapKeys;
2020-08-18 01:00:56 +08:00
}
else
{
return new List<KeysDataModel>();
}
}
}
public static List<AppSpecificKeysDataModel> CombineShortcutLists(List<KeysDataModel> globalShortcutList, List<AppSpecificKeysDataModel> appSpecificShortcutList)
{
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, TargetApp = "All Apps" }).Concat(appSpecificShortcutList).ToList();
}
public List<AppSpecificKeysDataModel> RemapShortcuts
{
get
{
if (_profile != null)
2020-08-18 01:00:56 +08:00
{
return CombineShortcutLists(_profile.RemapShortcuts.GlobalRemapShortcuts, _profile.RemapShortcuts.AppSpecificRemapShortcuts);
2020-08-18 01:00:56 +08:00
}
else
{
return new List<AppSpecificKeysDataModel>();
}
}
}
public ICommand RemapKeyboardCommand => _remapKeyboardCommand ?? (_remapKeyboardCommand = new RelayCommand(OnRemapKeyboard));
2020-08-18 01:00:56 +08:00
public ICommand EditShortcutCommand => _editShortcutCommand ?? (_editShortcutCommand = new RelayCommand(OnEditShortcut));
2020-08-18 01:00:56 +08:00
private async void OnRemapKeyboard()
{
await Task.Run(() => OnRemapKeyboardBackground());
}
private async void OnEditShortcut()
{
await Task.Run(() => OnEditShortcutBackground());
}
private async Task OnRemapKeyboardBackground()
{
Helper.AllowRunnerToForeground();
SendConfigMSG(Helper.GetSerializedCustomAction(PowerToyName, RemapKeyboardActionName, RemapKeyboardActionValue));
2020-08-18 01:00:56 +08:00
await Task.CompletedTask;
}
private async Task OnEditShortcutBackground()
{
Helper.AllowRunnerToForeground();
SendConfigMSG(Helper.GetSerializedCustomAction(PowerToyName, EditShortcutActionName, EditShortcutActionValue));
2020-08-18 01:00:56 +08:00
await Task.CompletedTask;
}
public void NotifyFileChanged()
2020-08-18 01:00:56 +08:00
{
OnPropertyChanged(nameof(RemapKeys));
OnPropertyChanged(nameof(RemapShortcuts));
2020-08-18 01:00:56 +08:00
}
public bool LoadProfile()
2020-08-18 01:00:56 +08:00
{
var success = true;
try
{
using (var profileFileMutex = Mutex.OpenExisting(ProfileFileMutexName))
{
if (profileFileMutex.WaitOne(ProfileFileMutexWaitTimeoutMilliseconds))
{
// update the UI element here.
try
{
_profile = _settingsUtils.GetSettings<KeyboardManagerProfile>(PowerToyName, Settings.Properties.ActiveConfiguration.Value + JsonFileType);
FilterRemapKeysList(_profile.RemapKeys.InProcessRemapKeys);
2020-08-18 01:00:56 +08:00
}
finally
{
// Make sure to release the mutex.
profileFileMutex.ReleaseMutex();
}
}
else
{
success = false;
}
}
}
catch (Exception)
{
// Failed to load the configuration.
success = false;
}
return success;
}
}
}