¿Cómo puedo registrar un activo global clave para decir CTRL+MAYÚS+(CARTA), utilizando WPF y .NET 3.5?

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

Pregunta

Estoy creando una aplicación en C# usando WPF.¿Cómo puedo enlazar a algunas teclas?

También, ¿cómo puedo enlazar con el Tecla de Windows?

¿Fue útil?

Solución

No estoy seguro de lo que quieres decir por "mundial" por aquí, pero aquí va (supongo que te refieres a un comando en el nivel de aplicación, por ejemplo, Guardar Todos Los que puede ser activado desde cualquier lugar Ctrl + Cambio + S.)

Encontrar el mundial UIElement de su elección, por ejemplo, la ventana de nivel superior que es el padre de todos los controles, donde se necesita este enlace.Debido a las "burbujas" de WPF eventos, eventos en el niño de los elementos de la burbuja todo el camino hasta la raíz del árbol de control.

Ahora, en primer lugar usted necesita

  1. para enlazar la Clave-Combinado con un Comando con un InputBinding como este
  2. usted puede, a continuación, transmisión en circuito del comando en el controlador (por ejemplo,el código al que se llama por SaveAll) a través de un CommandBinding.

Para el Windows Clave, utilizar el derecho de Clave enumerados miembro, Key.LWin o 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.
    }

Otros consejos

Esta es una solución completa de trabajo, espero que ayude...

Uso:

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

...

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

Clase:

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
    }

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

Si vas a mezclar Win32 y WPF, aquí es como yo lo hice:

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());
        }
    }
}

Usted puede conseguir el virtual-código de tecla para la tecla de acceso directo que desea registrar aquí: http://msdn.microsoft.com/en-us/library/ms927178.aspx

Puede haber una mejor manera, pero esto es lo que he conseguido hasta ahora.

Saludos!

Registrar el nivel de SO accesos directos es casi nunca una buena cosa:los usuarios no quieren que se metan con su sistema operativo.

Dicho esto, hay una forma mucho más simple y fácil manera de hacer esto en WPF, si estás bien con la tecla de trabajo dentro de la aplicación sólo (me.e tan largo como su aplicación WPF tiene el foco):

En La Aplicación.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
}

Es así de simple

Esto es similar a las respuestas ya dadas, pero me parece un poco más claro:

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.
        }
    }
}

Lo he encontrado en fluxbytes.com.

Aunque RegisterHotKey a veces es precisamente lo que usted desea, en la mayoría de los casos, usted probablemente no desea utilizar todo el sistema de teclas de acceso rápido.Terminé usando un código como el siguiente:

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");
            }
        }
    }
}

No estoy seguro acerca de WPF, pero esto puede ayudar.He utilizado la solución que se describe en RegisterHotKey (user32) (modificado a mis necesidades, por supuesto) para un Windows Forms en C# aplicación para asignar una combinación de teclas CTRL-combinación de teclas en Windows para que aparezca un formato de C#, y funcionó muy bien (incluso en Windows Vista).Espero te sirva de ayuda y buena suerte!

He encontrado la Global de Teclas de acceso rápido en WPF proyecto en codeproject.com que hace todo el trabajo para mí.Es relativamente reciente, no necesita una referencia para el Sistema.Windows.Formas y trabaja "a nivel mundial" en términos de reaccionar a la tecla se presionó incluso si "su" aplicación no es la ventana activa.

RegisterHotKey() sugerido por John podría funcionar - el único inconveniente es que requiere de un HWND (utilizando PresentationSource.FromVisual(), y emitir el resultado de un HwndSource).

Sin embargo, usted también tendrá que responder a la WM_HOTKEY mensaje - no estoy seguro de si hay una manera de obtener acceso a la WndProc de una ventana WPF o no (lo cual se puede hacer de Formas de Windows de windows).

Mandril de la solución funciona mejor porque usted puede tener múltiples ventanas.Hice ajustarlo para que se utiliza el PreviewKeyDownEvent en lugar de la PreviewKeyUpEvent con el fin de controlar la repetición de teclas.

Yo aconsejo que OS a nivel de registro a menos que usted está escribiendo algo como una herramienta que corta con tijeras o una grabación de audio de la aplicación ya que te permitirá tener acceso a las funciones cuando la ventana no está centrado.

Un co-trabajador escribió un ejemplo de cómo crear un teclado de bajo nivel de gancho para ser utilizado con WPF.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top