[vte] widget: Add wrapper class for key events



commit 19ea46dadd7898389753241ea2d1b5429bc4bd7d
Author: Christian Persch <chpe src gnome org>
Date:   Fri May 1 23:08:42 2020 +0200

    widget: Add wrapper class for key events
    
    Extract all information from the GdkEventKey, put them into a wrapper class,
    and pass that down to Terminal, instead of the native event.

 src/fwd.hh         |  6 +++++
 src/vte.cc         | 52 +++++++++++++++++++---------------------
 src/vteinternal.hh | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/widget.cc      | 40 +++++++++++++++++++++++++++++--
 src/widget.hh      |  9 ++++---
 5 files changed, 142 insertions(+), 35 deletions(-)
---
diff --git a/src/fwd.hh b/src/fwd.hh
index 11525a98..7cdfb741 100644
--- a/src/fwd.hh
+++ b/src/fwd.hh
@@ -25,4 +25,10 @@ class Pty;
 
 } // namespace base
 
+namespace platform {
+
+class Widget;
+
+} // namespace platform
+
 } // namespace vte
diff --git a/src/vte.cc b/src/vte.cc
index a7425afc..885288af 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -4494,36 +4494,33 @@ Terminal::beep()
                 m_real_widget->beep();
 }
 
-guint
-Terminal::translate_ctrlkey(GdkEventKey *event)
+unsigned
+Terminal::translate_ctrlkey(vte::terminal::KeyEvent const& event) const noexcept
 {
-       guint keyval;
-       GdkKeymap *keymap;
-       unsigned int i;
+       if (event.keyval() < 128)
+               return event.keyval();
 
-       if (event->keyval < 128)
-               return event->keyval;
-
-        keymap = gdk_keymap_get_for_display(gdk_window_get_display (event->window));
+        auto display = gdk_window_get_display(gdk_event_get_window((GdkEvent*)event.platform_event()));
+        auto keymap = gdk_keymap_get_for_display(display);
+        auto keyval = unsigned{event.keyval()};
 
        /* Try groups in order to find one mapping the key to ASCII */
-       for (i = 0; i < 4; i++) {
-               GdkModifierType consumed_modifiers;
-
+       for (auto i = unsigned{0}; i < 4; i++) {
+               auto consumed_modifiers = GdkModifierType{};
                gdk_keymap_translate_keyboard_state (keymap,
-                                                     event->hardware_keycode,
-                                                     (GdkModifierType)event->state,
+                                                     event.keycode(),
+                                                     GdkModifierType(event.modifiers()),
                                                      i,
                                                      &keyval, NULL, NULL, &consumed_modifiers);
                if (keyval < 128) {
                        _vte_debug_print (VTE_DEBUG_EVENTS,
-                                       "ctrl+Key, group=%d de-grouped into keyval=0x%x\n",
-                                       event->group, keyval);
-                       return keyval;
+                                          "ctrl+Key, group=%d de-grouped into keyval=0x%x\n",
+                                          event.group(), keyval);
+                        break;
                }
        }
 
-       return event->keyval;
+        return keyval;
 }
 
 void
@@ -4552,7 +4549,7 @@ Terminal::read_modifiers(GdkEvent *event)
 }
 
 bool
-Terminal::widget_key_press(GdkEventKey *event)
+Terminal::widget_key_press(vte::terminal::KeyEvent const& event)
 {
        char *normal = NULL;
        gsize normal_length = 0;
@@ -4565,10 +4562,11 @@ Terminal::widget_key_press(GdkEventKey *event)
 
        /* If it's a keypress, record that we got the event, in case the
         * input method takes the event from us. */
-       if (event->type == GDK_KEY_PRESS) {
+        // FIXMEchpe this is ::widget_key_press; what other event type could it even be!?
+       if (event.is_key_press()) {
                /* Store a copy of the key. */
-               keyval = event->keyval;
-               read_modifiers((GdkEvent*)event);
+                keyval = event.keyval();
+                m_modifiers = event.modifiers();
 
                 // FIXMEchpe?
                if (m_cursor_blink_timer) {
@@ -4588,7 +4586,7 @@ Terminal::widget_key_press(GdkEventKey *event)
                                "Keypress, modifiers=0x%x, "
                                "keyval=0x%x, raw string=`%s'.\n",
                                m_modifiers,
-                               keyval, event->string);
+                                 keyval, ((GdkEventKey*)event.platform_event())->string);
 
                /* We steal many keypad keys here. */
                if (!m_im_preedit_active) {
@@ -4687,10 +4685,10 @@ Terminal::widget_key_press(GdkEventKey *event)
        }
 
        /* Now figure out what to send to the child. */
-       if ((event->type == GDK_KEY_PRESS) && !modifier) {
+       if (event.is_key_press() && !modifier) {
                handled = FALSE;
                /* Map the key to a sequence name if we can. */
-               switch (keyval) {
+               switch (event.keyval()) {
                case GDK_KEY_BackSpace:
                        switch (m_backspace_binding) {
                        case EraseMode::eASCII_BACKSPACE:
@@ -5014,9 +5012,9 @@ Terminal::widget_key_press(GdkEventKey *event)
 }
 
 bool
-Terminal::widget_key_release(GdkEventKey *event)
+Terminal::widget_key_release(vte::terminal::KeyEvent const& event)
 {
-       read_modifiers((GdkEvent*)event);
+        m_modifiers = event.modifiers();
 
        if (m_input_enabled &&
             m_real_widget->im_filter_keypress(event))
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index b37272ad..e238fb32 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -267,6 +267,70 @@ class Widget;
 
 namespace terminal {
 
+class KeyEvent {
+        friend class vte::platform::Widget;
+        friend class Terminal;
+
+protected:
+
+        enum class Type {
+                ePRESS,
+                eRELEASE,
+        };
+
+        KeyEvent() noexcept = default;
+
+        constexpr KeyEvent(Type type,
+                           unsigned int modifiers,
+                           unsigned int keyval,
+                           unsigned int keycode,
+                           uint8_t group,
+                           unsigned int timestamp,
+                           bool is_modifier,
+                           GdkEventKey* gdk_event) noexcept
+                : m_type{type},
+                  m_modifiers{modifiers},
+                  m_keyval{keyval},
+                  m_keycode{keycode},
+                  m_group{group},
+                  m_timestamp{timestamp},
+                  m_is_modifier{is_modifier},
+                  m_platform_event{gdk_event}
+        {
+        }
+
+        constexpr auto platform_event() const noexcept { return m_platform_event; }
+
+public:
+        ~KeyEvent() noexcept = default;
+
+        KeyEvent(KeyEvent const&) = delete;
+        KeyEvent(KeyEvent&&) = delete;
+        KeyEvent& operator=(KeyEvent const&) = delete;
+        KeyEvent& operator=(KeyEvent&&) = delete;
+
+        constexpr auto const group()       const noexcept { return m_group;       }
+        constexpr auto const is_modifier() const noexcept { return m_is_modifier; }
+        constexpr auto const keycode()     const noexcept { return m_keycode;     }
+        constexpr auto const keyval()      const noexcept { return m_keyval;      }
+        constexpr auto const modifiers()   const noexcept { return m_modifiers;   }
+        constexpr auto const timestamp()   const noexcept { return m_timestamp;   }
+        constexpr auto const type()        const noexcept { return m_type;        }
+
+        constexpr auto const is_key_press()   const noexcept { return type() == Type::ePRESS;   }
+        constexpr auto const is_key_release() const noexcept { return type() == Type::eRELEASE; }
+
+private:
+        Type m_type;
+        unsigned m_modifiers;
+        unsigned m_keyval;
+        unsigned m_keycode;
+        uint8_t m_group;
+        unsigned m_timestamp;
+        bool m_is_modifier;
+        GdkEventKey* m_platform_event;
+}; // class KeyEvent
+
 class Terminal {
         friend class vte::platform::Widget;
 
@@ -920,8 +984,8 @@ public:
         void widget_style_updated();
         void widget_focus_in(GdkEventFocus *event);
         void widget_focus_out(GdkEventFocus *event);
-        bool widget_key_press(GdkEventKey *event);
-        bool widget_key_release(GdkEventKey *event);
+        bool widget_key_press(vte::terminal::KeyEvent const& event);
+        bool widget_key_release(vte::terminal::KeyEvent const& event);
         bool widget_button_press(GdkEventButton *event);
         bool widget_button_release(GdkEventButton *event);
         void widget_enter(GdkEventCrossing *event);
@@ -1110,7 +1174,7 @@ public:
         void vadjustment_value_changed();
 
         void read_modifiers(GdkEvent *event);
-        guint translate_ctrlkey(GdkEventKey *event);
+        unsigned translate_ctrlkey(vte::terminal::KeyEvent const& event) const noexcept;
 
         void apply_mouse_cursor();
         void set_pointer_autohidden(bool autohidden);
diff --git a/src/widget.cc b/src/widget.cc
index a8bd6c36..0a67a7bd 100644
--- a/src/widget.cc
+++ b/src/widget.cc
@@ -201,11 +201,11 @@ Widget::emit_eof() noexcept
 }
 
 bool
-Widget::im_filter_keypress(GdkEventKey* event) noexcept
+Widget::im_filter_keypress(vte::terminal::KeyEvent const& event) noexcept
 {
         // FIXMEchpe this can only be called when realized, so the m_im_context check is redundant
         return m_im_context &&
-                gtk_im_context_filter_keypress(m_im_context.get(), event);
+                gtk_im_context_filter_keypress(m_im_context.get(), event.platform_event());
 }
 
 void
@@ -245,6 +245,42 @@ Widget::im_set_cursor_location(cairo_rectangle_int_t const* rect) noexcept
         gtk_im_context_set_cursor_location(m_im_context.get(), rect);
 }
 
+unsigned
+Widget::read_modifiers_from_gdk(GdkEvent* event) const noexcept
+{
+        /* Read the modifiers. See bug #663779 for more information on why we do this. */
+        auto mods = GdkModifierType{};
+        if (!gdk_event_get_state(event, &mods))
+                return 0;
+
+        /* Map non-virtual modifiers to virtual modifiers (Super, Hyper, Meta) */
+        auto display = gdk_window_get_display(gdk_event_get_window(event));
+        auto keymap = gdk_keymap_get_for_display(display);
+        gdk_keymap_add_virtual_modifiers(keymap, &mods);
+
+        return unsigned(mods);
+}
+
+vte::terminal::KeyEvent
+Widget::key_event_from_gdk(GdkEventKey* event) const
+{
+        auto type = vte::terminal::KeyEvent::Type{};
+        switch (gdk_event_get_event_type(reinterpret_cast<GdkEvent*>(event))) {
+        case GDK_KEY_PRESS: type = vte::terminal::KeyEvent::Type::ePRESS; break;
+        case GDK_KEY_RELEASE: type = vte::terminal::KeyEvent::Type::eRELEASE; break;
+        default: g_assert_not_reached(); return {};
+        }
+
+        return {type,
+                read_modifiers_from_gdk(reinterpret_cast<GdkEvent*>(event)),
+                event->keyval,
+                event->hardware_keycode, // gdk_event_get_scancode(event),
+                event->group,
+                event->time,
+                event->is_modifier != 0,
+                event};
+}
+
 void
 Widget::map() noexcept
 {
diff --git a/src/widget.hh b/src/widget.hh
index d904fe33..721b13cc 100644
--- a/src/widget.hh
+++ b/src/widget.hh
@@ -74,8 +74,8 @@ public:
 
         void focus_in(GdkEventFocus *event) noexcept { m_terminal->widget_focus_in(event); }
         void focus_out(GdkEventFocus *event) noexcept { m_terminal->widget_focus_out(event); }
-        bool key_press(GdkEventKey *event) noexcept { return m_terminal->widget_key_press(event); }
-        bool key_release(GdkEventKey *event) noexcept { return m_terminal->widget_key_release(event); }
+        bool key_press(GdkEventKey *event) noexcept { return 
m_terminal->widget_key_press(key_event_from_gdk(event)); }
+        bool key_release(GdkEventKey *event) noexcept { return 
m_terminal->widget_key_release(key_event_from_gdk(event)); }
         bool button_press(GdkEventButton *event) noexcept { return m_terminal->widget_button_press(event); }
         bool button_release(GdkEventButton *event) noexcept { return 
m_terminal->widget_button_release(event); }
         void enter(GdkEventCrossing *event) noexcept { m_terminal->widget_enter(event); }
@@ -160,7 +160,7 @@ protected:
         void set_cursor(GdkCursor* cursor) noexcept;
         void set_cursor(Cursor const& cursor) noexcept;
 
-        bool im_filter_keypress(GdkEventKey* event) noexcept;
+        bool im_filter_keypress(vte::terminal::KeyEvent const& event) noexcept;
 
         void im_focus_in() noexcept;
         void im_focus_out() noexcept;
@@ -179,6 +179,9 @@ public: // FIXMEchpe
         void im_preedit_changed() noexcept;
 
 private:
+        unsigned read_modifiers_from_gdk(GdkEvent* event) const noexcept;
+        vte::terminal::KeyEvent key_event_from_gdk(GdkEventKey* event) const;
+
         GtkWidget* m_widget;
 
         vte::terminal::Terminal* m_terminal;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]