* Added new command wrapper, abstracts static and dynamic commands - All uses of the `Command` are replaced with either `AppCommand`, for a command that is static to the scope of the application, or a reference to an ICommand (specifically, an `EnumCommand<AppCommand>()` instance), which provides the abstract wrapper. - Functionality seems intact. - Next step is to have the MainViewModel add the per-shell commands via SettingsService.CreateShellKeyboardShortcuts(), and have the SettingsService.ParseCommandString() function parse the command strings passed around properly. - Finally, add the keyboard chord input to each shell's settings page. * First kick at adding a new terminal keyboard command. - It isn't presented anywhere, but references to keybindings should be using the ICommand key as their identifier for recognizing anything, and when xterm passes back a keyboard command event, the SettingsService is asked to convert the string into an ICommand. * Renaming ICommand to Command. It's not longer an interface, so this makes more sense. * Renaming back to Command, and new class is AbstractCommand. Going to simplify the PR diff considerably. * Shortcuts for default shells work. Need to get the shell profile edit UI elements working. * Added keyboard shortcut UI elements to shell profile pages. * New and deleted shell profiles propagate to all terminal views. * A bit of cleanup. * Camel-casing command text to fix Ctrl+C and copy behaviour. * Fixed failing test. The new on disk store uses a .ToString(), not the Enum description, since the command isn't an Enum, it's a class now in general, and those semantics make more sense. * Adding default value for null keybindings in shell profiles. * Merge branch 'shell_commands' of https://github.com/Riebart/FluentTerminal into pr/85 Improved default value for keybinding property * Renamed KeyBinding collection to KeyBindings * Use strings as Command parameter of KeyBinding * Added missing Commands to keyBindings of default shellProfiles * fix build and unit tests after merge with master * improve UI * Split OnShellProfileCollectionChanged event
166 lines
5.3 KiB
C#
166 lines
5.3 KiB
C#
using FluentTerminal.App.Services;
|
|
using FluentTerminal.Models;
|
|
using FluentTerminal.Models.Enums;
|
|
using GlobalHotKey;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Input;
|
|
using System.Windows.Threading;
|
|
using Windows.ApplicationModel;
|
|
using Windows.ApplicationModel.Core;
|
|
|
|
namespace FluentTerminal.SystemTray.Services
|
|
{
|
|
public class ToggleWindowService : IDisposable
|
|
{
|
|
private const int SW_MINIMIZE = 6;
|
|
private readonly HotKeyManager _hotKeyManager;
|
|
private readonly INotificationService _notificationService;
|
|
private readonly Dispatcher _dispatcher;
|
|
private bool _disposedValue;
|
|
private readonly List<HotKey> _hotKeys;
|
|
|
|
public ToggleWindowService(Dispatcher dispatcher, HotKeyManager hotKeyManager, INotificationService notificationService, ISettingsService settingsService)
|
|
{
|
|
_dispatcher = dispatcher;
|
|
_notificationService = notificationService;
|
|
_hotKeyManager = hotKeyManager;
|
|
_hotKeys = new List<HotKey>();
|
|
_hotKeyManager.KeyPressed += OnKeyPressed;
|
|
|
|
var keyBindings = settingsService.GetCommandKeyBindings()[nameof(Command.ToggleWindow)];
|
|
SetHotKeys(keyBindings);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
}
|
|
|
|
public void SetHotKeys(IEnumerable<KeyBinding> keyBindings)
|
|
{
|
|
foreach (var hotKey in _hotKeys)
|
|
{
|
|
_dispatcher.Invoke(() =>
|
|
{
|
|
_hotKeyManager.Unregister(hotKey);
|
|
});
|
|
}
|
|
|
|
_hotKeys.Clear();
|
|
|
|
foreach (var keyBinding in keyBindings)
|
|
{
|
|
try
|
|
{
|
|
var key = Utilities.ExtendVirtualKeyToInputKey((ExtendedVirtualKey)keyBinding.Key);
|
|
var modifiers = ModifierKeys.None;
|
|
if (keyBinding.Alt)
|
|
{
|
|
modifiers |= ModifierKeys.Alt;
|
|
}
|
|
if (keyBinding.Ctrl)
|
|
{
|
|
modifiers |= ModifierKeys.Control;
|
|
}
|
|
if (keyBinding.Shift)
|
|
{
|
|
modifiers |= ModifierKeys.Shift;
|
|
}
|
|
if (keyBinding.Meta)
|
|
{
|
|
modifiers |= ModifierKeys.Windows;
|
|
}
|
|
|
|
var hotKey = new HotKey(key, modifiers);
|
|
|
|
_dispatcher.Invoke(() =>
|
|
{
|
|
_hotKeyManager.Register(hotKey);
|
|
});
|
|
|
|
_hotKeys.Add(hotKey);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
_notificationService.ShowNotification("Error", "Failed to register the following hotkey: " + GetKeyBindingRepresentation(keyBinding));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!_disposedValue)
|
|
{
|
|
if (disposing)
|
|
{
|
|
_hotKeyManager?.Dispose();
|
|
}
|
|
|
|
_disposedValue = true;
|
|
}
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern IntPtr GetForegroundWindow();
|
|
|
|
private static string GetKeyBindingRepresentation(KeyBinding keyBinding)
|
|
{
|
|
var keys = new List<string>();
|
|
if (keyBinding.Ctrl)
|
|
{
|
|
keys.Add("Ctrl");
|
|
}
|
|
if (keyBinding.Alt)
|
|
{
|
|
keys.Add("Alt");
|
|
}
|
|
if (keyBinding.Shift)
|
|
{
|
|
keys.Add("Shift");
|
|
}
|
|
|
|
keys.Add(((ExtendedVirtualKey)keyBinding.Key).ToString());
|
|
|
|
return string.Join(" + ", keys);
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
|
|
|
private string GetActiveProcessFileName()
|
|
{
|
|
try
|
|
{
|
|
var hwnd = GetForegroundWindow();
|
|
GetWindowThreadProcessId(hwnd, out uint pid);
|
|
var process = Process.GetProcessById((int)pid);
|
|
return process.MainWindowTitle;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private async void OnKeyPressed(object sender, KeyPressedEventArgs e)
|
|
{
|
|
if (GetActiveProcessFileName().EndsWith("Fluent Terminal"))
|
|
{
|
|
var hwnd = GetForegroundWindow();
|
|
ShowWindow(hwnd, SW_MINIMIZE);
|
|
}
|
|
else
|
|
{
|
|
IEnumerable<AppListEntry> appListEntries = await Package.Current.GetAppListEntriesAsync();
|
|
await appListEntries.First().LaunchAsync();
|
|
}
|
|
}
|
|
}
|
|
} |