Assigning keyboard shortcuts to controls.

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

doublemax wrote: Sun Mar 14, 2021 6:10 pm

Code: Select all

int MyApp::FilterEvent(wxEvent &event)
{
  if( event.GetEventType() == wxEVT_KEY_DOWN /* || event.GetEventType() == wxEVT_KEY_UP */ )
  {
    wxWindow *focusWindow = wxWindow::FindFocus();
    if( focusWindow != NULL ) {
      const wxString &className = focusWindow->GetClassInfo()->GetClassName();
      // if textctrl has focus, let all keys through
      if( className == wxT("wxTextCtrl") )
        return wxEventFilter::Event_Skip;
    }

    wxKeyEvent *ke = wxDynamicCast( &event, wxKeyEvent );
    if( ke != NULL )
    {
      switch( ke->GetKeyCode() )
      {
        case ' ':
          //wxLogMessage("space pressed - do something here");
          wxLogDebug("space pressed - do something here");
          return wxEventFilter::Event_Processed;
        break;
      }
    }
  }
  return -1;
}
This just demonstrates the general idea, in practice, you'll probably have to deal with quite a few edge cases.

For communication between the app and the submodules, i'd suggest some kind of signal-slot mechanism, so that you don't have to introduce too many global dependencies, e.g. http://sigslot.sourceforge.net/
Do I need to Bind/Connect this to the frame? If so, what should be the event handler, as this does not work,

Code: Select all

    this->Connect(wxEVT_KEY_DOWN, wxEventHandler(Browser::FilterEvent), NULL, this);
gives error, cannot static cast from Browser* to wxEvent& wxEventFunction.
User avatar
doublemax@work
Super wx Problem Solver
Super wx Problem Solver
Posts: 474
Joined: Wed Jul 29, 2020 6:06 pm
Location: NRW, Germany

Re: Assigning keyboard shortcuts to controls.

Post by doublemax@work »

You don't need Connect/Bind for this, it's a global event filter, that all events pass through. But it only works in the wxApp object, not any frame or window.

You could also derive from wxEventFilter like in the documentation, but i've never tried that:
https://docs.wxwidgets.org/trunk/classw ... ilter.html
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

doublemax@work wrote: Mon May 10, 2021 11:50 am You don't need Connect/Bind for this, it's a global event filter, that all events pass through. But it only works in the wxApp object, not any frame or window.

You could also derive from wxEventFilter like in the documentation, but i've never tried that:
https://docs.wxwidgets.org/trunk/classw ... ilter.html
Okay, moving the method to wxApp class works, but when I have focus on wxDataViewListCtrl all keys except the space key works, wxSearchCtrl is able to filter all keys fine, which is nice. Space key works everywhere else though.

Code: Select all

int App::FilterEvent(wxEvent& event)
{
    if(event.GetEventType() == wxEVT_KEY_DOWN /* || event.GetEventType() == wxEVT_KEY_UP */)
    {
        wxWindow *focusWindow = wxWindow::FindFocus();
        if(focusWindow != NULL)
        {
            const wxString &className = focusWindow->GetClassInfo()->GetClassName();

            // if SearchCtrl has focus, let all keys through
            if(className == wxT("wxSearchCtrl"))
            {
                wxLogDebug("SearchCtrl focused skipping key filtering");
                return wxEventFilter::Event_Skip;
            }
            // else if(className == wxT("wxDataViewListCtrl"))
            // {
            //     wxLogDebug("DVLC focused skipping key filtering");
            //     return wxEventFilter::Event_Skip;
            // }
        }

        wxKeyEvent *ke = wxDynamicCast(&event, wxKeyEvent);
        if(ke != NULL)
        {
            switch (ke->GetKeyCode())
            {
                case WXK_SPACE:
                    wxLogDebug("Space pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'S':
                    wxLogDebug("S pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'P':
                    wxLogDebug("P pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'O':
                    wxLogDebug("O pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'L':
                    wxLogDebug("L pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'M':
                    wxLogDebug("M pressed");
                    return wxEventFilter::Event_Processed;
                    break;
            }
        }
    }

    return -1;
}
Also, the case statement for what key is pressed, I just call the method for the button or widget, that I want to trigger the action for?, with the key code, like,

Code: Select all

     m_Frame->OnClickPlayButton();
Last edited by apoorv569 on Tue May 11, 2021 6:33 am, edited 1 time in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Assigning keyboard shortcuts to controls.

Post by doublemax »

but when I have focus on wxDataViewListCtrl all keys except the space key works
You mean the space bar does not trigger an event at all?
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

doublemax wrote: Tue May 11, 2021 6:00 am
but when I have focus on wxDataViewListCtrl all keys except the space key works
You mean the space bar does not trigger an event at all?
No, I mean when the focus is on wxDataViewListCtrl. It works if the focus is anywhere but wxDataViewListCtrl.
User avatar
doublemax@work
Super wx Problem Solver
Super wx Problem Solver
Posts: 474
Joined: Wed Jul 29, 2020 6:06 pm
Location: NRW, Germany

Re: Assigning keyboard shortcuts to controls.

Post by doublemax@work »

Strange. Remind me what platform you're on?

If it's not Windows, wxDVC is a native control, and if that consumes any presses of the space key, i don't think there is anything you can do about it.
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

doublemax@work wrote: Strange. Remind me what platform you're on?
I'm using Arch Linux.
doublemax@work wrote: If it's not Windows, wxDVC is a native control, and if that consumes any presses of the space key, i don't think there is anything you can do about it.
I see, I guess I have to use a different keybind in place of space key. BTW, in those switch statements, what do I do now to trigger the action? Do I simply call the function, for example to trigger a action for a wxButton PlayButton, I just call its function OnClickPlayButton()? If so, how would the argument be handled here, as a wxButton takes wxCommandEvent& as its argument.
User avatar
doublemax@work
Super wx Problem Solver
Super wx Problem Solver
Posts: 474
Joined: Wed Jul 29, 2020 6:06 pm
Location: NRW, Germany

Re: Assigning keyboard shortcuts to controls.

Post by doublemax@work »

apoorv569 wrote: Tue May 11, 2021 9:51 am BTW, in those switch statements, what do I do now to trigger the action? Do I simply call the function, for example to trigger a action for a wxButton PlayButton, I just call its function OnClickPlayButton()? If so, how would the argument be handled here, as a wxButton takes wxCommandEvent& as its argument.
If you want to hardwire everything from inside the filter event handler, then yes. Move the actual code from OnClickPlayButton() into a separate void method. Then you can call this method from the "normal" button event handler (do you even still need this?), or from the filter event handler.
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

doublemax@work wrote: Tue May 11, 2021 10:17 am
apoorv569 wrote: Tue May 11, 2021 9:51 am BTW, in those switch statements, what do I do now to trigger the action? Do I simply call the function, for example to trigger a action for a wxButton PlayButton, I just call its function OnClickPlayButton()? If so, how would the argument be handled here, as a wxButton takes wxCommandEvent& as its argument.
If you want to hardwire everything from inside the filter event handler, then yes. Move the actual code from OnClickPlayButton() into a separate void method. Then you can call this method from the "normal" button event handler (do you even still need this?), or from the filter event handler.
And there is another way? What do you mean by hardwire? Is this a wrong way to deal with this?
User avatar
doublemax@work
Super wx Problem Solver
Super wx Problem Solver
Posts: 474
Joined: Wed Jul 29, 2020 6:06 pm
Location: NRW, Germany

Re: Assigning keyboard shortcuts to controls.

Post by doublemax@work »

apoorv569 wrote: Tue May 11, 2021 10:59 am And there is another way? What do you mean by hardwire? Is this a wrong way to deal with this?
Having a global event handler is always a little messy. A nicer way would be to broadcast an event which could then be received by anyone who's interested in it. But wxWidgets doesn't have that.

If it's only about redirecting a few events to a single control, i would probably do it the same way like you're doing it now.
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

doublemax@work wrote: Tue May 11, 2021 11:52 am
apoorv569 wrote: Tue May 11, 2021 10:59 am And there is another way? What do you mean by hardwire? Is this a wrong way to deal with this?
Having a global event handler is always a little messy. A nicer way would be to broadcast an event which could then be received by anyone who's interested in it. But wxWidgets doesn't have that.

If it's only about redirecting a few events to a single control, i would probably do it the same way like you're doing it now.
I want to bind 3 wxButton, 2 wxToggleButton, and 1 wxCheckBox. For this I have move quite a lot of code, as my Browser class, the class where all GUI elements/widgets are defined, has a lot of other things it fetches in these functions from other classes and so on. It is not really convenient to do so, as it might break some stuff, and/or cause bugs in the application. Is there really no other way to be able to do this? So I don't have to mess with existing (working) code.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Assigning keyboard shortcuts to controls.

Post by doublemax »

If these controls lie in the same frame, and the frame handles the events, you could create a wxCommandEvent, fill its members and send it to the frame, mimicking "real" events. Ugly, but should work.
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

I combined my MainFrame and Browser class to just one class MainFrame, before in MainFrame I was just initializing the wxFrame, and Browser class was inheriting from wxPanel. Tried a couple things, nothing seems to be changed now.
doublemax wrote: Tue May 11, 2021 3:47 pm If these controls lie in the same frame, and the frame handles the events, you could create a wxCommandEvent, fill its members and send it to the frame, mimicking "real" events. Ugly, but should work.
Do you mean like this (using wxDynamicCast)?

Code: Select all

        wxKeyEvent* keyEvent = wxDynamicCast(&event, wxKeyEvent);
        wxCommandEvent* cevt = wxDynamicCast(&event, wxCommandEvent);
        if(keyEvent != NULL)
        {
            switch (keyEvent->GetKeyCode())
            {
                case WXK_SPACE:
                    wxLogDebug("Space pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'A':
                    m_Frame->OnCheckAutoplay(*cevt);
                    wxLogDebug("A pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'S':
                    wxLogDebug("S pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'P':
                    m_Frame->OnClickPlay(*cevt);
                    wxLogDebug("P pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'O':
                    wxLogDebug("O pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'L':
                    m_Frame->OnClickLoop(*cevt);
                    wxLogDebug("L pressed");
                    return wxEventFilter::Event_Processed;
                    break;
                case 'M':
                    wxLogDebug("M pressed");
                    return wxEventFilter::Event_Processed;
                    break;
            }
        }
    }

    return -1;
}
The method works, I had to make the OnClickPlay() and other method in the above code public, but this method won't let me toggle wxToggleButton and wxCheckBox, Also spacebar does not work still when the focus is on wxDataViewListCtrl. Looks like I have to drop the plan for assigning keybindings. As somethings are simply not working.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Assigning keyboard shortcuts to controls.

Post by doublemax »

No. You can't just cast a wxKeyEvent to a wxCommandEvent.

E.g. to emulate a button click event:

Code: Select all

wxCommandEvent evt(wxEVT_BUTTON);

// this two are not always needed, depends on your event binding and 
// whether the event handlers use these values
evt.SetId( /* control id */ );
evt.SetEventObject( /* control pointer */ );

m_Frame->AddPendingEvent(evt);
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: Assigning keyboard shortcuts to controls.

Post by apoorv569 »

doublemax wrote: Wed May 12, 2021 6:13 pm No. You can't just cast a wxKeyEvent to a wxCommandEvent.

E.g. to emulate a button click event:

Code: Select all

wxCommandEvent evt(wxEVT_BUTTON);

// this two are not always needed, depends on your event binding and 
// whether the event handlers use these values
evt.SetId( /* control id */ );
evt.SetEventObject( /* control pointer */ );

m_Frame->AddPendingEvent(evt);
This is giving me similar result, only wxButton are able to be assigned, wxToggleButton does not work, also spacebar still won't work if focus is on wxDataViewListCtrl, however I noticed, if I have autoplay (wxCheckBox) checked, then spacebar works. BTW my LoopButton (wxToggleButton) method looking like this,

Code: Select all

void MainFrame::OnClickLoop(wxCommandEvent& event)
{
    if (m_LoopButton->GetValue())
    {
        bLoop = true;
    }
    else
    {
        bLoop = false;
    }
}
It just sets a boolean true or false based on the toggle state. However I can call LoopButton->SetValue(true).
Post Reply