creative-account
@creative-account

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

PowerToysRunのようなアプリを作る

解決したいこと

C# + WPF + .NET 6.0 で PowerToys Runのようなアプリを作っています。
↓PowerToys Run
image.png
やりたいことがいくつかあるのですが、調べてもよく分からなかったので教えてください。

やりたいこと 1

テキストボックスにフォーカスが当たったときの枠線を消したい
image.png

やりたいこと 2

システムのデフォルトで自動的にライトテーマダークテーマを切り替える

やりたいこと 3

バックグラウンドアプリとして動作させたい
具体的には、ショートカットキーが押されたら画面を表示する。
ウィンドウからフォーカスが外れたら画面を消す

該当するソースコード

ちょっとコードが多すぎるのでGitHubのリポジトリも貼っておきます。
リポジトリ

MainWindow.xaml.cs
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();
        }

    }
}

MainWindow.xaml
<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>

HotKeyHeloper.cs
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"を消してみた。
ホットキーの組み合わせをいろいろ試した

あまりにも分からなさすぎて変な文になっていますが、回答お願いします。

0

1Answer

this._windowHandle = host.Handle;

Control.BorderThickness

あたりでしょうか?

ウインドウ(画面のパーツ)のハンドルを取得し、そのウインドウのプロパティを変化させたりするだけです。

mouseover 等は自力で検索して下さい。

PowerToysをそのまま利用しては?
また、.NETから離れてWindows App SDKのみで開発しては?

2Like

Comments

  1. ありがとうございますぅぅぅーーー

    見事フォーカス時の枠線が消えました

    PowerToys流用はPT Runのコードがどこに有るか分からなかったので…
    Windows App SDKはあれですよね? WinUI 3が使えるやつ
    実はデザイナーを使ってGUIでやらないとUI作れないんですよ (XAMLかけない)

    image.png

  2. 解決おめでとうございます。

    PowerToysはGUI版powerShellですね!
    Windows App SDKで補えそうですが。

Your answer might help someone💌