Access to native keycode values


#1

Hi,

For my application I need to capture keycodes during GUI configuration and store them in a config file. This is all very easily done in Juce.

However, I later want to synthesise events that simulate those key presses. Reading juce_mac_NSViewComponentPeer.mm however, it seems that the juce::KeyPress keyCode is not the key code of the native system event, which obviously makes sense. Sadly though, the native key code is lost at this time and I can’t get access to it. I could try to reverse-synthesise the keycode from the character keycode that Juce uses, but that seems so much work for information that was there all along.

Does anyone have a good idea about how to preserve the native key code? I could modify the Juce KeyPress class and add a nativeKeyCode field to it, but I’d rather not stray from the Juce mainline.

Any thoughts? Jules, would you accept a patch back like this that preserves the original keycode throughout as a separate field?

Thank for the help,

Geert


#2

Not 100% sure what you’re trying to do, but the idea of adding to the KeyPress class doesn’t appeal too much, it feels like that could have some knock-on effects and cause complications.


#3

I’m basically building an app that generates key presses and mouse events automatically based on certain gestures.

The generation of these events is native code that I have working. However, I need to allow users to configure the key presses that they want to have automatically generated. The easiest way for them to do that is by pressing some keys. Using Juce’s key listeners and the KeyPress event with the text generation makes this very easy.

However, now I’m stuck since I can’t reverse the Juce’s 8-bit key code to generate the key press event that the user configured. Seems like an obvious choice to somehow store the original key code and then simply use it.

I totally understand that you’re not so hot on messing with the KeyPress class for this, me neither. However, I’m not so enthused to put in all the ‘reverse mapping’ work just to get the data that was there in the first place.


#4

Jules, this is a quick diff of the changes I made so that this works on OSX. I haven’t tested the other platforms yet, but it gives an indicator at what the impact of this change would be.

It works perfectly for my purpose explained before and I can just access the nativeCode KeyPress attribute to synthesise the key press events afterwards.

Any thoughts?


#5

Hmm. Feels wrong to me in ways that are hard to explain… Just seems like the wrong approach somehow. I guess my main problem is that the existing keyCode is already platform-dependent, so adding another, different, platform dependent key code is just confusing. It also bothers me that if you add an extra field like this, you’d be able to have two KeyPress objects whose operator== says they’re the same, but which are actually different.


#6

Yes I share a similar feeling, but what you’re saying is not entirely spot on. The existing keyCode is a Juce-specific interpreted and filtered version of native code with some part that are platform independent, some aren’t. This makes the whole thing so difficult to reverse back to the native representation.

I used this diff on Windows yesterday also and again it did exactly what I needed for my purpose: ie. resynthesise the original event.

For the equals implementation, I did punt on that, but it could be handling in the same way you’re handling the textCharacter now, where it’s only taken into account when present in both instances.


#7

Perhaps the correct thing to do would just be to change it so that the existing keycode field does what you need? Those values already vary between platforms, so as long as the enum constants like KeyPress::F1Key etc are correct, then that might work?


#8

That would definitely be the cleanest, but I’d be scared to break compatibility for existing apps as you have been generating that keyCode based mainly on ascii character representation.


#9

Well, I did always have this disclaimer about the keycodes:

// Note that the actual values of these are platform-specific and may change // without warning, so don't store them anywhere as constants. For persisting/retrieving // KeyPress objects, use getTextDescription() and createFromDescription() instead.


#10

[quote=“jules”]Well, I did always have this disclaimer about the keycodes:

// Note that the actual values of these are platform-specific and may change // without warning, so don't store them anywhere as constants. For persisting/retrieving // KeyPress objects, use getTextDescription() and createFromDescription() instead. [/quote]

That does making the reverse operation difficult again for createFromDescription(), which is probably why you opted for the character-based keycode approach. If getTextDescription() and createFromDescription() should be symmetrical for each different platform’s native behaviour, quite a lot of research and work will creep into this I think.


#11

Hmm, possibly. It’s all quite a can of worms really.


#12

Here’s an additional diff with the equals implementation and a small improvement for Android. I think that with this, the change is consistent throughout and does what I need.

Since there doesn’t seem to be a better solution and it is all tied together in quite a tricky way, I hope you’ll consider adding it to the mainline.


#13

So, I’ve now been using this patch for almost a week everyday with the app I’m working on. Haven’t seen any negative aspects to it. Is there any chance for it to be committed to the mainline?


#14

Well… I just don’t like it aesthetically. The thing is that I already don’t like the existing keyCode value because its meaning isn’t very clearly defined. So to add another, even less clearly defined but different value in addition just seems like the wrong approach.


#15

Ok, understood, I haven’t found a better way so I guess I’ll be stuck with maintain a little fork of Juce for this project :-/


#16

I’d like to help, but am a bit stuck for ideas!


#17

Sorry guys for stepping in but I’ve just got an idea about this.

Basically, I like the idea that jules had about using the already existing keycode field to contain the unique and platform dependent keypress description. At that point, if I understand conrrectly, the difficult part would be to make getTextDescription() and createFromDescription() play nicely with each other using an agnostic String representation of the keypress.

About that, what do you think about adding to the string generated by getTextDescription() an optional part that is basically a string encoding of the platform-dependent keycode already used within the class? For example, for a CTRL+F1 keypress on Mac it could return “CTRL+F1 [M#123456]”. On Windows, the same keypress would could generate the following encoding instead “CTRL+F1 [W#abcdef]”. They both share the platform-agnostic part, but they also have a platform-specific representation.

With this in mind, the createFromDescription could parse the string and look for the optional part at first. If it exists and matches the current platform, it has all information needed to create a KeyPress object that’s an exact clone of the original. On the other hand, if the optional part does not match the platform or if it is missing because was generated with an earlier JUCE version, the createFromDescription method could still use the platform-agnostic desciprion (“CTRL+F1” in this case) to do its best to recreate the correct keypress.

What do you think about this?


#18

I think it’s an interesting idea. The problem still is that if the current keycode is replaced with the native keycode, then the Juce’s public KeyCode constants don’t work anymore. They don’t all have regular key presses as native codes, but I think that’s mostly the media keys. There still would need to be dedicated handling for the native codes, with a dedicated method to access them. At that point, I don’t see the point of doing all the extra work of back and forth mapping just to save one class field that can be there from the start all along.


#19

Sorry, I don’t understand what you mean? All the public keycode values are statics whose value is hidden, and which is explicitly described as being subject to change between platforms and versions. Nothing should break if any of those values change (?)


#20

I think (but I may be misunderstanding something) that in the past messages gbevin concentrated more on the part of the disclaimer about “getTextDescription()/createFromDescription()”, worrying about the difficulties in their implementation (which I have written about), rather than the “all internal values can change without notice” part. To me, it looks like you are right and changing the internal representation shouldn’t break anything that uses the constants properly