Merge branch 'gtk_unknown_keys' of https://github.com/martinetd/wxWidgets

Generate wxKeyEvents even for unknown keys in wxGTK.

See https://github.com/wxWidgets/wxWidgets/pull/2576
This commit is contained in:
Vadim Zeitlin
2021-11-05 13:55:12 +01:00
2 changed files with 54 additions and 62 deletions

View File

@@ -1321,20 +1321,26 @@ enum wxKeyCategoryFlags
This event class contains information about key press and release events. This event class contains information about key press and release events.
The main information carried by this event is the key being pressed or The main information carried by this event is the key being pressed or
released. It can be accessed using either GetKeyCode() function or released. It can be accessed using one of GetUnicodeKey(), GetKeyCode()
GetUnicodeKey(). For the printable characters, the latter should be used as or GetRawKeyCode() functions.
it works for any keys, including non-Latin-1 characters that can be entered For the printable characters, GetUnicodeKey() should be used as it works
when using national keyboard layouts. GetKeyCode() should be used to handle for any keys, including non-Latin-1 characters that can be entered when
using national keyboard layouts. GetKeyCode() should be used to handle
special characters (such as cursor arrows keys or @c HOME or @c INS and so special characters (such as cursor arrows keys or @c HOME or @c INS and so
on) which correspond to ::wxKeyCode enum elements above the @c WXK_START on) which correspond to ::wxKeyCode enum elements above the @c WXK_START
constant. While GetKeyCode() also returns the character code for Latin-1 constant. While GetKeyCode() also returns the character code for Latin-1
keys for compatibility, it doesn't work for Unicode characters in general keys for compatibility, it doesn't work for Unicode characters in general
and will return @c WXK_NONE for any non-Latin-1 ones. For this reason, it's and will return @c WXK_NONE for any non-Latin-1 ones.
recommended to always use GetUnicodeKey() and only fall back to GetKeyCode() If both GetUnicodeKey() and GetKeyCode() return @c WXK_NONE then the key
if GetUnicodeKey() returned @c WXK_NONE meaning that the event corresponds has no @c WXK_xxx mapping and GetRawKeyCode() can be used to distinguish
to a non-printable special keys. between keys, but raw key codes are platform specific.
For these reasons, it is recommended to always use GetUnicodeKey() and
only fall back to GetKeyCode() if GetUnicodeKey() returned @c WXK_NONE,
meaning that the event corresponds to a non-printable special keys, then
optionally check GetRawKeyCode() if GetKeyCode() also returned @c WXK_NONE
or simply ignore that key.
While both of these functions can be used with the events of @c While these three functions can be used with the events of @c
wxEVT_KEY_DOWN, @c wxEVT_KEY_UP and @c wxEVT_CHAR types, the values wxEVT_KEY_DOWN, @c wxEVT_KEY_UP and @c wxEVT_CHAR types, the values
returned by them are different for the first two events and the last one. returned by them are different for the first two events and the last one.
For the latter, the key returned corresponds to the character that would For the latter, the key returned corresponds to the character that would
@@ -1368,6 +1374,10 @@ enum wxKeyCategoryFlags
can be used to retrieve the key code as GetKeyCode() just returns @c can be used to retrieve the key code as GetKeyCode() just returns @c
WXK_NONE in this case. WXK_NONE in this case.
Also, note that @c wxEVT_CHAR events are not generated for keys which do
not have a wxWidgets mapping, so GetRawKeyCode() should never be required
for this event.
To summarize: you should handle @c wxEVT_CHAR if you need the translated To summarize: you should handle @c wxEVT_CHAR if you need the translated
key and @c wxEVT_KEY_DOWN if you only need the value of the key itself, key and @c wxEVT_KEY_DOWN if you only need the value of the key itself,
independent of the current keyboard state. independent of the current keyboard state.

View File

@@ -974,7 +974,7 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event,
} }
static bool static void
wxTranslateGTKKeyEventToWx(wxKeyEvent& event, wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
wxWindowGTK *win, wxWindowGTK *win,
GdkEventKey *gdk_event) GdkEventKey *gdk_event)
@@ -1093,18 +1093,16 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
event.m_uniChar = event.m_keyCode; event.m_uniChar = event.m_keyCode;
} }
// sending unknown key events doesn't really make sense // sending a WXK_NONE key and let app deal with it the RawKeyCode if required
if ( !key_code && !event.m_uniChar ) if ( !key_code && !event.m_uniChar )
return false; event.m_keyCode = WXK_NONE;
#else #else
if (!key_code) if (!key_code)
return false; event.m_keyCode = WXK_NONE;
#endif // wxUSE_UNICODE #endif // wxUSE_UNICODE
// now fill all the other fields // now fill all the other fields
wxFillOtherKeyEventFields(event, win, gdk_event); wxFillOtherKeyEventFields(event, win, gdk_event);
return true;
} }
@@ -1194,55 +1192,46 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
wxKeyEvent event( wxEVT_KEY_DOWN ); wxKeyEvent event( wxEVT_KEY_DOWN );
bool ret = false; bool ret = false;
bool return_after_IM = false;
if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) ) wxTranslateGTKKeyEventToWx(event, win, gdk_event);
// Send the CHAR_HOOK event first
if ( SendCharHookEvent(event, win) )
{ {
// Send the CHAR_HOOK event first // Don't do anything at all with this event any more.
if ( SendCharHookEvent(event, win) ) return TRUE;
{ }
// Don't do anything at all with this event any more.
return TRUE;
}
// Next check for accelerators. // Next check for accelerators.
#if wxUSE_ACCEL #if wxUSE_ACCEL
wxWindowGTK *ancestor = win; wxWindowGTK *ancestor = win;
while (ancestor) while (ancestor)
{
int command = ancestor->GetAcceleratorTable()->GetCommand( event );
if (command != -1)
{ {
int command = ancestor->GetAcceleratorTable()->GetCommand( event ); wxCommandEvent menu_event( wxEVT_MENU, command );
if (command != -1) ret = ancestor->HandleWindowEvent( menu_event );
if ( !ret )
{ {
wxCommandEvent menu_event( wxEVT_MENU, command ); // if the accelerator wasn't handled as menu event, try
ret = ancestor->HandleWindowEvent( menu_event ); // it as button click (for compatibility with other
// platforms):
if ( !ret ) wxCommandEvent button_event( wxEVT_BUTTON, command );
{ ret = ancestor->HandleWindowEvent( button_event );
// if the accelerator wasn't handled as menu event, try
// it as button click (for compatibility with other
// platforms):
wxCommandEvent button_event( wxEVT_BUTTON, command );
ret = ancestor->HandleWindowEvent( button_event );
}
break;
} }
if (ancestor->IsTopNavigationDomain(wxWindow::Navigation_Accel))
break; break;
ancestor = ancestor->GetParent();
} }
if (ancestor->IsTopNavigationDomain(wxWindow::Navigation_Accel))
break;
ancestor = ancestor->GetParent();
}
#endif // wxUSE_ACCEL #endif // wxUSE_ACCEL
// If not an accelerator, then emit KEY_DOWN event // If not an accelerator, then emit KEY_DOWN event
if ( !ret ) if ( !ret )
ret = win->HandleWindowEvent( event ); ret = win->HandleWindowEvent( event );
}
else
{
// Return after IM processing as we cannot do
// anything with it anyhow.
return_after_IM = true;
}
if ( !ret ) if ( !ret )
{ {
@@ -1265,9 +1254,6 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
} }
} }
if (return_after_IM)
return FALSE;
// Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
// will only be sent if it is not in an accelerator table. // will only be sent if it is not in an accelerator table.
if (!ret) if (!ret)
@@ -1395,11 +1381,7 @@ gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event); wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event);
wxKeyEvent event( wxEVT_KEY_UP ); wxKeyEvent event( wxEVT_KEY_UP );
if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) ) wxTranslateGTKKeyEventToWx(event, win, gdk_event);
{
// unknown key pressed, ignore (the event would be useless anyhow)
return FALSE;
}
return win->GTKProcessEvent(event); return win->GTKProcessEvent(event);
} }