Пример #1
0
PlatformKeyboardEvent::PlatformKeyboardEvent(wxKeyEvent& event)
{
    if (event.GetEventType() == wxEVT_KEY_UP)
        m_type = KeyUp;
    else if (event.GetEventType() == wxEVT_KEY_DOWN)
        m_type = KeyDown;
    else if (event.GetEventType() == wxEVT_CHAR)
        m_type = Char;
    else
        ASSERT_NOT_REACHED();
    if (m_type != Char)
        m_keyIdentifier = keyIdentifierForWxKeyCode(event.GetKeyCode());
    else {
        //ENTER is an editing command processed as a char (only Enter and Tab are)
        //unfortunately the unicode key for numpad_enter (370) is NOT what we want here (13)
        //The unicode values for normal enter and tab are the same as the ASCII values, thus ok
        //Note that I think this a wx bug, as the Character Code is actually 13 when
        //numpad_enter is a CHAR event.
        if (event.GetKeyCode() == 13 && event.GetUnicodeKey() == wxChar(370))
            m_text = "\r";
        else
            m_text = wxString(event.GetUnicodeKey());
        m_unmodifiedText = m_text;
    }
    m_autoRepeat = false; // FIXME: not correct.
    m_windowsVirtualKeyCode = windowsKeyCodeForKeyEvent(event.GetKeyCode());
    m_nativeVirtualKeyCode = event.GetKeyCode();
    m_isKeypad = (event.GetKeyCode() >= WXK_NUMPAD_SPACE) && (event.GetKeyCode() <= WXK_NUMPAD_DIVIDE);
    m_shiftKey = event.ShiftDown();
    m_ctrlKey = event.CmdDown();
    m_altKey = event.AltDown();
    m_metaKey = event.MetaDown();
}
Пример #2
0
void GSPanel::OnKeyDown( wxKeyEvent& evt )
{

	// HACK: Legacy PAD plugins expect PCSX2 to ignore keyboard messages on the GS Window while
	// the PAD plugin is open, so ignore here (PCSX2 will direct messages routed from PAD directly
	// to the APP level message handler, which in turn routes them right back here -- yes it's
	// silly, but oh well).

#ifdef __linux__
	// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad plugin. Wx deletes
	// the event before the pad see it. So you send key event directly to the pad.
	if( (PADWriteEvent != NULL) && (GSopen2 != NULL) ) {
		keyEvent event;
		event.key = evt.GetRawKeyCode();
		if (evt.GetEventType() == wxEVT_KEY_UP)
			event.evt = 3; // X equivalent of KEYRELEASE;
		else if (evt.GetEventType() == wxEVT_KEY_DOWN)
			event.evt = 2; // X equivalent of KEYPRESS;
		else
			event.evt = 0;

		PADWriteEvent(event);
	}
#endif

	if( (PADopen != NULL) && CoreThread.IsOpen() ) return;
	DirectKeyCommand( evt );
}
Пример #3
0
void KeyMonitorTextCtrl::OnKey(wxKeyEvent &event)
{
	if(event.GetKeyCode() != 308){
		//printf("key:%d %d\n", event.GetKeyCode(), event.GetModifiers());
	}
    // backspace cannot be used as shortcut key...
    if (event.GetKeyCode() == WXK_BACK)
    {
        // this text ctrl contains something and the user pressed backspace...
        // we must delete the keypress...
        Clear();
        return;
    }

    if (event.GetEventType() == wxEVT_KEY_DOWN ||
        (event.GetEventType() == wxEVT_KEY_UP && !IsValidKeyComb()))
    {
        // the user pressed some key combination which must be displayed
        // in this text control.... or he has just stopped pressing a
        // modifier key like shift, ctrl or alt without adding any
        // other alphanumeric char, thus generating an invalid keystroke
        // which must be cleared out...

        KeyBinder::Key key;
        key.code    = event.GetKeyCode();
        key.flags   = event.GetModifiers();
		
        SetValue(KeyBinder::GetKeyBindingAsText(key));
        SetInsertionPointEnd();

    }

}
bool
KeyboardTarget::update_state (wxKeyEvent &ev)
{
	unsigned int keyval = (unsigned int) ev.GetKeyCode();
	bool changed = true;
	
	if (ev.GetEventType() == wxEVT_KEY_DOWN)
	{
		if (find (_state.begin(), _state.end(), keyval) == _state.end()) {
			_state.push_back (keyval);
			sort (_state.begin(), _state.end());
		}
		else {
			changed = false;
		}
	}
	else if (ev.GetEventType() == wxEVT_KEY_UP) {
		KeyState::iterator i;
		
		if ((i = find (_state.begin(), _state.end(), keyval)) != _state.end()) {
			_state.erase (i);
			sort (_state.begin(), _state.end());
		} 
	}

#ifdef DEBUG_KEYBOARD
	cerr << "STATE: ";
	for (KeyState::iterator i = _state.begin(); i != _state.end(); ++i) {
		cerr << name_from_keycode(*i) << ' ';
	}
	cerr << " changed: " << changed << endl;
#endif

	return changed;
}
Пример #5
0
void wxKeyMonitorTextCtrl::OnKey(wxKeyEvent &event)
{
    // backspace cannot be used as shortcut key...
#ifndef wxKEYBINDER_ALLOW_BACKSPACE
    if (event.GetKeyCode() == WXK_BACK) {

        // this text ctrl contains something and the user pressed backspace...
        // we must delete the keypress...
        Clear();
        return;
    }
#endif

    if (event.GetEventType() == wxEVT_KEY_DOWN ||
            (event.GetEventType() == wxEVT_KEY_UP && !IsValidKeyComb())) {

        // the user pressed some key combination which must be displayed
        // in this text control.... or he has just stopped pressing a
        // modifier key like shift, ctrl or alt without adding any
        // other alphanumeric char, thus generating an invalid keystroke
        // which must be cleared out...
        SetValue(wxKeyBind::GetKeyStrokeString(event));
        SetInsertionPointEnd();
    }
}
Пример #6
0
void GSPanel::OnKeyDownOrUp( wxKeyEvent& evt )
{

	// HACK: Legacy PAD plugins expect PCSX2 to ignore keyboard messages on the GS Window while
	// the PAD plugin is open, so ignore here (PCSX2 will direct messages routed from PAD directly
	// to the APP level message handler, which in turn routes them right back here -- yes it's
	// silly, but oh well).

#if defined(__unix__)
	// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad plugin. Wx deletes
	// the event before the pad see it. So you send key event directly to the pad.
	if( (PADWriteEvent != NULL) && (GSopen2 != NULL) ) {
		keyEvent event;
		event.key = evt.GetRawKeyCode();
		if (evt.GetEventType() == wxEVT_KEY_UP)
			event.evt = 3; // X equivalent of KEYRELEASE;
		else if (evt.GetEventType() == wxEVT_KEY_DOWN)
			event.evt = 2; // X equivalent of KEYPRESS;
		else
			event.evt = 0;

		PADWriteEvent(event);
	}
#endif

#ifdef __WXMSW__
	// Not sure what happens on Linux, but on windows this method is called only when emulation
	// is paused and the GS window is not hidden (and therefore the event doesn't arrive from
	// the pad plugin and doesn't go through Pcsx2App::PadKeyDispatch). On such case (paused).
	// It needs to handle two issues:
	// 1. It's called both for key down and key up (linux apparently needs it this way) - but we
	//    don't want to execute the command twice (normally commands execute on key down only).
	// 2. It has wx keycode which is upper case for ascii chars, but our command handlers expect
	//    lower case for non-special keys.

	// ignore key up events
	if (evt.GetEventType() == wxEVT_KEY_UP)
		return;

	// Make ascii keys lower case - this apparently works correctly also with modifiers (shift included)
	if (evt.m_keyCode >= 'A' && evt.m_keyCode <= 'Z')
		evt.m_keyCode += (int)'a' - 'A';
#endif

	if( (PADopen != NULL) && CoreThread.IsOpen() ) return;
	DirectKeyCommand( evt );
}
void
KeyboardTarget::process_key_event (wxKeyEvent &event)
{
	KeyMap::iterator result;
	bool changed = true;

	if (!_enabled) {
		event.Skip();
		return;
	}
	
	if (event.GetEventType() == wxEVT_KEY_DOWN)
	{
		changed = update_state (event);

		if (changed) {
			if (_learning) {
				// do nothing yet
			}
			else if ((result = keymap.find (_state)) != keymap.end()) {
				(*result).second (false);
			}
			else  {
				event.Skip();
			}
		}
		// if it didn't change, it was an autorepeat, which we ignore

	}
	else if (event.GetEventType() == wxEVT_KEY_UP) {

		if (_learning) {
			// this is the first key up while learning, commit the binding
			commit_learn ();
			_learning = false;
			LearningStopped(); // emit
		}
		else if ((result = keymap.find (_state)) != keymap.end()) {
			(*result).second (true);
		}
		else {
			event.Skip();
		}

		update_state (event);
	}
}
Пример #8
0
void wxWebView::OnKeyEvents(wxKeyEvent& event)
{
    WebCore::Frame* frame = 0;
    if (m_mainFrame)
        frame = m_mainFrame->GetFrame();
        
    if (frame && frame->view()) {
        // WebCore doesn't handle these events itself, so we need to do
        // it and not send the event down or else CTRL+C will erase the text
        // and replace it with c.
        if (event.CmdDown() && event.GetEventType() == wxEVT_KEY_UP) {
            if (event.GetKeyCode() == static_cast<int>('C'))
                Copy();
            else if (event.GetKeyCode() == static_cast<int>('X'))
                Cut();
            else if (event.GetKeyCode() == static_cast<int>('V'))
                Paste();
            else if (event.GetKeyCode() == static_cast<int>('Z')) {
                if (event.ShiftDown()) {
                    if (m_mainFrame->CanRedo())
                        m_mainFrame->Redo();
                }
                else {
                    if (m_mainFrame->CanUndo())
                        m_mainFrame->Undo();
                }
            }
        } else {    
            WebCore::PlatformKeyboardEvent wkEvent(event);
            if (wkEvent.type() == WebCore::PlatformKeyboardEvent::Char && wkEvent.altKey())
                frame->eventHandler()->handleAccessKey(wkEvent);
            else
                frame->eventHandler()->keyEvent(wkEvent);
        }
    }
    
    // make sure we get the character event.
    if (event.GetEventType() != wxEVT_CHAR)
        event.Skip();
}
Пример #9
0
int AudacityApp::OnAllKeys(wxKeyEvent& event)
{
   AudacityProject *audacityPrj = GetActiveProject();

   if (!audacityPrj) {
      return -1;
   }

   if(audacityPrj->IsActive())
   {
      if (event.GetEventType() == wxEVT_KEY_DOWN) {
         if (audacityPrj->HandleKeyDown(event))
            return true;
      }
      if (event.GetEventType() == wxEVT_KEY_UP) {
         if (audacityPrj->HandleKeyUp(event))
            return true;
      }
   }

   return -1;
}
Пример #10
0
PlatformKeyboardEvent::PlatformKeyboardEvent(wxKeyEvent& event)
{
    m_text = wxString(event.GetUnicodeKey());
    m_unmodifiedText = m_text;
    m_keyIdentifier = keyIdentifierForWxKeyCode(event.GetKeyCode());
    m_isKeyUp = event.GetEventType() == wxEVT_KEY_UP;
    m_autoRepeat = false; // FIXME: not correct.
    m_WindowsKeyCode = windowsKeyCodeForKeyEvent(event.GetKeyCode());
    m_isKeypad = (event.GetKeyCode() >= WXK_NUMPAD_SPACE) && (event.GetKeyCode() <= WXK_NUMPAD_DIVIDE);
    m_shiftKey = event.ShiftDown();
    m_ctrlKey = event.CmdDown();
    m_altKey = event.AltDown();
    m_metaKey = event.MetaDown();    
}
Пример #11
0
void reViewport::OnCanvasKeypress(wxKeyEvent& event){
	wxEventType eventType = event.GetEventType();

	bool handled = false;

	if (eventType == wxEVT_KEY_DOWN)
		handled = m_toolManager->OnKeyDown(event, m_glCanvas);
	else
		handled = m_toolManager->OnKeyUp(event, m_glCanvas);

	if (!handled){
		event.Skip();
	}
}
Пример #12
0
///Call this when a key event is received.
///If it matches a command, it will call the appropriate
///CommandManagerListener function.  If you pass any flags,
///the command won't be executed unless the flags are compatible
///with the command's flags.
bool CommandManager::HandleKey(wxKeyEvent &evt, wxUint32 flags, wxUint32 mask)
{
   wxString keyStr = KeyEventToKeyString(evt);
   CommandListEntry *entry = mCommandKeyHash[keyStr];
   if (evt.GetEventType() == wxEVT_KEY_DOWN)
   {
      return HandleCommandEntry( entry, flags, mask, &evt );
   }

   if (entry && entry->wantevent)
   {
      return HandleCommandEntry( entry, flags, mask, &evt );
   }

   return false;
}
Пример #13
0
void wxWebView::OnKeyEvents(wxKeyEvent& event)
{
    WebCore::Frame* frame = 0;
    if (m_impl->page)
        frame = m_impl->page->focusController()->focusedOrMainFrame();

    if (!(frame && frame->view()))
        return;

    if (event.GetKeyCode() == WXK_CAPITAL)
        frame->eventHandler()->capsLockStateMayHaveChanged();

    WebCore::PlatformKeyboardEvent wkEvent(event);

    if (frame->eventHandler()->keyEvent(wkEvent))
        return;

    //Some things WebKit won't do for us... Copy/Cut/Paste and KB scrolling
    if (event.GetEventType() == wxEVT_KEY_DOWN) {
        switch (event.GetKeyCode()) {
        case 67: //"C"
            if (CanCopy() && event.GetModifiers() == wxMOD_CMD) {
                Copy();
                return;
            }
            break;
        case 86: //"V"
            if (CanPaste() && event.GetModifiers() == wxMOD_CMD) {
                Paste();
                return;
            }
            break;
        case 88: //"X"
            if (CanCut() && event.GetModifiers() == wxMOD_CMD) {
                Cut();
                return;
            }
            break;
        case WXK_INSERT:
            if (CanCopy() && event.GetModifiers() == wxMOD_CMD) {
                Copy();
                return;
            }
            if (CanPaste() && event.GetModifiers() == wxMOD_SHIFT) {
                Paste();
                return;
            }
            return; //Insert shall not become a char
        case WXK_DELETE:
            if (CanCut() && event.GetModifiers() == wxMOD_SHIFT) {
                Cut();
                return;
            }
            break;
        case WXK_LEFT:
        case WXK_NUMPAD_LEFT:
            frame->view()->scrollBy(WebCore::IntSize(-WebCore::Scrollbar::pixelsPerLineStep(), 0));
            return;
        case WXK_UP:
        case WXK_NUMPAD_UP:
            frame->view()->scrollBy(WebCore::IntSize(0, -WebCore::Scrollbar::pixelsPerLineStep()));
            return;
        case WXK_RIGHT:
        case WXK_NUMPAD_RIGHT:
            frame->view()->scrollBy(WebCore::IntSize(WebCore::Scrollbar::pixelsPerLineStep(), 0));
            return;
        case WXK_DOWN:
        case WXK_NUMPAD_DOWN:
            frame->view()->scrollBy(WebCore::IntSize(0, WebCore::Scrollbar::pixelsPerLineStep()));
            return;
        case WXK_END:
        case WXK_NUMPAD_END:
            frame->view()->setScrollPosition(WebCore::IntPoint(frame->view()->scrollX(), frame->view()->maximumScrollPosition().y()));
            return;
        case WXK_HOME:
        case WXK_NUMPAD_HOME:
            frame->view()->setScrollPosition(WebCore::IntPoint(frame->view()->scrollX(), 0));
            return;
        case WXK_PAGEUP:
        case WXK_NUMPAD_PAGEUP:
            frame->view()->scrollBy(WebCore::IntSize(0, -frame->view()->visibleHeight() * WebCore::Scrollbar::minFractionToStepWhenPaging()));
            return;
        case WXK_PAGEDOWN:
        case WXK_NUMPAD_PAGEDOWN:
            frame->view()->scrollBy(WebCore::IntSize(0, frame->view()->visibleHeight() * WebCore::Scrollbar::minFractionToStepWhenPaging()));
            return;
        //These we don't want turning into char events, stuff 'em
        case WXK_ESCAPE:
        case WXK_LBUTTON:
        case WXK_RBUTTON:
        case WXK_CANCEL:
        case WXK_MENU:
        case WXK_MBUTTON:
        case WXK_CLEAR:
        case WXK_PAUSE:
        case WXK_SELECT:
        case WXK_PRINT:
        case WXK_EXECUTE:
        case WXK_SNAPSHOT:
        case WXK_HELP:
        case WXK_F1:
        case WXK_F2:
        case WXK_F3:
        case WXK_F4:
        case WXK_F5:
        case WXK_F6:
        case WXK_F7:
        case WXK_F8:
        case WXK_F9:
        case WXK_F10:
        case WXK_F11:
        case WXK_F12:
        case WXK_F13:
        case WXK_F14:
        case WXK_F15:
        case WXK_F16:
        case WXK_F17:
        case WXK_F18:
        case WXK_F19:
        case WXK_F20:
        case WXK_F21:
        case WXK_F22:
        case WXK_F23:
        case WXK_F24:
        case WXK_NUMPAD_F1:
        case WXK_NUMPAD_F2:
        case WXK_NUMPAD_F3:
        case WXK_NUMPAD_F4:
        //When numlock is off Numpad 5 becomes BEGIN, or HOME on Char
        case WXK_NUMPAD_BEGIN:
        case WXK_NUMPAD_INSERT:
            return;
        }
    }

    event.Skip();
}
Пример #14
0
static bool
wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
                           wxWindowGTK *win,
                           GdkEventKey *gdk_event)
{
    // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
    //     but only event->keyval which is quite useless to us, so remember
    //     the last character from GDK_KEY_PRESS and reuse it as last resort
    //
    // NB: should be MT-safe as we're always called from the main thread only
    static struct
    {
        KeySym keysym;
        long   keycode;
    } s_lastKeyPress = { 0, 0 };

    KeySym keysym = gdk_event->keyval;

    wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
               event.GetEventType() == wxEVT_KEY_UP ? _T("release")
                                                    : _T("press"),
               keysym);

    long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);

    if ( !key_code )
    {
        // do we have the translation or is it a plain ASCII character?
        if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
        {
            // we should use keysym if it is ASCII as X does some translations
            // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
            // which we don't want here (but which we do use for OnChar())
            if ( !wxIsAsciiKeysym(keysym) )
            {
                keysym = (KeySym)gdk_event->string[0];
            }

            // we want to always get the same key code when the same key is
            // pressed regardless of the state of the modifiers, i.e. on a
            // standard US keyboard pressing '5' or '%' ('5' key with
            // Shift) should result in the same key code in OnKeyDown():
            // '5' (although OnChar() will get either '5' or '%').
            //
            // to do it we first translate keysym to keycode (== scan code)
            // and then back but always using the lower register
            Display *dpy = (Display *)wxGetDisplay();
            KeyCode keycode = XKeysymToKeycode(dpy, keysym);

            wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);

            KeySym keysymNormalized = XkbKeycodeToKeysym(dpy, keycode, 0, 0);

            // use the normalized, i.e. lower register, keysym if we've
            // got one
            key_code = keysymNormalized ? keysymNormalized : keysym;

            // as explained above, we want to have lower register key codes
            // normally but for the letter keys we want to have the upper ones
            //
            // NB: don't use XConvertCase() here, we want to do it for letters
            // only
            key_code = toupper(key_code);
        }
        else // non ASCII key, what to do?
        {
            // by default, ignore it
            key_code = 0;

            // but if we have cached information from the last KEY_PRESS
            if ( gdk_event->type == GDK_KEY_RELEASE )
            {
                // then reuse it
                if ( keysym == s_lastKeyPress.keysym )
                {
                    key_code = s_lastKeyPress.keycode;
                }
            }
        }

        if ( gdk_event->type == GDK_KEY_PRESS )
        {
            // remember it to be reused for KEY_UP event later
            s_lastKeyPress.keysym = keysym;
            s_lastKeyPress.keycode = key_code;
        }
    }

    wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);

    // sending unknown key events doesn't really make sense
    if ( !key_code )
        return false;

    // now fill all the other fields
    wxFillOtherKeyEventFields(event, win, gdk_event);

    event.m_keyCode = key_code;
#if wxUSE_UNICODE
    if ( gdk_event->type == GDK_KEY_PRESS ||  gdk_event->type == GDK_KEY_RELEASE )
    {
        event.m_uniChar = key_code;
    }
#endif

    return true;
}
Пример #15
0
// This method handles common code for SendKeyDown, SendKeyUp, and SendChar events.
void wxApp::MacCreateKeyEvent( wxKeyEvent& event, wxWindow* focus , long keymessage , long modifiers , long when , wxChar uniChar )
{
#if wxOSX_USE_COCOA_OR_CARBON
    
    short keycode, keychar ;

    keychar = short(keymessage & charCodeMask);
    keycode = short(keymessage & keyCodeMask) >> 8 ;
    if ( !(event.GetEventType() == wxEVT_CHAR) && (modifiers & (controlKey | shiftKey | optionKey) ) )
    {
        // control interferes with some built-in keys like pgdown, return etc. therefore we remove the controlKey modifier
        // and look at the character after
#ifdef __LP64__
        // TODO new implementation using TextInputSources
#else
        UInt32 state = 0;
        UInt32 keyInfo = KeyTranslate((Ptr)GetScriptManagerVariable(smKCHRCache), ( modifiers & (~(controlKey | shiftKey | optionKey))) | keycode, &state);
        keychar = short(keyInfo & charCodeMask);
#endif
    }

    long keyval = wxMacTranslateKey(keychar, keycode) ;
    if ( keyval == keychar && ( event.GetEventType() == wxEVT_KEY_UP || event.GetEventType() == wxEVT_KEY_DOWN ) )
        keyval = wxToupper( keyval ) ;

    // Check for NUMPAD keys.  For KEY_UP/DOWN events we need to use the
    // WXK_NUMPAD constants, but for the CHAR event we want to use the
    // standard ascii values
    if ( event.GetEventType() != wxEVT_CHAR )
    {
        if (keyval >= '0' && keyval <= '9' && keycode >= 82 && keycode <= 92)
        {
            keyval = (keyval - '0') + WXK_NUMPAD0;
        }
        else if (keycode >= 65 && keycode <= 81)
        {
            switch (keycode)
            {
                case 76 :
                    keyval = WXK_NUMPAD_ENTER;
                    break;

                case 81:
                    keyval = WXK_NUMPAD_EQUAL;
                    break;

                case 67:
                    keyval = WXK_NUMPAD_MULTIPLY;
                    break;

                case 75:
                    keyval = WXK_NUMPAD_DIVIDE;
                    break;

                case 78:
                    keyval = WXK_NUMPAD_SUBTRACT;
                    break;

                case 69:
                    keyval = WXK_NUMPAD_ADD;
                    break;

                case 65:
                    keyval = WXK_NUMPAD_DECIMAL;
                    break;
                default:
                    break;
            }
        }
    }

    event.m_shiftDown = modifiers & shiftKey;
    event.m_rawControlDown = modifiers & controlKey;
    event.m_altDown = modifiers & optionKey;
    event.m_controlDown = modifiers & cmdKey;
    event.m_keyCode = keyval ;
#if wxUSE_UNICODE
    event.m_uniChar = uniChar ;
#endif

    event.m_rawCode = keymessage;
    event.m_rawFlags = modifiers;
    event.SetTimestamp(when);
    event.SetEventObject(focus);
#else
    wxUnusedVar(event);
    wxUnusedVar(focus);
    wxUnusedVar(keymessage);
    wxUnusedVar(modifiers);
    wxUnusedVar(when);
    wxUnusedVar(uniChar);
#endif
}
Пример #16
0
void wxMultiColumnListCtrl::OnKey(wxKeyEvent& event)
{
    if (event.GetEventType() == wxEVT_KEY_UP)
    {
        if (event.GetKeyCode() == GetModifierKey())
        {
            // The window will close, don't select the item under mouse pointer
            m_ptMouse.x = m_ptMouse.y = -2;
            SendCloseEvent();
        }
        event.Skip();
        return;
    }

    if (event.GetKeyCode() == WXK_ESCAPE || event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER)
    {
        // The window will close, don't select the item under mouse pointer
        m_ptMouse.x = m_ptMouse.y = -2;

        if (event.GetKeyCode() == WXK_ESCAPE)
            m_items.SetSelection(-1);

        SendCloseEvent();
    }
    else if (event.GetKeyCode() == WXK_TAB || event.GetKeyCode() == GetExtraNavigationKey())
    {
        if (event.ShiftDown())
        {
            m_items.SetSelection(m_items.GetSelection() - 1);
            if (m_items.GetSelection() < 0)
                m_items.SetSelection(m_items.GetItemCount() - 1);

            AdvanceToNextSelectableItem(-1);
        }
        else
        {
            m_items.SetSelection(m_items.GetSelection() + 1);
            if (m_items.GetSelection() >= m_items.GetItemCount())
                m_items.SetSelection(0);

            AdvanceToNextSelectableItem(1);
        }

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_NUMPAD_DOWN)
    {
        m_items.SetSelection(m_items.GetSelection() + 1);
        if (m_items.GetSelection() >= m_items.GetItemCount())
            m_items.SetSelection(0);

        AdvanceToNextSelectableItem(1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_NUMPAD_UP)
    {
        m_items.SetSelection(m_items.GetSelection() - 1);
        if (m_items.GetSelection() < 0)
            m_items.SetSelection(m_items.GetItemCount() - 1);

        AdvanceToNextSelectableItem(-1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_HOME || event.GetKeyCode() == WXK_NUMPAD_HOME)
    {
        m_items.SetSelection(0);

        AdvanceToNextSelectableItem(1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_END || event.GetKeyCode() == WXK_NUMPAD_END)
    {
        m_items.SetSelection(m_items.GetItemCount() - 1);

        AdvanceToNextSelectableItem(-1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_LEFT || event.GetKeyCode() == WXK_NUMPAD_LEFT)
    {
        wxSwitcherItem& item = m_items.GetItem(m_items.GetSelection());

        int row = item.GetRowPos();
        int newCol = item.GetColPos() - 1;
        if (newCol < 0)
            newCol = (m_items.GetColumnCount() - 1);

        // Find the first item from the end whose row matches and whose column is equal or lower
        int i;
        for (i = m_items.GetItemCount()-1; i >= 0; i--)
        {
            wxSwitcherItem& item2 = m_items.GetItem(i);
            if (item2.GetColPos() == newCol && item2.GetRowPos() <= row)
            {
                m_items.SetSelection(i);
                break;
            }
        }

        AdvanceToNextSelectableItem(-1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_RIGHT || event.GetKeyCode() == WXK_NUMPAD_RIGHT)
    {
        wxSwitcherItem& item = m_items.GetItem(m_items.GetSelection());

        int row = item.GetRowPos();
        int newCol = item.GetColPos() + 1;
        if (newCol >= m_items.GetColumnCount())
            newCol = 0;

        // Find the first item from the end whose row matches and whose column is equal or lower
        int i;
        for (i = m_items.GetItemCount()-1; i >= 0; i--)
        {
            wxSwitcherItem& item2 = m_items.GetItem(i);
            if (item2.GetColPos() == newCol && item2.GetRowPos() <= row)
            {
                m_items.SetSelection(i);
                break;
            }
        }

        AdvanceToNextSelectableItem(1);

        GenerateSelectionEvent();

        Refresh();
    }
    else
        event.Skip();
}