Key modifiers in complex components


#1

Hi Jules!

I want to be able to apply my own modifier keys (e.g. for Cmd-V etc.) when the keyboard focus is on a slider control. This is fine when the keyboard focus is owned by a button sub-component of the slider.

However, when the focus is owned by the slider’s underlying text editor component, I can’t seem to prevent the text editor that is owned by the slider grabbing the Cmd-V key, and using it for its own end (e.g. to paste current text). That’s a shame, as I really need instead to perform a higher-level action in reponse to Cmd-V…!

Can I please :slight_smile: ask if there is some way that for sliders, there could be a method I could call that would pass-on a request to the underlying text editor to ignore command modifiers?

Or perhaps a hook I could apply to components that allow patching-in of key handling, where I can do something like this (that I’m already doing with my text editor components)…? That would be very powerful.

  virtual bool keyPressed (const KeyPress &key)
  {
    if (key.getModifiers().isCommandDown())
    {
      return false;
    }

    return TextEditor::keyPressed(key);
  }

Thanks in advance,

Pete


#2

But surely the text editor only exists while the value is actually being edited? In that case, wouldn’t you want the editor to get the cmd-v?


#3

Hi Jules,

Actually no, I want a higher-level command to apply. In this case, the component is just the child of a row. The semantics of the UI require that a paste operation via “cmd-V” to be interpreted as a paste to the entire row; hence the app needs to ensure that the text component ignores the command in this case.

Another example I’ve just come up against is in the context of a grid (e.g. TableListBox), where I want to intercept the up/down keys to move the focus up/down from grid cell to grid cell. However, when I’m in the TextEditor sub-component of a ComboBox, or the TextEditor sub-component of a Slider, I can’t find a way to grab the key events and use them for my own purposes!!

Seems like the general (and simple) solution to this sort of key handling might be to allow an application to:

  • ask ComboBox or Slider for child TextEditor (c.f. ListBox components can be asked its vertical Slider)
  • allow the application to register a key event listener/observer/“hook” with any component (including the TextEditor I’d have got from the above call), that allows the app to intercept events as necessary before the component handles them. In this case the listener can return a status code to indicate that the event has been handled.

With that in place, I can then get my apps keyboard handling nice and sorted! :slight_smile:

One other associated request would be if I could have a method on a ComboBox that I can call to determine if the Drop-down list is displayed. I would ignore up/down key even overriding in that case. I would also like a method that could force the ComboBox pop-up to appear (so I could have that happen e.g. if user pressed Enter key when on the box).

Hoping this makes sense, and all the best!

Pete


#4

Have you thought about using an editable Label instead of a TextEditor? That’d only intercept keys when it’s actually in the modal state of being edited. It’s more lightweight, too.


#5

Hi Jules, no I hadn’t - many thanks for the tip, sounds like a good thing for me to do!

Have you had any thoughts on the subject of key event “hooks” for components?

Pete


#6

Hmm… key event hooks - nice idea but would it be worth the extra bloat in the Component base class for such a rarely-needed feature?


#7

Hi Jules,

The problem is that without the ability to tell components to do something different with navigation key events (and other key events), my application will have poor keyboard navigation support. I have a user base which is pretty fussy about keyboard support working “just right”, so if you aren’t able to do it in the core system, I’ll have to modify my copy of the Juce library to do this <shudder!>. :shock: :slight_smile:

I don’t see there being much bloat, to be honest:

  • new hook class ComponentKeyHook (or some such) with one pure method:
    bool KeyEventHook
    … returns true if the hook handles the event, otherwise false
  • new methods on component allowing a hook to be registered/cleared
    (just like your common listener handling):
    addKeyEventHook
    removeKeyEventHook
    … and a new member variable or two and some new code in the
    key event handler

New method in both Slider and ComboBox, allowing the app to grab the TextEditor sub-component so it can add a hook:
TextEditor *getTextEditor (void)

Anyways, hoping that feedback helps. I know you’ve always got too much in your in-tray … don’t we all :slight_smile: … so hopefully you’ll consider it for some future development. I’m sure I won’t be the only Juce user who’d find the need to do this…?

All the best!

Pete


#8

How about, instead of all that, a change to the KeyListeners - at the moment, the component’s keyPressed method is called before the listeners are told, but if I reversed it to give the listeners the first go at the event, then they could override the components own method.

That’d do what you need, but would it bugger up other people’s code? Probably not…


#9

Hi Jules,

I see where you are coming from … :slight_smile: … but I can’t see that without adding:
getTextEditor() … to ComboBox and Slider
… and in turn adding:
setKeyListener/removeKeyListener() on Component…

… would the app be able to override key events on the internal TextEditor component within the ComboBox and Slider…?

…? Of course, you totally understand the framework, and I’m just learning my way around it!! :slight_smile:

Pete


#10

The combobox and slider both use Labels, not TextEditors, so there is no texteditor except when the user’s actually typing in them.


#11

Hi Jules,

Got you! So… I wonder how best to get keyboard hooks into the ComboBox and Slider …?


#12

Could probably be done by changing the keylistener stuff like I mentioned earlier. Let me have a think…


#13

Hi Jules, fabbo, many thanks. :slight_smile:

Pete


#14

Hi Jules, have you had that think yet? :slight_smile:

BTW, intermorphic’s noatikl and liptikl are now due for release in the next couple of weeks; due in no small part to the power of Juce. Much kudos to you, Jules!

Pete


#15

I think I changed around the keylistener order ages ago, probably about the time of this thread…

Thought you’d been a bit quiet lately - glad to hear you’ve been busy!


#16

Hi Jules!

Just returning to this as we prepare noatikl for sale in next week or so. :slight_smile:

I got your change to the key listener handling, but the problem is this:

  • I have no way to get guaranteed access to the underlying TextEditor that is created dynamically by the Label owned by the Slider, to attach a key listener, as the TextEditor appears and disappears dynamically.
  • when the Slider is attached to the ui, the Label is created immediately (and I can of course search for this Label by enumeration of the Slider child components of course, so could attach a key listener to this… but that is of no use of course as it is the TextEditor that handles the keyboard interaction…)
  • when the Slider gets focus, the Label owned by the Slider creates a TextEditor to handle the editing; this TextEditor is created dynamically, internally to the Label, so I have no way to attach a key listener to it; so I cannot override the TextEditor key handling. :slight_smile:
  • the solution to this might be to have something like “editorCreated” and “editorDeleted” listeners on the label class, that would allow my app to see when the editor owned by the label appeared/disappeared, giving me a chance to attach/detach key listeners to that TextEditor as it appears/disappears?

Hoping this makes sense. :slight_smile:

Pete


#17

Hi Pete

How about if I add a LookAndFeel method to create the editor component? Then you could override that so that when one gets created, you can attach your listener to it…


#18

ah - actually you can already do this: if you override LookAndFeel::createSliderTextBox, and make it return a custom Label where you override Label::createEditorComponent(), you can attach the listener there. A bit fiddly, but it should work.


#19

Brilliant idea Jules - and great foresight on your part. :slight_smile:

I’ll let you know how I get on…!

Pete


#20

Hi Jules,

Just to confirm that worked, once I’d updated my copy of juce_ComponentPeer.cpp … for the implementation of ComponentPeer::handleKeyPress()… to match the svn tip.

Once again: many thanks for that. :slight_smile:

The next (directly related!) question is: how can I intercept the key events for combo boxes. :slight_smile:

The reason is the same as before: I have them embedded in a table, and when the user presses up/down key when they have the focus and the pop-up list of values isn’t visible, I want to grab those events to allow me to change focus within the table up/down.

All the best!

Pete