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
This commit is contained in:
Vadim Zeitlin 2001-10-08 17:44:29 +00:00
parent 9feee261c9
commit f17393f199
3 changed files with 159 additions and 139 deletions

View File

@ -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}

View File

@ -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 <esc> 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

View File

@ -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 <esc> 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