window.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,007 行 · 第 1/5 页

CPP
2,007
字号
        }
    }
#endif
    if (return_after_IM)
        return false;

#ifndef __WXGTK20__
    // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
    // in the "commit" handler.

    // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
    // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
    // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
    // composed of more than one character, which means gdk_event->length will always
    // greater than one. When gtk_event->length == 1, this may be an ASCII character
    // and can be translated by wx.  However, when MBCS characters are sent by IM,
    // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
    // nor should we pass it to controls. The following explanation was excerpted
    // from GDK documentation.
    // gint length : the length of string.
    // gchar *string : a null-terminated multi-byte string containing the composed
    // characters resulting from the key press. When text is being input, in a GtkEntry
    // for example, it is these characters which should be added to the input buffer.
    // When using Input Methods to support internationalized text input, the composed
    // characters appear here after the pre-editing has been completed.

    if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
    {
        // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
        #if wxUSE_UNICODE   // GTK+ 1.2 is not UTF-8 based.
            const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
            if( !string )
                return false;
        #else
            const char* string = gdk_event->string;
        #endif

        // Implement OnCharHook by checking ancesteror top level windows
        wxWindow *parent = win;
        while (parent && !parent->IsTopLevel())
            parent = parent->GetParent();

        for( const wxChar* pstr = string; *pstr; pstr++ )
        {
        #if wxUSE_UNICODE
            event.m_uniChar = *pstr;
            // Backward compatible for ISO-8859-1
            event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
        #else
            event.m_keyCode = *pstr;
        #endif
            if (parent)
            {
                event.SetEventType( wxEVT_CHAR_HOOK );
                ret = parent->GetEventHandler()->ProcessEvent( event );
            }
            if (!ret)
            {
                event.SetEventType(wxEVT_CHAR);
                win->GetEventHandler()->ProcessEvent( event );
            }
        }
        return true;
    }

#endif  // #ifndef  __WXGTK20__

#if wxUSE_ACCEL
    if (!ret)
    {
        wxWindowGTK *ancestor = win;
        while (ancestor)
        {
            int command = ancestor->GetAcceleratorTable()->GetCommand( event );
            if (command != -1)
            {
                wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
                ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
                break;
            }
            if (ancestor->IsTopLevel())
                break;
            ancestor = ancestor->GetParent();
        }
    }
#endif // wxUSE_ACCEL

    // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
    // will only be sent if it is not in an accelerator table.
    if (!ret)
    {
        long key_code;
        KeySym keysym = gdk_event->keyval;
        // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
        key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
        if ( !key_code )
        {
            if ( wxIsAsciiKeysym(keysym) )
            {
                // ASCII key
                key_code = (unsigned char)keysym;
            }
            // gdk_event->string is actually deprecated
            else if ( gdk_event->length == 1 )
            {
                key_code = (unsigned char)gdk_event->string[0];
            }
        }

        if ( key_code )
        {
            wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);

            event.m_keyCode = key_code;

            // To conform to the docs we need to translate Ctrl-alpha
            // characters to values in the range 1-26.
            if (event.ControlDown() && key_code >= 'a' && key_code <= 'z' )
            {
                event.m_keyCode = key_code - 'a' + 1;
            }               

#if wxUSE_UNICODE
            event.m_uniChar = event.m_keyCode;
#endif
            // Implement OnCharHook by checking ancesteror top level windows
            wxWindow *parent = win;
            while (parent && !parent->IsTopLevel())
                parent = parent->GetParent();
            if (parent)
            {
                event.SetEventType( wxEVT_CHAR_HOOK );
                ret = parent->GetEventHandler()->ProcessEvent( event );
            }

            if (!ret)
            {
                event.SetEventType(wxEVT_CHAR);
                ret = win->GetEventHandler()->ProcessEvent( event );
            }
        }
    }





    // win is a control: tab can be propagated up
    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
// JS: enabling again to make consistent with other platforms
//     (with wxTE_PROCESS_TAB you have to call Navigate to get default
//     navigation behaviour)
#if wxUSE_TEXTCTRL
         (! (win->HasFlag(wxTE_PROCESS_TAB) && win->IsKindOf(CLASSINFO(wxTextCtrl)) )) &&
#endif
         win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
    {
        wxNavigationKeyEvent new_event;
        new_event.SetEventObject( win->GetParent() );
        // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
        new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
        // CTRL-TAB changes the (parent) window, i.e. switch notebook page
        new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
        new_event.SetCurrentFocus( win );
        ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
    }

    // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
    if ( !ret &&
         (gdk_event->keyval == GDK_Escape) )
    {
        // however only do it if we have a Cancel button in the dialog,
        // otherwise the user code may get confused by the events from a
        // non-existing button and, worse, a wxButton might get button event
        // from another button which is not really expected
        wxWindow *winForCancel = win,
                 *btnCancel = NULL;
        while ( winForCancel )
        {
            btnCancel = winForCancel->FindWindow(wxID_CANCEL);
            if ( btnCancel )
            {
                // found a cancel button
                break;
            }

            if ( winForCancel->IsTopLevel() )
            {
                // no need to look further
                break;
            }

            // maybe our parent has a cancel button?
            winForCancel = winForCancel->GetParent();
        }

        if ( btnCancel )
        {
            wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
            event.SetEventObject(btnCancel);
            ret = btnCancel->GetEventHandler()->ProcessEvent(event);
        }
    }

    if (ret)
    {
        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
        return TRUE;
    }

    return FALSE;
}
}

#ifdef __WXGTK20__
extern "C" {
static void gtk_wxwindow_commit_cb (GtkIMContext *context,
                           const gchar  *str,
                           wxWindow     *window)
{
    wxKeyEvent event( wxEVT_KEY_DOWN );

    // take modifiers, cursor position, timestamp etc. from the last
    // key_press_event that was fed into Input Method:
    if (window->m_imData->lastKeyEvent)
    {
        wxFillOtherKeyEventFields(event,
                                  window, window->m_imData->lastKeyEvent);
    }

#if wxUSE_UNICODE
    const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
#else
    const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
    const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
#endif // wxUSE_UNICODE
    if( !(const wxChar*)data )
        return;

    bool ret = false;

    // Implement OnCharHook by checking ancestor top level windows
    wxWindow *parent = window;
    while (parent && !parent->IsTopLevel())
        parent = parent->GetParent();

    for( const wxChar* pstr = data; *pstr; pstr++ )
    {
#if wxUSE_UNICODE
        event.m_uniChar = *pstr;
        // Backward compatible for ISO-8859-1
        event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
        wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
#else
        event.m_keyCode = *pstr;
#endif  // wxUSE_UNICODE

        // To conform to the docs we need to translate Ctrl-alpha
        // characters to values in the range 1-26.
        if (event.ControlDown() && *pstr >= 'a' && *pstr <= 'z' )
        {
            event.m_keyCode = *pstr - 'a' + 1;
#if wxUSE_UNICODE
            event.m_uniChar = event.m_keyCode;
#endif  
        }               

        if (parent)
        {
            event.SetEventType( wxEVT_CHAR_HOOK );
            ret = parent->GetEventHandler()->ProcessEvent( event );
        }

        if (!ret)
        {
            event.SetEventType(wxEVT_CHAR);
            ret = window->GetEventHandler()->ProcessEvent( event );
        }
    }
}
}
#endif


//-----------------------------------------------------------------------------
// "key_release_event" from any window
//-----------------------------------------------------------------------------

extern "C" {
static gint gtk_window_key_release_callback( GtkWidget *widget,
                                             GdkEventKey *gdk_event,
                                             wxWindowGTK *win )
{
    DEBUG_MAIN_THREAD

    if (g_isIdle)
        wxapp_install_idle_handler();

    if (!win->m_hasVMT)
        return FALSE;

    if (g_blockEventsOnDrag)
        return FALSE;

    wxKeyEvent event( wxEVT_KEY_UP );
    if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
    {
        // unknown key pressed, ignore (the event would be useless anyhow
        return FALSE;
    }

    if ( !win->GetEventHandler()->ProcessEvent( event ) )
        return FALSE;

    gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
    return TRUE;
}
}

// ============================================================================
// the mouse events
// ============================================================================

// ----------------------------------------------------------------------------
// mouse event processing helpers
// ----------------------------------------------------------------------------

// init wxMouseEvent with the info from GdkEventXXX struct
template<typename T> void InitMouseEvent(wxWindowGTK *win,
                                         wxMouseEvent& event,
                                         T *gdk_event)
{
    event.SetTimestamp( gdk_event->time );
    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
    if (event.GetEventType() == wxEVT_MOUSEWHEEL)
    {
       event.m_linesPerAction = 3;
       event.m_wheelDelta = 120;
       if (((GdkEventButton*)gdk_event)->button == 4)
           event.m_wheelRotation = 120;
       else if (((GdkEventButton*)gdk_event)->button == 5)
           event.m_wheelRotation = -120;
    }

    wxPoint pt = win->GetClientAreaOrigin();
    event.m_x = (wxCoord)gdk_event->x - pt.x;
    event.m_y = (wxCoord)gdk_event->y - pt.y;

    event.SetEventObject( win );
    event.SetId( win->GetId() );
    event.SetTimestamp( gdk_event->time );
}

static void AdjustEventButtonState(wxMouseEvent& event)
{
    // GDK reports the old state of the button for a button press event, but
    // for compatibility with MSW and common sense we want m_leftDown be TRUE
    // for a LEFT_DOWN event, not FALSE, so we will invert
    // left/right/middleDown for the corresponding click events

    if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
        (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
        (event.GetEventType() == wxEVT_LEFT_UP))
    {
        event.m_leftDown = !event.m_leftDown;
        return;
    }

    if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
        (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
        (event.GetEventType() == wxEVT_MIDDLE_UP))
    {
        event.m_middleDown = !event.m_middleDown;
        return;
    }

    if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
        (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
        (event.GetEventType() == wxEVT_RIGHT_UP))
    {
        event.m_rightDown = !event.m_rightDown;
        return;
    }
}

// find the window to send the mouse event too
static
wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
{
    wxCoord xx = x;
    wxCoord yy = y;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?