Mac shortcut keys issue. Keys being sent to parent frame window.

74 views
Skip to first unread message

Tony Kennedy

unread,
Mar 25, 2025, 1:18:26 PMMar 25
to wx-users
Hi all,

On the Mac, if I have a floating wxMiniFrame (or AUI panel) that contains a text control, any shortcut keys (CMD-C, CMD-V etc) are sent to the parent wxFrame window. 

The parent wxFrame window has a wxMenu with copy/paste, so I see why the key presses are going there. But this behaviour is different on Windows (the text control works as expected, copy/paste is handled by the wxTextCtrl).

Am I missing something? I've tried disabling the top window accelerator keys (no joy) and using the wxEX_BLOCK_EVENTS style when creating the window (no joy).

Any help or suggestions are very welcome.

Thanks in advance,

Tony.

Vadim Zeitlin

unread,
Mar 25, 2025, 3:27:50 PMMar 25
to wx-u...@googlegroups.com
On Tue, 25 Mar 2025 06:18:26 -0700 (PDT) Tony Kennedy wrote:

TK> On the Mac, if I have a floating wxMiniFrame (or AUI panel) that contains a
TK> text control, any shortcut keys (CMD-C, CMD-V etc) are sent to the parent
TK> wxFrame window.

Sorry, I'm afraid this is one of these things that Mac just does
differently, i.e. I believe that it sends accelerators from palette windows
to the parent by default, and I have no idea about how to convince it not
to do it, especially without breaking anything else.

You probably need to track the key handling in wxOSX (setting
WXTRACE=keyevent may help to see better what's going on) and try to find a
place where the event handling diverges from the desired. Maybe this will
give you an idea about how to change it.

Sorry but this is all I can say without spending (much more) time (than I
can afford) on this.

Good luck!
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
https://www.tt-solutions.com/

Tony Kennedy

unread,
Mar 25, 2025, 4:52:10 PMMar 25
to wx-users
No problem.  I'm not familiar with objective C at all and not even sure if the code below is objective C or Swift.

I'm trying to trace things. In utils.m, I found the sendEvent function. And in it, there is a test for NSKeyUp, and the Apple docs say that it's depreciated. It also says there is an AppKit bug.


I tried replacing NSKeyUp with NSEvent.EventType.keyUp, but it refuses to compile so I'm stuck.


/* This is needed because otherwise we don't receive any key-up events for command-key
 combinations (an AppKit bug, apparently) */
- (void)sendEvent:(NSEvent *)anEvent
{
    if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
        [[self keyWindow] sendEvent:anEvent];
    else
        [super sendEvent:anEvent];    
}

Vadim Zeitlin

unread,
Mar 26, 2025, 9:20:24 PMMar 26
to wx-u...@googlegroups.com
On Tue, 25 Mar 2025 09:52:10 -0700 (PDT) Tony Kennedy wrote:

TK> No problem. I'm not familiar with objective C at all and not even sure if
TK> the code below is objective C or Swift.

It's Objective-C++ (as indicated by .mm extension, rather than the
standard .m for Objective-C), we don't use Swift.

TK> I'm trying to trace things. In utils.m, I found the sendEvent function. And
TK> in it, there is a test for NSKeyUp, and the Apple docs say that it's
TK> depreciated. It also says there is an AppKit bug.
TK>
TK> https://developer.apple.com/documentation/appkit/nskeyup
TK>
TK> I tried replacing NSKeyUp with NSEvent.EventType.keyUp
TK> <https://developer.apple.com/documentation/appkit/nsevent/eventtype/keyup>,
TK> but it refuses to compile so I'm stuck.

What was the intention behind this change? NSKeyUp is perfectly fine...

Perhaps it would be worth removing this "if" (or even this entire
function) entirely -- maybe it's indeed why you get the events in a wrong
window (although I'm not sure, as I'd expect the key window to be the
palette window).

Regards,

Tony Kennedy

unread,
Apr 1, 2025, 11:32:39 AM (13 days ago) Apr 1
to wx-users
I've done a little experimentation on this today and seemed to have got something working. But I'm really worried about any knock on effects.

Two functions have been changed,  wxWidgetCocoaImpl::keyEvent in window.mm and - (void)sendEvent:(NSEvent *)anEvent in utils.mm (images below show the differences).

In the  wxWidgetCocoaImpl::keyEvent function (window.mm I think), for a key down event, it's sent to the menu first. If I re-order the function to what is below (let the control have a go first), copy/paste work. 

Are there any Mac specialists here that can comment on this change? 

Thanks in advance,

Tony.

ChangeToUtilsMM.jpg
ChangeToWindowMM.jpg

Tony Kennedy

unread,
Apr 1, 2025, 11:48:30 AM (13 days ago) Apr 1
to wx-users
Ahh, this doesn't quite work, so please ignore (for now).

Tony Kennedy

unread,
Apr 1, 2025, 1:42:34 PM (13 days ago) Apr 1
to wx-users
ok, now I think I've got something that works. Previous attempt registered double key presses in certain controls.

Two functions have been changed,  wxWidgetCocoaImpl::keyEvent in window.mm and - (void)sendEvent:(NSEvent *)anEvent in utils.mm (images below show the differences).

In the existing wxWidgetCocoaImpl::keyEvent function (window.mm), when a key event happens, it's sent to the menu first. If I re-order the function to what is below (let the control have a go first), copy/paste work. 

Are there any Mac specialists here that can comment on this change? 

Thanks in advance,

Tony.



--------------------------Replacement function sendEvent in utils.mm---------------------------------
- (void)sendEvent:(NSEvent *)anEvent
{
    if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
        [[self keyWindow] sendEvent:anEvent];
    else if ([anEvent type] == NSKeyDown && ([anEvent modifierFlags] & NSCommandKeyMask))

        [[self keyWindow] sendEvent:anEvent];
    else
        [super sendEvent:anEvent];
}

--------------------------Replacement function wxWidgetCocoaImpl::keyEvent in window.mm---------------------------------
void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
{
    wxLogTrace(TRACE_KEYS, "Got %s for %s",
               wxDumpSelector((SEL)_cmd), wxDumpNSView(slf));

    if ( !m_wxPeer->IsEnabled() )
        return;

    bool bTryPopagateToMenu = false;
   
    if ( [event type] == NSKeyDown )
    {
        bTryPopagateToMenu = true;
        BeginNativeKeyDownEvent(event);
    }
   
    bool bEventHandled = true;//false;
    if ( GetFocusedViewInWindow([slf window]) != slf || m_hasEditor || (bEventHandled = !DoHandleKeyEvent(event)) )
    {
        wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
        superimpl(slf, (SEL)_cmd, event);
    }
   
    if ( [event type] == NSKeyDown )
    {
        EndNativeKeyDownEvent();
    }
   
    if  (bTryPopagateToMenu == true && bEventHandled == false)
    {
        if ( [[[NSApplication sharedApplication] mainMenu] performKeyEquivalent:event] )
        {
            wxLogTrace(TRACE_KEYS, "%s processed as key equivalent by the menu",
                       wxDumpSelector((SEL)_cmd));
            return;
        }
    }
}
ChangeToWindowMM.jpg
ChangeToUtilsMM.jpg

Igor Korot

unread,
Apr 1, 2025, 3:05:01 PM (13 days ago) Apr 1
to wx-u...@googlegroups.com
Hi, Tony,



On Tue, Apr 1, 2025, 8:42 AM Tony Kennedy <kenned...@gmail.com> wrote:
ok, now I think I've got something that works. Previous attempt registered double key presses in certain controls.

Two functions have been changed,  wxWidgetCocoaImpl::keyEvent in window.mm and - (void)sendEvent:(NSEvent *)anEvent in utils.mm (images below show the differences).

In the existing wxWidgetCocoaImpl::keyEvent function (window.mm), when a key event happens, it's sent to the menu first. If I re-order the function to what is below (let the control have a go first), copy/paste work. 

Are there any Mac specialists here that can comment on this change? 

Can you make a PR with your changes?

Thank you.

--
Please read https://www.wxwidgets.org/support/mlhowto.htm before posting.
---
You received this message because you are subscribed to the Google Groups "wx-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wx-users+u...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/wx-users/9c046e54-3652-4ae6-91d7-3ef3d5cb02bcn%40googlegroups.com.

Tony Kennedy

unread,
Apr 1, 2025, 4:45:35 PM (13 days ago) Apr 1
to wx-users
Sure (as soon as I work out how to do it).

One of the staff here is going to use the build with the modified code for a few days to see if there are any knock on effects.

Tony.

Vadim Zeitlin

unread,
Apr 1, 2025, 4:52:21 PM (13 days ago) Apr 1
to wx-u...@googlegroups.com
On Tue, 1 Apr 2025 06:42:34 -0700 (PDT) Tony Kennedy wrote:

TK> In the existing wxWidgetCocoaImpl::keyEvent function (window.mm), when a
TK> key event happens, it's sent to the menu first. If I re-order the function
TK> to what is below (let the control have a go first), copy/paste work.
TK>
TK> Are there any Mac specialists here that can comment on this change?

I'm not a Mac specialist, but I think that Mac applications are supposed
to send the events to the menu first, so it probably wouldn't be a good
idea to change this for the normal case. Can this be only done if the
current window is a floating one?

Thanks,

Tony Kennedy

unread,
Apr 1, 2025, 7:37:21 PM (13 days ago) Apr 1
to wx-users
I'm no Mac specialist either.

This has been driven by our users, they are complaining that in a floating panel containing a text control, the shortcut keys are not working. And they are right, the wxTextCtrl handles copy/paste etc, but if the wxTextCtrl is in a floating window, the main window intercepts the key presses. If the floating window had it's own menu, then sending the shortcut key to the menu would make sense. Maybe things need to be a little more complex.

There are two possibilities. Either the current functionality in wx is wrong, or my app doesn't implement copy/paste correctly. Copy/paste in my app target the main window, not the control with the focus. So maybe the correct thing to do is modify the copy/paste code so it works on the control with the focus. But that probably would not work for me as a user can select things, then change config in another window before hitting copy/paste. Maybe the correct thing to do (for my app) is disable the main window copy/paste when a wxTextCtrl has focus. I'll experiment with that tomorrow to see if it fixes things (implementing that could take a ton of work though).

Tony.

PS. I've had some feedback from my first user : I think the shortcuts for the comment section are entirely fixed. I could do cmd+c, cmd+v, option+delete, command+delete inside the comment section without any problems. Also, the shortcuts work perfectly everywhere (not just the comment section).






Tony Kennedy

unread,
Apr 2, 2025, 5:37:33 AM (12 days ago) Apr 2
to wx-users
ok, the more I look into this and think about it, all is ok and I was just assuming copy/paste/etc should be handled automatically.

Essentially the copy/paste/etc routines in my app should respond to what is selected. If focus is on a wxTextCtrl, I need to detect this and call the wxTextCtrl copy/paste methods. I've seen users select some text in a control and then click Edit->Copy (as they don't know that shortcut keys exist) and that should work on a wxTextCtrl if that is what has the focus. And this is not Mac specific, it's the same for any operating system.

So please ignore this thread. There is nothing wrong. I've now got a new function that detects if a wxTextCtrl has focus and responds appropriately (pasted below in case anyone else wants it).

Thanks to all for your comments (and making me think in more detail about this).

Tony.




void wxMyTopWindow::OnCopy(wxCommandEvent& e)
{
    if (OnShortcutKey(e, wxID_COPY))
        return;
   
...........
other code to execute if a wxTextCtrl does not have focus.
...........

}


bool wxMyTopWindow::OnShortcutKey(wxCommandEvent &e, int nID)
{
    wxWindow *pWndWithFocus = wxWindow::FindFocus();
   
    if ( pWndWithFocus != NULL )
    {
        if ( pWndWithFocus->IsKindOf(wxCLASSINFO(wxTextCtrl)) )
        {
            wxTextCtrl *pTextCtrl = (wxTextCtrl*)(pWndWithFocus);
            //int nID = e.GetId();
           
            bool bHandled = false;
           
            switch(nID)
            {
                case wxID_CUT:
                    pTextCtrl->Cut();
                    bHandled = true;
                    break;
                case wxID_COPY:
                    pTextCtrl->Copy();
                    bHandled = true;
                    break;
                case  wxID_PASTE:
                    pTextCtrl->Paste();
                    bHandled = true;
                    break;
                case wxID_CLEAR:
                    pTextCtrl->Clear();
                    bHandled = true;
                    break;
                case wxID_SELECTALL:
                    pTextCtrl->SelectAll();
                    bHandled = true;
                    break;

                case wxID_DELETE:
                    pTextCtrl->OnDelete(e);
                    bHandled = true;
                    break;
                   
                case wxID_UNDO:
                    pTextCtrl->Undo();
                    bHandled = true;
                    break;
                case wxID_REDO:
                    pTextCtrl->Redo();
                    bHandled = true;
                    break;


                    //case wxID_FIND,
                    //pTextCtrl->Find();
                    //bHandled = true;
                    //break;
                    //wxID_DUPLICATE,
                    //wxID_REPLACE,
                    //wxID_REPLACE_ALL,
                    //wxID_PROPERTIES,
            }
           
            if ( bHandled == true)
            {
                e.Skip();
            }
           
            return bHandled;
        }
    }

    return false;
}
Reply all
Reply to author
Forward
0 new messages