Intercepting keyboard accelerator keys inside TextCtrl

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.
Post Reply
jscholes
In need of some credit
In need of some credit
Posts: 3
Joined: Sun May 21, 2017 3:15 pm

Intercepting keyboard accelerator keys inside TextCtrl

Post by jscholes »

Hi all,

I have a menu containing several items, all with accelerator shortcuts defined using the tab character convenience method. Like this:

Code: Select all

Increase volume\tCtrl+Up
So far so good. However, two of my accelerators use the shortcusts Ctrl+Left and Ctrl+Right, respectively. My problem is that while focused on a TextCtrl, those shortcuts already have an expected function - in text fields, Ctrl+Left and Ctrl+Right should navigate by word. The majority of my users will utilise the keyboard very heavily so it's key that these functions work as expected.

So far, I've worked out that I can intercept all keys before they're processed for accelerator usage by binding a handler for wxEVT_CHAR_HOOK. But I'm not quite sure how to precede from that point. I want to define a set of shortcuts that should be passed through to the TextCtrl, but allow other accelerators to be processed normally if they don't have a TextCtrl-specific function. For instance, Ctrl+Left and Ctrl+Right should be processed by the TextCtrl because they navigate by word, but Ctrl+O should trigger its associated menu command because the TextCtrl has no use for that particular shortcut.

Changing the shortcuts (e.g. to Alt+Left instead of Ctrl+Left) isn't an option here as the application allows the users to interactively change the accelerators. Disabling the problematic menu items when a TextCtrl has focus also won't work, because the associated accelerator shortcuts still don't carry out their intended functions inside the TextCtrl (i.e. disabling the menu item with accelerator Ctrl+Left doesn't magically make the TextCtrl process that key combination properly). The latter point seems like a bug in wx, but it is how it is.

Hopefully I've made myself clear enough, and I appreciate any help anyone can give on this.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Intercepting keyboard accelerator keys inside TextCtrl

Post by doublemax »

I don't know if it works, but i'd try this first:
In the event handler for ctrl-up, check if a wxTextCtrl has focus. If yes, call event.Skip() and do nothing. Otherwise let the handler do its job.

Code: Select all

wxTextCtrl *tc = wxDynamicCast( wxWindow::FindFocus(), wxTextCtrl );
if( tc != NULL )
{
   event.Skip();
   return;
}
Use the source, Luke!
jscholes
In need of some credit
In need of some credit
Posts: 3
Joined: Sun May 21, 2017 3:15 pm

Re: Intercepting keyboard accelerator keys inside TextCtrl

Post by jscholes »

doublemax wrote:In the event handler for ctrl-up, check if a wxTextCtrl has focus. If yes, call event.Skip() and do nothing. Otherwise let the handler do its job.
Hi there, many thanks for the suggestion. Unfortunately I've already tried this - in my handler for wxEVT_MENU I checked whether the currently focused control was a wxTextCtrl and skipped the event if so, as you suggested. Unfortunately this only solves half of the problem. The action assigned to the menu item doesn't occur, but the TextCtrl doesn't handle the key combination either.

I have the same problem if I disable the menu item when a TextCtrl is focused, as well as if I set wxNullAcceleratorTable as the accelerator table for the TextCtrl. All of these approaches result in the menu event being ignored, but without the keyboard functionality being restored to the TextCtrl.
jscholes
In need of some credit
In need of some credit
Posts: 3
Joined: Sun May 21, 2017 3:15 pm

Re: Intercepting keyboard accelerator keys inside TextCtrl

Post by jscholes »

Upon considering this a bit further, I've come to some conclusions about what's going wrong - feel free to correct me if I haven't got these right:

1. When I'm focused on a wxTextCtrl and I press Ctrl+Left, the resolution order for handling that keypress is: wxEVT_KEY_HOOK -> any defined accelerator tables -> wxEVT_KEY_DOWN -> wxEVT_CHAR.
2. The behaviour to navigate by word presumably occurs in response to the wxEVT_KEY_DOWN event being fired, but because this comes last in line after accelerator processing it never gets a chance.
3. If I disable the associated menu item, the accelerator table for my window still eats up the wxEVT_KEY_DOWN event, because it simply discards the keypress with nothing to do.
4. If I call SetAcceleratorTable on my wxTextCtrl and pass wxNullAcceleratorTable, the processing for the keystroke still doesn't reach the wxEVT_KEY_DOWN stage. In this case, I was incorrect in my previous posts, because processing continues up the tree and the accelerator table assigned to the parent frame processes the keystroke as normal. In other words, this has no impact whatsoever. Some other posts on the Internet led me to believe that wxNullAcceleratorTable would somehow prevent any parent accelerators from being triggered which in retrospect, doesn't make any sense.

TL;DR: How do I bypass my frame's accelerator table while focused on a wxTextCtrl so that wxEVT_KEY_DOWN reaches the control as normal?
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Intercepting keyboard accelerator keys inside TextCtrl

Post by doublemax »

The only workaround i found was to manage the accelerator tables manually. Unfortunately that means that you can't show the keyboard shortcuts in the menu.

I do agree that disabling the menu entries should disable the shortcut and this would also be the easiest solution. Try asking about this on the wx-users mailing list: https://groups.google.com/forum/#!forum/wx-users
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Intercepting keyboard accelerator keys inside TextCtrl

Post by ONEEYEMAN »

Hi,
IIRC, there was a ticket about that.

Thank you.
Post Reply