Copy paste in TextEditor not working in OSX if used in ApplicationCommandTarget

Hello,
I’m developping an interface with JUCE and I need to be able to control the Copy/Cut/Paste behaviours to do those operations on custom classes in my software. At the same time, I expect the text editors to behave correctly when doing Ctrl+C / Ctrl+V / Ctrl+X .

On Windows, it’s working perfectly, I can select my elements and copy / paste them, and when editing a text, the copy/paste function will only work in the text field.
On OSX, the copy/paste functions are still triggering the code inside my main ApplicationCommandTarget class which is handling the custom copy/paste instead of the text editing ones, resulting in users copy/pasting objects when they expect to just copy/paste the text they’re editing.

If set the command infos to setActive(false), then the copy/pasting work but obviously not my custom functions (also there is a bug in the native mac menu that makes it not refresh when selected, and it needs to be called manually with handleAsyncUpdate(). This is again working just normally on windows and menus get refreshed when clicking on them)

My question is : is is a bug in JUCE, or is it some code that I should place to check that the focus is on a text editor ? As it is just working as expected on Windows and linux, I would imagine that the problem is on the JUCE/OSX side.

EDIT :
I traced back the events to the function menuItemInvoked in juce_mac_MainMenu.mm
it seems to be a native function, which I guess helps understand the difference of behaviour between windows/linux and mac. What seems to happen is that the keypress event is not even passed through the software’s componentPeer stack, but only handled by the ApplicationCommandTarget, so text editors and such can’t catch the event and take priority.

So I would guess that the workaround would be to activate/deactivate the copy/paste menu everytime a text editor is being edited, and force it to update because Mac won’t do it by itself.

Is there a better, cleaner way to do this ? I think to remember that this was not always the case (few years ago I mean)

Thank you

We ran into this same issue. We only have a Mac version of our app atm but this all worked in JUCE 5. I reverted the JUCE version back to version 5 to be sure and the behavior was back to normal.

Interesting you say it’s working on Windows!
We weren’t sure if something has changed in JUCE that requires us to update the key handling code.
But if these events are still forwarded to the TextEditor automatically on Windows this almost sounds like a bug to me.

I now just wrote appropriate key handlers for Cmd+C/V/A and forwarding it to the foreground components which will do for now but would also be interested to learn if this was changed intentionally.

Nice to not feel alone on this one :slight_smile:
Care to share the piece of code ?

FYI, the softwares I’m working on are :

Cheers

1 Like

Sure, no worries.
Use at your own risk though :wink:
The following is a section taken from this function:

bool perform ( const InvocationInfo& info) override;

Code

else if (info.commandID == StandardApplicationCommandIDs::undo)
{
	UndoRedoHelpers::sharedUndoManager().undo();
	return true;
}
else if (info.commandID == StandardApplicationCommandIDs::redo)
{
	UndoRedoHelpers::sharedUndoManager().redo();
	return true;
}
else if (info.commandID == StandardApplicationCommandIDs::copy)
{
	auto* comp = Component::getCurrentlyFocusedComponent();
	if (!comp)
		return true; // Pretend that we handled the command if no component focused
	
	TextEditor* editor = dynamic_cast<TextEditor*>(comp);
	if (editor)
		editor->copyToClipboard();
	
	return true;
}
else if (info.commandID == StandardApplicationCommandIDs::paste)
{
	auto* comp = Component::getCurrentlyFocusedComponent();
	if (!comp)
		return true; // Pretend that we handled the command if no component focused
	
	TextEditor* editor = dynamic_cast<TextEditor*>(comp);
	if (editor)
		editor->pasteFromClipboard();
	
	return true;
}
else if (info.commandID == StandardApplicationCommandIDs::selectAll)
{
	auto* comp = Component::getCurrentlyFocusedComponent();
	if (!comp)
		return true; // Pretend that we handled the command if no component focused
	
	TextEditor* editor = dynamic_cast<TextEditor*>(comp);
	if (editor)
	{
		editor->selectAll();
	}
	else if (dynamic_cast<EventListWindow*>(comp->getTopLevelComponent()))
	{
		EventListWindow* theWindow = (EventListWindow*) comp->getTopLevelComponent();
		theWindow->keyPressed(KeyPress::createFromDescription("CMD + A"));
	}
	return true;
}

As I said: just a workaround for our purposes.
Maybe it helps.

Thank you !

Thanks for reporting this issue. I think this change in behaviour is a regression introduced shortly after the release of JUCE 6, which I’ve attempted to rectify in this patch:

Please let us know if you encounter any problems with this change.

sorry for the late reply, it seems to work just fine, thank you !

1 Like

Thanks for the patch. Looks like that does not help for M1 Macs. Anyone having the same issue?