Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Application wide capture of key up/down events

Tags:

c#

key

events

wpf

I'm trying to capture keypress events anywhere in my WPF application, regardless of which UI element has the focus. Currently I'm having no luck. Can anyone suggest some strategies that I might not have tried? Or, ideally, provide an answer like "oh that's easy, you just do this".

It's a distributed application, which has a chat system. The effect that I'm looking for is that the user can start typing a chat message at any time, without switching to a standard chat box. I'll display their message in the application myself, using FormattedText objects. This is important because it means there are no text input elements in the application anywhere.

My XAML structure looks roughly like:

<MainWindow>
  <Canvas 1>
    <Canvas 2>
      <Image 1 />
    </Canvas 2>
    <Image 2 />
  </Canvas 1>
</MainWindow>

I programmatically add elements into Canvas 2, and manipulate Image 2, which is why it has that structure.

I've tried adding KeyDown, KeyUp and the Preview events to MainWindow and Canvas 1, but none of them seem to fire (I check with breakpoints). I've also, after reading another related question here, tried manually setting the focus on the main window in the Loaded() method.

I realise there are many related questions on this site, but they haven't helped me because:

  • there aren't any answers (will my question be answered?)
  • they assume a text entry widget and are interested in bubbling up events
  • they want a keybinding for a small number of keys - I would like to capture any key
  • they are interested in detecting if a control/shift/alt key is down after they've already captured the event

Thank you for taking the time to read my long winded post, and thank you for suggestions.

Update (After Rachel's comment) When I put in a TextBox and set the focus to the TextBox, a key event method at the MainWindow level will fire. So that works as advertised.

However, I would really like to not have an explicit text entry widget in the application at all. I would like the user to be able to just start typing to compose a message.

like image 785
cursa Avatar asked Dec 03 '10 17:12

cursa


2 Answers

A little bit of tinkering got me this:

XAML:

<Window x:Class="KeyInput.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="100" Width="225">
    <Canvas>
        <Grid>
            <Label Name="test" Content="Empty" />
        </Grid>
    </Canvas>
</Window>

CS:

using System.Windows;
using System.Windows.Input;

namespace KeyInput
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.KeyDown += new KeyEventHandler(OnButtonKeyDown);
        }

        private void OnButtonKeyDown(object sender, KeyEventArgs e)
        {
            test.Content = test.Content + e.Key.ToString();
        }
    }
}

This prints out stuff like "Shift" So you'd obviously have to use switches... but it has a Text Box that collects key presses.

like image 155
WernerCD Avatar answered Nov 13 '22 10:11

WernerCD


I managed to work it out, inspired by answers from Rachel and WernerCD. As they both demonstrated, having the event capture at the MainWindow level does work. The problem was that I neglected to mention that I had a dialog before the MainWindow loaded, which seems to interfere with normal keyboard focus on the MainWindow. Putting explicit Keyboard.focus() in the Loaded() method is too soon. I fixed the problem by putting Keyboard.focus() in the MainWindow_ContentRendered() method.

All is now well (until the next issue anyway). Thank you for the help.

like image 35
cursa Avatar answered Nov 13 '22 09:11

cursa