From: Vadim Zeitlin Date: Mon, 8 Oct 2001 17:44:29 +0000 (+0000) Subject: normalized handling of Ctrl-x key presses and documented it clearly X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/f17393f19902b4fd15ad20068af37aa6bbefd952 normalized handling of Ctrl-x key presses and documented it clearly git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11892 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/latex/wx/keyevent.tex b/docs/latex/wx/keyevent.tex index 99d3386f3f..0abdc667d4 100644 --- a/docs/latex/wx/keyevent.tex +++ b/docs/latex/wx/keyevent.tex @@ -2,6 +2,49 @@ This event class contains information about keypress (character) events. +Notice that there are three different kinds of keyboard events in wxWindows: +key down and up events and char events. The difference between the first two +is clear - the first corresponds to a key press and the second to a key +release - otherwise they are identical. Just note that if the key is +maintained in a pressed state you will typically get a lot of (automatically +generated) down events but only up one so it is wrong to assume that there is +one up event corresponding to each down one. + +Both key events provide untranslated key codes while the char event carries +the translated one. The untranslated code for alphanumeric keys is always +an upper case value. For the other keys it is one of {\tt WXK\_XXX} values +from the \helpref{keycodes table}{keycodes}. The translated key is, in +general, the character the user expects to appear as the result of the key +combination when typing the text into a text entry zone, for example. + +A few examples to clarify this (all assume that {\sc Caps Lock} is unpressed +and the standard US keyboard): when the {\tt 'A'} key is pressed, the key down +event key code is equal to {\tt ASCII A} $== 65$. But the char event key code +is {\tt ASCII a} $== 97$. On the other hand, if you press both {\sc Shift} and +{\tt 'A'} keys simultaneously , the key code in key down event will still be +just {\tt 'A'} while the char event key code parameter will now be {\tt 'A'} +as well. + +Although in this simple case it is clear that the correct key code could be +found in the key down event handler by checking the value returned by +\helpref{ShiftDown()}{wxkeyeventshiftdown}, in general you should use +{\tt EVT\_CHAR} for this as for non alphanumeric keys the translation is +keyboard-layout dependent and can only be done properly by the system itself. + +Another kind of translation is done when the control key is pressed: for +example, for {\sc Ctrl-A} key press the key down event still carries the +same key code {\tt 'a'} as usual but the char event will have key code of +$1$, the ASCII value of this key combination. + +You may discover how the other keys on your system behave interactively by +running the \helpref{text}{sampletext} wxWindows sample and pressing some keys +in any of the text controls shown in it. + +{\bf Note for Windows programmers:} The key and char events in wxWindows are +similar to but slightly different from Windows {\tt WM\_KEYDOWN} and +{\tt WM\_CHAR} events. In particular, Alt-x combination will generate a char +event in wxWindows (unless it is used as an acclerator). + \wxheading{Derived from} \helpref{wxEvent}{wxevent} @@ -17,11 +60,10 @@ functions that take a wxKeyEvent argument. \twocolwidtha{7cm} \begin{twocollist}\itemsep=0pt -\twocolitem{{\bf EVT\_CHAR(func)}}{Process a wxEVT\_CHAR event (a non-modifier key has been pressed).} \twocolitem{{\bf EVT\_KEY\_DOWN(func)}}{Process a wxEVT\_KEY\_DOWN event (any key has been pressed).} \twocolitem{{\bf EVT\_KEY\_UP(func)}}{Process a wxEVT\_KEY\_UP event (any key has been released).} \twocolitem{{\bf EVT\_CHAR(func)}}{Process a wxEVT\_CHAR event.} -\twocolitem{{\bf EVT\_CHAR\_HOOK(func)}}{Process a wxEVT\_CHAR\_HOOK event.} +%\twocolitem{{\bf EVT\_CHAR\_HOOK(func)}}{Process a wxEVT\_CHAR\_HOOK event.} \end{twocollist}% \wxheading{See also} @@ -138,7 +180,7 @@ the latter is that it is common for {\sc NumLock} key to be configured as {\sc Meta} under X but the key presses even while {\sc NumLock} is on should be still processed normally). -\membersection{wxKeyEvent::ShiftDown} +\membersection{wxKeyEvent::ShiftDown}\label{wxkeyeventshiftdown} \constfunc{bool}{ShiftDown}{\void} diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 71c1df2f66..16d1c58200 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -487,7 +487,7 @@ static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNU static long map_to_unmodified_wx_keysym( GdkEventKey *event ) { KeySym keysym = event->keyval; - guint key_code = 0; + long key_code; switch (keysym) { @@ -581,21 +581,19 @@ static long map_to_unmodified_wx_keysym( GdkEventKey *event ) case GDK_F11: key_code = WXK_F11; break; case GDK_F12: key_code = WXK_F12; break; default: - { - if (event->length == 1) - { - key_code = toupper( (unsigned char)*event->string ); - } - else if ((keysym & 0xFF) == keysym) + if ( (keysym & 0xFF) == keysym ) { guint upper = gdk_keyval_to_upper( (guint)keysym ); - keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */ - key_code = (guint)keysym; + key_code = upper ? upper : keysym; + } + else + { + // unknown key code + key_code = 0; } - } } - return (key_code); + return key_code; } static long map_to_wx_keysym( GdkEventKey *event ) @@ -686,18 +684,18 @@ static long map_to_wx_keysym( GdkEventKey *event ) case GDK_F12: key_code = WXK_F12; break; default: { - if (event->length == 1) - { - key_code = (unsigned char)*event->string; - } - else if ((keysym & 0xFF) == keysym) + if (event->length == 1) + { + key_code = (unsigned char)*event->string; + } + else if ((keysym & 0xFF) == keysym) { key_code = (guint)keysym; } } } - return (key_code); + return key_code; } //----------------------------------------------------------------------------- @@ -967,6 +965,9 @@ static void gtk_window_draw_callback( GtkWidget *widget, // "key_press_event" from any window //----------------------------------------------------------------------------- +// turn on to see the key event codes on the console +#undef DEBUG_KEY_EVENTS + static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win ) @@ -980,23 +981,23 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, if (g_blockEventsOnDrag) return FALSE; -/* - wxString tmp; - tmp += (char)gdk_event->keyval; - printf( "KeyDown-Code is: %s.\n", tmp.c_str() ); - printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval ); -*/ - int x = 0; int y = 0; GdkModifierType state; - if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state); + if (gdk_event->window) + gdk_window_get_pointer(gdk_event->window, &x, &y, &state); bool ret = FALSE; long key_code = map_to_unmodified_wx_keysym( gdk_event ); + +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code); +#endif // DEBUG_KEY_EVENTS + /* sending unknown key events doesn't really make sense */ - if (key_code == 0) return FALSE; + if (key_code == 0) + return FALSE; wxKeyEvent event( wxEVT_KEY_DOWN ); event.SetTimestamp( gdk_event->time ); @@ -1031,39 +1032,37 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } #endif // wxUSE_ACCEL - /* wxMSW doesn't send char events with Alt pressed */ /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x will only be sent if it is not in an accelerator table. */ - key_code = map_to_wx_keysym( gdk_event ); - - if ( (!ret) && - (key_code != 0)) + if ( !ret ) { - wxKeyEvent event2( wxEVT_CHAR ); - event2.SetTimestamp( gdk_event->time ); - event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); - event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); - event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK); - event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); - event2.m_keyCode = key_code; - event2.m_scanCode = gdk_event->keyval; - event2.m_x = x; - event2.m_y = y; - event2.SetEventObject( win ); - ret = win->GetEventHandler()->ProcessEvent( event2 ); + key_code = map_to_wx_keysym( gdk_event ); + + if ( key_code ) + { +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Char event: %ld\n"), key_code); +#endif // DEBUG_KEY_EVENTS + + // reuse the ame event object, just change its type and use the + // translated keycode instead of the raw one + event.SetEventType(wxEVT_CHAR); + event.m_keyCode = key_code; + + ret = win->GetEventHandler()->ProcessEvent( event ); + } } /* win is a control: tab can be propagated up */ - if ( (!ret) && + if ( !ret && ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) && // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may // have this style, yet choose not to process this particular TAB in which // case TAB must still work as a navigational character #if 0 - (!win->HasFlag(wxTE_PROCESS_TAB)) && + !win->HasFlag(wxTE_PROCESS_TAB) && #endif // 0 - (win->GetParent()) && - (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) + win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) { wxNavigationKeyEvent new_event; new_event.SetEventObject( win->GetParent() ); @@ -1076,7 +1075,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } /* generate wxID_CANCEL if has been pressed (typically in dialogs) */ - if ( (!ret) && + if ( !ret && (gdk_event->keyval == GDK_Escape) ) { wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL); @@ -1084,10 +1083,9 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ret = win->GetEventHandler()->ProcessEvent( new_event ); } -#if (GTK_MINOR_VERSION > 0) - /* Pressing F10 will activate the menu bar of the top frame. */ /* Doesn't work. */ -/* +#if 0 // (GTK_MINOR_VERSION > 0) + /* Pressing F10 will activate the menu bar of the top frame. */ if ( (!ret) && (gdk_event->keyval == GDK_F10) ) { @@ -1113,8 +1111,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ancestor = ancestor->GetParent(); } } -*/ -#endif +#endif // 0 if (ret) { @@ -1139,28 +1136,20 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; -/* - printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval ); - if (gdk_event->state & GDK_SHIFT_MASK) - printf( "ShiftDown.\n" ); - else - printf( "ShiftUp.\n" ); - if (gdk_event->state & GDK_CONTROL_MASK) - printf( "ControlDown.\n" ); - else - printf( "ControlUp.\n" ); - printf( "\n" ); -*/ - long key_code = map_to_unmodified_wx_keysym( gdk_event ); +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code); +#endif // DEBUG_KEY_EVENTS + /* sending unknown key events doesn't really make sense */ if (key_code == 0) return FALSE; int x = 0; int y = 0; GdkModifierType state; - if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state); + if (gdk_event->window) + gdk_window_get_pointer(gdk_event->window, &x, &y, &state); wxKeyEvent event( wxEVT_KEY_UP ); event.SetTimestamp( gdk_event->time ); @@ -1772,7 +1761,7 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; - wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") ) + //wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") ) g_activeFrameLostFocus = TRUE; // VZ: this is really weird but GTK+ seems to call us from inside diff --git a/src/gtk1/window.cpp b/src/gtk1/window.cpp index 71c1df2f66..16d1c58200 100644 --- a/src/gtk1/window.cpp +++ b/src/gtk1/window.cpp @@ -487,7 +487,7 @@ static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNU static long map_to_unmodified_wx_keysym( GdkEventKey *event ) { KeySym keysym = event->keyval; - guint key_code = 0; + long key_code; switch (keysym) { @@ -581,21 +581,19 @@ static long map_to_unmodified_wx_keysym( GdkEventKey *event ) case GDK_F11: key_code = WXK_F11; break; case GDK_F12: key_code = WXK_F12; break; default: - { - if (event->length == 1) - { - key_code = toupper( (unsigned char)*event->string ); - } - else if ((keysym & 0xFF) == keysym) + if ( (keysym & 0xFF) == keysym ) { guint upper = gdk_keyval_to_upper( (guint)keysym ); - keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */ - key_code = (guint)keysym; + key_code = upper ? upper : keysym; + } + else + { + // unknown key code + key_code = 0; } - } } - return (key_code); + return key_code; } static long map_to_wx_keysym( GdkEventKey *event ) @@ -686,18 +684,18 @@ static long map_to_wx_keysym( GdkEventKey *event ) case GDK_F12: key_code = WXK_F12; break; default: { - if (event->length == 1) - { - key_code = (unsigned char)*event->string; - } - else if ((keysym & 0xFF) == keysym) + if (event->length == 1) + { + key_code = (unsigned char)*event->string; + } + else if ((keysym & 0xFF) == keysym) { key_code = (guint)keysym; } } } - return (key_code); + return key_code; } //----------------------------------------------------------------------------- @@ -967,6 +965,9 @@ static void gtk_window_draw_callback( GtkWidget *widget, // "key_press_event" from any window //----------------------------------------------------------------------------- +// turn on to see the key event codes on the console +#undef DEBUG_KEY_EVENTS + static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win ) @@ -980,23 +981,23 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, if (g_blockEventsOnDrag) return FALSE; -/* - wxString tmp; - tmp += (char)gdk_event->keyval; - printf( "KeyDown-Code is: %s.\n", tmp.c_str() ); - printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval ); -*/ - int x = 0; int y = 0; GdkModifierType state; - if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state); + if (gdk_event->window) + gdk_window_get_pointer(gdk_event->window, &x, &y, &state); bool ret = FALSE; long key_code = map_to_unmodified_wx_keysym( gdk_event ); + +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code); +#endif // DEBUG_KEY_EVENTS + /* sending unknown key events doesn't really make sense */ - if (key_code == 0) return FALSE; + if (key_code == 0) + return FALSE; wxKeyEvent event( wxEVT_KEY_DOWN ); event.SetTimestamp( gdk_event->time ); @@ -1031,39 +1032,37 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } #endif // wxUSE_ACCEL - /* wxMSW doesn't send char events with Alt pressed */ /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x will only be sent if it is not in an accelerator table. */ - key_code = map_to_wx_keysym( gdk_event ); - - if ( (!ret) && - (key_code != 0)) + if ( !ret ) { - wxKeyEvent event2( wxEVT_CHAR ); - event2.SetTimestamp( gdk_event->time ); - event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); - event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); - event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK); - event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); - event2.m_keyCode = key_code; - event2.m_scanCode = gdk_event->keyval; - event2.m_x = x; - event2.m_y = y; - event2.SetEventObject( win ); - ret = win->GetEventHandler()->ProcessEvent( event2 ); + key_code = map_to_wx_keysym( gdk_event ); + + if ( key_code ) + { +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Char event: %ld\n"), key_code); +#endif // DEBUG_KEY_EVENTS + + // reuse the ame event object, just change its type and use the + // translated keycode instead of the raw one + event.SetEventType(wxEVT_CHAR); + event.m_keyCode = key_code; + + ret = win->GetEventHandler()->ProcessEvent( event ); + } } /* win is a control: tab can be propagated up */ - if ( (!ret) && + if ( !ret && ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) && // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may // have this style, yet choose not to process this particular TAB in which // case TAB must still work as a navigational character #if 0 - (!win->HasFlag(wxTE_PROCESS_TAB)) && + !win->HasFlag(wxTE_PROCESS_TAB) && #endif // 0 - (win->GetParent()) && - (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) + win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) { wxNavigationKeyEvent new_event; new_event.SetEventObject( win->GetParent() ); @@ -1076,7 +1075,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, } /* generate wxID_CANCEL if has been pressed (typically in dialogs) */ - if ( (!ret) && + if ( !ret && (gdk_event->keyval == GDK_Escape) ) { wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL); @@ -1084,10 +1083,9 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ret = win->GetEventHandler()->ProcessEvent( new_event ); } -#if (GTK_MINOR_VERSION > 0) - /* Pressing F10 will activate the menu bar of the top frame. */ /* Doesn't work. */ -/* +#if 0 // (GTK_MINOR_VERSION > 0) + /* Pressing F10 will activate the menu bar of the top frame. */ if ( (!ret) && (gdk_event->keyval == GDK_F10) ) { @@ -1113,8 +1111,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget, ancestor = ancestor->GetParent(); } } -*/ -#endif +#endif // 0 if (ret) { @@ -1139,28 +1136,20 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; -/* - printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval ); - if (gdk_event->state & GDK_SHIFT_MASK) - printf( "ShiftDown.\n" ); - else - printf( "ShiftUp.\n" ); - if (gdk_event->state & GDK_CONTROL_MASK) - printf( "ControlDown.\n" ); - else - printf( "ControlUp.\n" ); - printf( "\n" ); -*/ - long key_code = map_to_unmodified_wx_keysym( gdk_event ); +#ifdef DEBUG_KEY_EVENTS + wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code); +#endif // DEBUG_KEY_EVENTS + /* sending unknown key events doesn't really make sense */ if (key_code == 0) return FALSE; int x = 0; int y = 0; GdkModifierType state; - if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state); + if (gdk_event->window) + gdk_window_get_pointer(gdk_event->window, &x, &y, &state); wxKeyEvent event( wxEVT_KEY_UP ); event.SetTimestamp( gdk_event->time ); @@ -1772,7 +1761,7 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED if (!win->m_hasVMT) return FALSE; if (g_blockEventsOnDrag) return FALSE; - wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") ) + //wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") ) g_activeFrameLostFocus = TRUE; // VZ: this is really weird but GTK+ seems to call us from inside