Chapter 23. Keyboard and Mouse Events

# Chapter 23. Keyboard and Mouse Events

Event signals differ in some ways from other signals. These differences are described in the Event signals section in the appendix. Here we will use keyboard events and mouse events to show how events can be used in a program.

## Overview

Whenever you press or release a key, an event is emitted. You can add an event controller and connect a signal handler to handle such events.

The event signal handler will receive arguments that depend on the type of event. For key press events the arguments are (guint `keyval`, guint `keycode`, Gdk::ModifierType `state`). As described in the appendix, the key press event signal handler returns a bool value, to indicate that the signal is fully handled (`true`) or allow event propagation (`false`).

To determine which key was pressed or released, you read the value of the `keyval` argument and compare it with a constant in the `<gdk/gdkkeysyms.h>` header file. The states of modifier keys (shift, ctrl, etc.) are available as bit-flags in `state`.

Here's a simple example:

    bool MyClass::on_key_pressed(guint keyval, guint, Gdk::ModifierType state)
    {
      if (keyval == GDK_KEY_1 &&
        (state & (Gdk::ModifierType::SHIFT_MASK | Gdk::ModifierType::CONTROL_MASK |
         Gdk::ModifierType::ALT_MASK)) == Gdk::ModifierType::ALT_MASK)
      {
        handle_alt_press();
        return true;
      }
      return false;
    }

    // in MyClass constructor
    auto controller = Gtk::EventControllerKey::create();
    controller->signal_key_pressed().connect(
      sigc::mem_fun(*this, &MyClass::on_key_pressed), false);
    add_controller(controller);

### Example

In this example there are three keyboard shortcuts: Alt+1 selects the first radio button, Alt+2 selects the second one, and the Esc key closes the window.

Figure 23.1. Keyboard Events - Simple

Source Code

File: `examplewindow.h` (For use with gtkmm 4)

    #ifndef GTKMM_EXAMPLEWINDOW_H
    #define GTKMM_EXAMPLEWINDOW_H

    #include <gtkmm.h>

    class ExampleWindow : public Gtk::Window
    {
    public:

      ExampleWindow();
      virtual ~ExampleWindow();

    private:
      // Signal handler:
      bool on_window_key_pressed(guint keyval, guint keycode, Gdk::ModifierType state);

      Gtk::Box m_container;
      Gtk::CheckButton m_first;
      Gtk::CheckButton m_second;
    };

    #endif //GTKMM_EXAMPLEWINDOW_H

File: `examplewindow.cc` (For use with gtkmm 4)

    #include "examplewindow.h"

    ExampleWindow::ExampleWindow()
    {
      set_title("Keyboard Events");
      m_container.set_margin(10);
      set_child(m_container);

      // Radio buttons:
      m_first.set_label("First");
      m_second.set_label("Second");

      m_second.set_group(m_first);
      m_first.set_active();

      // Main Container:
      m_container.set_orientation(Gtk::Orientation::HORIZONTAL);
      m_container.append(m_first);
      m_container.append(m_second);

      // Events.
      auto controller = Gtk::EventControllerKey::create();
      controller->signal_key_pressed().connect(
        sigc::mem_fun(*this, &ExampleWindow::on_window_key_pressed), false);
      add_controller(controller);
    }

    bool ExampleWindow::on_window_key_pressed(guint keyval, guint, Gdk::ModifierType state)
    {
      //Gdk::ModifierType::ALT_MASK -> the 'Alt' key(mask)
      //GDK_KEY_1 -> the '1' key
      //GDK_KEY_2 -> the '2' key

      //select the first radio button, when we press alt + 1
      if((keyval == GDK_KEY_1) &&
        (state & (Gdk::ModifierType::SHIFT_MASK | Gdk::ModifierType::CONTROL_MASK | Gdk::ModifierType::ALT_MASK)) == Gdk::ModifierType::ALT_MASK)
      {
        m_first.set_active();
        //returning true, cancels the propagation of the event
        return true;
      }
      else if((keyval == GDK_KEY_2) &&
        (state & (Gdk::ModifierType::SHIFT_MASK | Gdk::ModifierType::CONTROL_MASK | Gdk::ModifierType::ALT_MASK)) == Gdk::ModifierType::ALT_MASK)
      {
        //and the second radio button, when we press alt + 2
        m_second.set_active();
        return true;
      }
      else if(keyval == GDK_KEY_Escape)
      {
        //close the window, when the 'esc' key is pressed
        close();
        return true;
      }

      //the event has not been handled
      return false;
    }

    ExampleWindow::~ExampleWindow()
    {
    }

File: `main.cc` (For use with gtkmm 4)

    #include "examplewindow.h"
    #include <gtkmm/application.h>

    int main(int argc, char *argv[])
    {
      auto app = Gtk::Application::create("org.gtkmm.example");

      //Shows the window and returns when it is closed.
      return app->make_window_and_run<ExampleWindow>(argc, argv);
    }

FileChooser and FileDialog |  | Event Propagation