WPF 및 .NET 3.5를 사용하여 CTRL+SHIFT+(LETTER)를 말하는 전역 단축키를 등록하려면 어떻게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/48935

문제

WPF를 사용하여 C#으로 애플리케이션을 구축하고 있습니다.일부 키를 어떻게 바인딩할 수 있나요?

또한, 어떻게 바인딩할 수 있습니까? 윈도우 키?

도움이 되었습니까?

해결책

여기서 "전역"이 무엇을 의미하는지 잘 모르겠지만 여기서는 그렇습니다(예를 들어 애플리케이션 수준의 명령을 의미한다고 가정합니다. 모두 저장 어디서든 촉발될 수 있는 Ctrl 키 + 옮기다 + 에스.)

당신은 글로벌을 찾아 UIElement 예를 들어 이 바인딩이 필요한 모든 컨트롤의 상위인 최상위 창을 선택할 수 있습니다.WPF 이벤트의 "버블링"으로 인해 하위 요소의 이벤트는 컨트롤 트리의 루트까지 버블링됩니다.

이제 먼저 필요한 것은

  1. 키-콤보를 명령과 결합하려면 InputBinding 이와 같이
  2. 그런 다음 명령을 핸들러에 연결할 수 있습니다(예:호출되는 코드 SaveAll)를 통해 CommandBinding.

에 대한 윈도우 열쇠, 당신은 권리를 사용합니다 열쇠 열거된 회원, Key.LWin 또는 Key.RWin

    public WindowMain()
    {
       InitializeComponent();
       // Bind Key
       InputBinding ib = new InputBinding(
           MyAppCommands.SaveAll,
           new KeyGesture(Key.S, ModifierKeys.Shift | ModifierKeys.Control));
       this.InputBindings.Add(ib);
       // Bind handler
       CommandBinding cb = new CommandBinding( MyAppCommands.SaveAll);
       cb.Executed += new ExecutedRoutedEventHandler( HandlerThatSavesEverthing );
       this.CommandBindings.Add (cb );
    }

    private void HandlerThatSavesEverthing (object obSender, ExecutedRoutedEventArgs e)
    {
      // Do the Save All thing here.
    }

다른 팁

이것은 완벽하게 작동하는 솔루션입니다. 도움이 되기를 바랍니다...

용법:

_hotKey = new HotKey(Key.F9, KeyModifier.Shift | KeyModifier.Win, OnHotKeyHandler);

...

private void OnHotKeyHandler(HotKey hotKey)
{
    SystemHelper.SetScreenSaverRunning();
}

수업:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Mime;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;

namespace UnManaged
{
    public class HotKey : IDisposable
    {
        private static Dictionary<int, HotKey> _dictHotKeyToCalBackProc;

        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, UInt32 fsModifiers, UInt32 vlc);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        public const int WmHotKey = 0x0312;

        private bool _disposed = false;

        public Key Key { get; private set; }
        public KeyModifier KeyModifiers { get; private set; }
        public Action<HotKey> Action { get; private set; }
        public int Id { get; set; }

        // ******************************************************************
        public HotKey(Key k, KeyModifier keyModifiers, Action<HotKey> action, bool register = true)
        {
            Key = k;
            KeyModifiers = keyModifiers;
            Action = action;
            if (register)
            {
                Register();
            }
        }

        // ******************************************************************
        public bool Register()
        {
            int virtualKeyCode = KeyInterop.VirtualKeyFromKey(Key);
            Id = virtualKeyCode + ((int)KeyModifiers * 0x10000);
            bool result = RegisterHotKey(IntPtr.Zero, Id, (UInt32)KeyModifiers, (UInt32)virtualKeyCode);

            if (_dictHotKeyToCalBackProc == null)
            {
                _dictHotKeyToCalBackProc = new Dictionary<int, HotKey>();
                ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage);
            }

            _dictHotKeyToCalBackProc.Add(Id, this);

            Debug.Print(result.ToString() + ", " + Id + ", " + virtualKeyCode);
            return result;
        }

        // ******************************************************************
        public void Unregister()
        {
            HotKey hotKey;
            if (_dictHotKeyToCalBackProc.TryGetValue(Id, out hotKey))
            {
                UnregisterHotKey(IntPtr.Zero, Id);
            }
        }

        // ******************************************************************
        private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled)
        {
            if (!handled)
            {
                if (msg.message == WmHotKey)
                {
                    HotKey hotKey;

                    if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey))
                    {
                        if (hotKey.Action != null)
                        {
                            hotKey.Action.Invoke(hotKey);
                        }
                        handled = true;
                    }
                }
            }
        }

        // ******************************************************************
        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // ******************************************************************
        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be _disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be _disposed.
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this._disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    Unregister();
                }

                // Note disposing has been done.
                _disposed = true;
            }
        }
    }

    // ******************************************************************
    [Flags]
    public enum KeyModifier
    {
        None = 0x0000,
        Alt = 0x0001,
        Ctrl = 0x0002,
        NoRepeat = 0x4000,
        Shift = 0x0004,
        Win = 0x0008
    }

    // ******************************************************************
}

Win32와 WPF를 혼합하려는 경우 제가 수행한 방법은 다음과 같습니다.

using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media;
using System.Threading;
using System.Windows;
using System.Windows.Input;

namespace GlobalKeyboardHook
{
    public class KeyboardHandler : IDisposable
    {

        public const int WM_HOTKEY = 0x0312;
        public const int VIRTUALKEYCODE_FOR_CAPS_LOCK = 0x14;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        private readonly Window _mainWindow;
        WindowInteropHelper _host;

        public KeyboardHandler(Window mainWindow)
        {
            _mainWindow = mainWindow;
            _host = new WindowInteropHelper(_mainWindow);

            SetupHotKey(_host.Handle);
            ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage;
        }

        void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled)
        {
            if (msg.message == WM_HOTKEY)
            {
                //Handle hot key kere
            }
        }

        private void SetupHotKey(IntPtr handle)
        {
            RegisterHotKey(handle, GetType().GetHashCode(), 0, VIRTUALKEYCODE_FOR_CAPS_LOCK);
        }

        public void Dispose()
        {
            UnregisterHotKey(_host.Handle, GetType().GetHashCode());
        }
    }
}

여기에서 등록하려는 단축키에 대한 가상 키 코드를 얻을 수 있습니다. http://msdn.microsoft.com/en-us/library/ms927178.aspx

더 좋은 방법이 있을 수 있지만 이것이 제가 지금까지 얻은 것입니다.

건배!

OS 수준 단축키를 등록하는 것은 결코 좋은 일이 아닙니다.사용자는 자신의 OS를 엉망으로 만드는 것을 원하지 않습니다.

즉, 애플리케이션 내에서만 단축키가 작동하는 데 동의한다면(예: WPF 앱에 포커스가 있는 경우) WPF에서 이 작업을 수행하는 훨씬 더 간단하고 사용자 친화적인 방법이 있습니다.

App.xaml.cs에서:

protected override void OnStartup(StartupEventArgs e)
{
   EventManager.RegisterClassHandler(typeof(Window), Window.PreviewKeyUpEvent, new KeyEventHandler(OnWindowKeyUp));
}

private void OnWindowKeyUp(object source, KeyEventArgs e))
{
   //Do whatever you like with e.Key and Keyboard.Modifiers
}

그렇게 간단해요

이것은 이미 제공된 답변과 유사하지만 조금 더 깨끗하다고 ​​생각합니다.

using System;
using System.Windows.Forms;

namespace GlobalHotkeyExampleForm
{
    public partial class ExampleForm : Form
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        enum KeyModifier
        {
            None = 0,
            Alt = 1,
            Control = 2,
            Shift = 4,
            WinKey = 8
        }

        public ExampleForm()
        {
            InitializeComponent();

            int id = 0;     // The id of the hotkey. 
            RegisterHotKey(this.Handle, id, (int)KeyModifier.Shift, Keys.A.GetHashCode());       // Register Shift + A as global hotkey. 
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == 0x0312)
            {
                /* Note that the three lines below are not needed if you only want to register one hotkey.
                 * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */

                Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);                  // The key of the hotkey that was pressed.
                KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);       // The modifier of the hotkey that was pressed.
                int id = m.WParam.ToInt32();                                        // The id of the hotkey that was pressed.


                MessageBox.Show("Hotkey has been pressed!");
                // do something
            }
        }

        private void ExampleForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnregisterHotKey(this.Handle, 0);       // Unregister hotkey with id 0 before closing the form. You might want to call this more than once with different id values if you are planning to register more than one hotkey.
        }
    }
}

나는 그것을 찾았습니다 fluxbytes.com.

RegisterHotKey가 때로는 정확하게 원하는 것일 수도 있지만 대부분의 경우 시스템 전체 단축키를 사용하고 싶지 않을 것입니다.결국 다음과 같은 코드를 사용하게 되었습니다.

using System.Windows;
using System.Windows.Interop;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        const int WM_KEYUP = 0x0101;

        const int VK_RETURN = 0x0D;
        const int VK_LEFT = 0x25;  

        public MainWindow()
        {
            this.InitializeComponent();

            ComponentDispatcher.ThreadPreprocessMessage += 
                ComponentDispatcher_ThreadPreprocessMessage;
        }

        void ComponentDispatcher_ThreadPreprocessMessage(
            ref MSG msg, ref bool handled)
        {
            if (msg.message == WM_KEYUP)
            {
                if ((int)msg.wParam == VK_RETURN)
                    MessageBox.Show("RETURN was pressed");

                if ((int)msg.wParam == VK_LEFT)
                    MessageBox.Show("LEFT was pressed");
            }
        }
    }
}

WPF에 대해 잘 모르겠지만 이것이 도움이 될 수 있습니다.나는 다음에 설명된 솔루션을 사용했습니다. HotKey 등록(user32) (물론 내 필요에 따라 수정됨) C# Windows Forms 응용 프로그램이 Windows 내에서 CTRL-KEY 조합을 할당하여 C# 양식을 불러오면 Windows Vista에서도 훌륭하게 작동했습니다.도움이 되기를 바라며 행운을 빕니다!

나는 찾았다 WPF의 전역 단축키 나를 위해 일을 하는 codeproject.com의 프로젝트입니다.비교적 최신이며 System.Windows.Forms에 대한 참조가 필요하지 않으며 "귀하의" 응용 프로그램이 활성 창이 아닌 경우에도 누르는 단축키에 반응한다는 점에서 "전역적으로" 작동합니다.

RegisterHotKey() John이 제안한 작업은 작동할 수 있습니다. 유일한 문제점은 HWND가 필요하다는 것입니다(다음을 사용하여). PresentationSource.FromVisual(), 결과를 HwndSource로 캐스팅).

그러나 다음 사항에도 응답해야 합니다. WM_HOTKEY 메시지 - WPF 창의 WndProc에 액세스할 수 있는 방법이 있는지 여부(Windows Forms 창에서 수행할 수 있음)가 확실하지 않습니다.

Baboon의 솔루션은 여러 개의 창이 있을 수 있기 때문에 가장 잘 작동합니다.키 입력의 반복을 처리하기 위해 PreviewKeyUpEvent 대신 PreviewKeyDownEvent를 사용하도록 조정했습니다.

캡처 도구나 오디오 녹음 앱과 같은 프로그램을 작성하지 않는 한 OS 수준 등록을 권장하지 않습니다. 창에 포커스가 없을 때 기능에 액세스할 수 있기 때문입니다.

동료가 WPF와 함께 사용할 낮은 수준의 키보드 후크를 만드는 방법에 대한 샘플을 작성했습니다.

http://blogs.vertigo.com/personal/ralph/Blog/Lists/Posts/Post.aspx?ID=8

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top