views:

7568

answers:

7

Im building an app in c# using WPF and i need it to bind to some keys. Ive found some links but not work well with my setup. Anyone done this before?

also if i could bind to the windows key would be great.

+1  A: 

I'm not sure about WPF, but this may help...I used this solution (modified to my needs of course) for a c# Windows forms application to assign a CTRL-KEY combination within Windows to bring up a c# form and it worked beautifully (even on Windows Vista). Hope it helps and good luck!

http://www.pinvoke.net/default.aspx/user32/RegisterHotKey.html

John Virgolino
This doesn't work with WPF.
w-ll
A: 

RegisterHotKey() suggested by John could work - the only catch is that it requires an HWND (using PresentationSource.FromVisual(), and casting the result to an HwndSource), however you'll also need to respond to the WM_HOTKEY message - I'm not sure if there is a way to get access to the WndProc of a WPF window or not (which can be done for WinForms windows).

Andy
+1  A: 

You might take a look at Scott Hanselman's BabySmash series and the BabySmash source. I don't know anything about WPF, but some of the blog posts in the series I linked discussed key bindings and limitations in WPF.

Ben Robbins
+7  A: 

I'm not sure of what you mean by "global" here but here goes (I'm assuming you mean a command at the application level e.g. Save All that can be triggered from anywhere by Ctrl+Shift+S

You find the global UIElement of your choice e.g. the top level window which is the parent of all the controls where you need this binding. Due to "bubbling" of WPF events, events at child elements will bubble all the way up to the root of the control tree. Now first you need

  1. to bind the Key-Combo with a Command using an InputBinding like this
  2. you can then hookup the command to your handler (e.g. code that gets called by SaveAll) via a CommandBinding.

For the Windows Key, you use the right Key enumerated member, Key.LWin or 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
    }
Gishu
+2  A: 

A co-worker wrote a sample on how to create a low-level keyboard hook to be used WPF.

http://blogs.vertigo.com/personal/ralph/Blog/archive/2007/02/12/wpf-low-level-keyboard-hook-sample.aspx

Alan Le
+5  A: 

If you're going to mix Win32 and WPF, here's how I did it:

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

You can get the virtual-key code for the hotkey you want to register here: http://msdn.microsoft.com/en-us/library/ms927178.aspx

There may be a better way, but this is what I've got so far.

Cheers!

jgraves
I guess you produce a memory leak there...
Turing Complete
A: 
Mattias Wikström