How can I get a WPF desktop application to catch a Elgato Streamdeck command with text characters?

312 Views Asked by At

I have a WPF desktop application written with NET Core 3.1 and it catches keystrokes with KeyDown command. All characters are caught with the keyboard. When I use a Streamdeck and its System Text feature, which sends keys like a keyboard my WPF app doesn't catch it.

Tested on Notepad and the text sent from the Streamdeck works as it should, e.g. X 1 Enter.

When I debug the only thing that gets sent is Enter key.

private void MyApp_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.X)
    {
        //do something
    }
}

Everything works fine with a normal keyboard. Barcode Scanner works too. It's the Streamdeck that won't catch the text it sends.

Is there anything I need to set in my project to catch it?

StreamDeck Screenshot

1

There are 1 best solutions below

2
emoacht On BEST ANSWER

I myself am interested in Elgato Stream Deck a little and so tried Stream Deck Mobile app. I found when the app sends a text, a pair of WM_KEYDOWN and WM_KEYUP windows messages with VK_PACKET virtual-key code are sent for each letter. It suggests the app utilizes SendInput function to "send Unicode characters as if they were keystrokes".

Then, luckily I found UIElement.PreviewTextInput event can capture each letter. So, assuming the text ends with Enter key, we can retrieve the text sent by the app by aggregating the letters.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private readonly StringBuilder _buffer = new();

    protected override void OnPreviewTextInput(TextCompositionEventArgs e)
    {
        if (e.Text is ("\r\n" or "\r" or "\n")) // Key.Return produces a line break.
        {
            if (_buffer.Length > 0)
            {
                OnTextRecieved(_buffer.ToString());
                _buffer.Clear();
            }
        }
        else
        {
            _buffer.Append(e.Text);
        }
        base.OnPreviewTextInput(e);
    }

    protected virtual void OnTextRecieved(string text)
    {
        Debug.WriteLine($"TextRecieved {text}");
    }
}