PowerToysRunのようなアプリを作る
解決したいこと
C# + WPF + .NET 6.0 で PowerToys Runのようなアプリを作っています。
↓PowerToys Run
やりたいことがいくつかあるのですが、調べてもよく分からなかったので教えてください。
やりたいこと 1
やりたいこと 2
システムのデフォルトで自動的にライトテーマダークテーマを切り替える
やりたいこと 3
バックグラウンドアプリとして動作させたい
具体的には、ショートカットキーが押されたら画面を表示する。
ウィンドウからフォーカスが外れたら画面を消す
該当するソースコード
ちょっとコードが多すぎるのでGitHubのリポジトリも貼っておきます。
リポジトリ
using System;
using System.Collections.Generic;
using System.Linq;
using System.Media;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interop;
using HotKeySample;
namespace programmer_calculator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private HotKeyHelper _hotkey;
public MainWindow()
{
InitializeComponent();
this.MouseLeftButtonDown += (sender, e) => { this.DragMove(); };
this._hotkey = new HotKeyHelper(this);
this._hotkey.Register(ModifierKeys.Windows, Key.C, (_, __) => { SystemSounds.Beep.Play(); });
formulaTextBox.Focus();
}
public void EscClose(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
SystemSounds.Beep.Play();
Close();
}
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
// HotKeyの登録解除
this._hotkey.Dispose();
}
}
}
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:programmer_calculator"
x:Name="inputWindow" x:Class="programmer_calculator.MainWindow"
mc:Ignorable="d"
Title="MainWindow"
Height="66"
Width="670"
WindowStyle="None"
ResizeMode="NoResize"
Background="#00ffffff"
AllowsTransparency="True"
KeyDown="EscClose" Icon="/quikcalc.png" WindowStartupLocation="CenterScreen" ShowInTaskbar="False">
<Grid>
<Border Background="#d9000000" CornerRadius="10" BorderThickness="1"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Center" Width="600" Height="46" Margin="10,0,0,0" Background="#00ffffff" BorderBrush="{x:Null}" Foreground="White" FontSize="36" FontFamily="Meiryo UI" CaretBrush="White" Name="formulaTextBox"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
namespace HotKeySample
{
public class HotKeyItem
{
public ModifierKeys ModifierKeys { get; private set; }
public Key Key { get; private set; }
public EventHandler Handler { get; private set; }
public HotKeyItem(ModifierKeys modKey, Key key, EventHandler handler)
{
this.ModifierKeys = modKey;
this.Key = key;
this.Handler = handler;
}
}
/// <summary>
/// HotKey登録を管理するヘルパークラス
/// </summary>
public class HotKeyHelper : IDisposable
{
private IntPtr _windowHandle;
private Dictionary<int, HotKeyItem> _hotkeyList = new Dictionary<int, HotKeyItem>();
private const int WM_HOTKEY = 0x0312;
[DllImport("user32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int modKey, int vKey);
[DllImport("user32.dll")]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
public HotKeyHelper(Window window)
{
var host = new WindowInteropHelper(window);
this._windowHandle = host.Handle;
ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage;
}
private void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled)
{
if (msg.message != WM_HOTKEY) { return; }
var id = msg.wParam.ToInt32();
var hotkey = this._hotkeyList[id];
hotkey?.Handler
?.Invoke(this, EventArgs.Empty);
}
private int _hotkeyID = 0x0000;
private const int MAX_HOTKEY_ID = 0xC000;
/// <summary>
/// 引数で指定された内容で、HotKeyを登録します。
/// </summary>
/// <param name="modKey"></param>
/// <param name="key"></param>
/// <param name="handler"></param>
/// <returns></returns>
public bool Register(ModifierKeys modKey, Key key, EventHandler handler)
{
var modKeyNum = (int)modKey;
var vKey = KeyInterop.VirtualKeyFromKey(key);
// HotKey登録
while (this._hotkeyID < MAX_HOTKEY_ID)
{
var ret = RegisterHotKey(this._windowHandle, this._hotkeyID, modKeyNum, vKey);
if (ret != 0)
{
// HotKeyのリストに追加
var hotkey = new HotKeyItem(modKey, key, handler);
this._hotkeyList.Add(this._hotkeyID, hotkey);
this._hotkeyID++;
return true;
}
this._hotkeyID++;
}
return false;
}
/// <summary>
/// 引数で指定されたidのHotKeyを登録解除します。
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool Unregister(int id)
{
var ret = UnregisterHotKey(this._windowHandle, id);
return ret == 0;
}
/// <summary>
/// 引数で指定されたmodKeyとkeyの組み合わせからなるHotKeyを登録解除します。
/// </summary>
/// <param name="modKey"></param>
/// <param name="key"></param>
/// <returns></returns>
public bool Unregister(ModifierKeys modKey, Key key)
{
var item = this._hotkeyList
.FirstOrDefault(o => o.Value.ModifierKeys == modKey && o.Value.Key == key);
var isFound = !item.Equals(default(KeyValuePair<int, HotKeyItem>));
if (isFound)
{
var ret = Unregister(item.Key);
if (ret)
{
this._hotkeyList.Remove(item.Key);
}
return ret;
}
else
{
return false;
}
}
/// <summary>
/// 登録済みのすべてのHotKeyを解除します。
/// </summary>
/// <returns></returns>
public bool UnregisterAll()
{
var result = true;
foreach (var item in this._hotkeyList)
{
result &= this.Unregister(item.Key);
}
return result;
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// マネージリソースの破棄
}
// アンマネージリソースの破棄
this.UnregisterAll();
disposedValue = true;
}
}
~HotKeyHelper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}
自分で試したこと
StartupUri="MainWindow.xaml"を消してみた。
ホットキーの組み合わせをいろいろ試した
あまりにも分からなさすぎて変な文になっていますが、回答お願いします。