Keycode output mismatch between Component::keyPressed() and KeyPress::isKeyCurrentlyDown()

I’ve ran into an issue of Component::keyPressed(const juce::KeyPress& key) not representing the button down states (keycodes and character codes) the same way as when querying them using KeyPress::isKeyCurrentlyDown(const int keyCode).

I’m calling isKeyCurrentlyDown() from Component::keyStateChanged(bool isKeyDown).

Here is what I get when pressing “q”, which gives the correct output which I expect to see:

    keycode: 81, character code: 113 == 'q'     ---> Output from keyPressed(const juce::KeyPress& key)

    keycode: 81    ---> Output from isKeyCurrentlyDown()
    keycode: 113    ---> Also output at the same time from the same isKeyCurrentlyDown()

So two different keycodes respond to being pressed down when I go through all of them.
In this case the outputs match between keyPressed() and isKeyCurrentlyDown().

Here is what I get when pressing “ü” which gives wrong output which needs to be fixed somehow:

    keycode: 252, character code: 252 == 'ü'   ---> Output from keyPressed(const juce::KeyPress& key)

    keycode: 58 ---> Output from isKeyCurrentlyDown()
    keycode: 59 ---> Also output at the same time from isKeyCurrentlyDown()
    keycode: 186 ---> Also output at the same time from isKeyCurrentlyDown()

So when I press “ü”, I get three keycodes telling me that they are held down. None of them match with what the keyPressed() says about being pressed down. keyPressed() seems to return the correct keycodes though.

So what is going on and how to fix this issue so that isKeyCurrentlyDown() also returns matching keycodes when I poll through the full keycode range with that method?

What I’m trying to do is to ensure my keyboard layout localization works properly. I’m using Windows/Finnish keyboard with German keyboard layout turned on in Windows to test that everything works as they should. I don’t know if this affects the results or not.

EDIT:
This seems to be happening also when I have my finnish scandic keyboard and windows is set for that keyboard layout. When pressing scandic letter keys, they are not recognized by isKeyCurrentlyDown() when called from keyStateChanged().

This what comes out of keyPressed() when I press “ä”:
keycode: 228, character code: 228 == ‘ä’

And this is what isKeyCurrentlyDown() reports to me:
keycode: 222

My personal diagnosis is that somehow JUCE doesn’t report scandic letters properly when using keyStateChanged() polling. Can anyone confirm this is the real issue? How to fix this so that both methods can be used to get keypresses regarding same scandic keys?

Attached to this post is minimal test software (.ZIP file) which demonstrates this issue (less than 80 lines of code).

Here’s output with some of the scandic letters, as you can see the outputs don’t match between keyStateChanged() and keyPressed():

keyStateChanged(): 93, 221, 
keyPressed(): 229, 229, L'å'

keyStateChanged(): 222, 
keyPressed(): 228, 228, L'ä'

keyStateChanged(): 192, 
keyPressed(): 246, 246, L'ö'

Here’s the application code:

#include "MainComponent.h"


MainComponent::MainComponent()
{
    mp_editor.reset(new juce::CodeEditorComponent(m_code_document, nullptr));
    mp_editor->setLineNumbersShown(false);
    mp_editor->setColour(juce::CodeEditorComponent::ColourIds::backgroundColourId, juce::Colour(0xFF555555));
    mp_editor->setColour(juce::CodeEditorComponent::ColourIds::highlightColourId, juce::Colour(0xFFAA5533));
    addAndMakeVisible(mp_editor.get());

    juce::String text;
    text << "Click this area with mouse, then type keyboard keys";

    m_help_text.setText(text, juce::NotificationType::dontSendNotification);
    addAndMakeVisible(m_help_text);
    
    setWantsKeyboardFocus(true);
    setSize(800, 600);
}


MainComponent::~MainComponent()
{
}


bool MainComponent::keyPressed(const juce::KeyPress& key)
{
    const int  key_code  = key.getKeyCode();
    const auto character = key.getTextCharacter();
    const int  decimal   = character;

    juce::String text;
    text << "keyPressed(): " << key_code << ", " << decimal << ", " << "L'" << character << "'\n\n";

    mp_editor->insertTextAtCaret(text);

    return true;
}


bool MainComponent::keyStateChanged(bool isKeyDown)
{
    if (!isKeyDown)
        return false;

    juce::String text;

    text << "keyStateChanged(): ";

    for (int i = 0; i < 10240; ++i)
        if (juce::KeyPress::isKeyCurrentlyDown(i))
            text << i << ", ";

    text << "\n";
    mp_editor->insertTextAtCaret(text);

    return false;
}


void MainComponent::paint(juce::Graphics& g)
{
    g.fillAll(getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
}


void MainComponent::resized()
{
    m_help_text.setBounds(0, 0, 1200, 200);
    mp_editor->setBounds(0, 200, getWidth(), getHeight() - 200);
}

Keyboard_Layout_Test_Minimal.zip (3.8 KB)

It seems that all my problems would be easily solved if JUCE would allow me to somehow receive the OS’s own raw key codes. Is there a way to receive the raw OS key codes somehow from JUCE? Even a user defined callback function would be do the job nicely in my case, it it was Called with the raw keycode whenever the keys are pressed/lifted.

If there is no such support in JUCE, what would be the easiest way to implement it?

That’s what the patch I had posted on your previous question does, I think. I can also post the os-dependent map between virtual scan code and physical key location.

1 Like

Ah, for some reason my mind hadn’t registered that what you originally proposed was actually what was the best approach :slight_smile:

If my eyes don’t deceive me, the only thing that’s required is to put the original keycode into global variable and read it from the usual place inside JUCE. Looks simple enough. Thank you! (better late than never)

How often do those files in JUCE change? I.e do I need to do the changed for each JUCE version or can I just save the modified version and copy it over the new JUCE release version?

I use a custom git branch for my own patches, and I regularly merge JUCE develop branch into it. There are very rare merge conflicts, and when there are, it is always very trivial conflicts, so it is not a big burden.

1 Like

Sounds like a plan. I’ll do the same. Thanks! :slight_smile: