Add simple test to check `ext-input-trigger-v1` initialization

Unfortunately, WLCS doesn't actually have a way to simulate keyboard
input yet, so further testing will have to wait.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bca1a7e..e19a009 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -155,6 +155,8 @@
 GENERATE_PROTOCOL(viewporter)
 GENERATE_PROTOCOL(fractional-scale-v1)
 GENERATE_PROTOCOL(linux-dmabuf-stable-v1)
+GENERATE_PROTOCOL(ext-input-trigger-action-v1)
+GENERATE_PROTOCOL(ext-input-trigger-registration-v1)
 
 option(WLCS_BUILD_ASAN "Build a test runner with AddressSanitizer annotations" ON)
 option(WLCS_BUILD_TSAN "Build a test runner with ThreadSanitizer annotations" ON)
@@ -189,6 +191,7 @@
   tests/wp_viewporter.cpp
   tests/fractional_scale_v1.cpp
   tests/linux_dmabuf_v1.cpp
+  tests/input_trigger_v1.cpp
 )
 
 set(
@@ -338,3 +341,4 @@
   DESTINATION
     ${CMAKE_INSTALL_LIBDIR}/pkgconfig/
 )
+
diff --git a/src/protocol/ext-input-trigger-action-v1.xml b/src/protocol/ext-input-trigger-action-v1.xml
new file mode 100644
index 0000000..b0cc3c2
--- /dev/null
+++ b/src/protocol/ext-input-trigger-action-v1.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_input_trigger_action_v1">
+  <copyright>
+    Copyright 2025 Canonical Limited
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+  </copyright>
+
+  <description summary="Registration for global input actions">
+    This protocol allows for a Wayland clients to subscribe to input trigger
+    actions for "begin", "update,  and "end" notifications.
+
+    ext_input_trigger_action_v1 and the associated ext_input_trigger_registration_v1
+    are based on the following discussion document:
+    https://docs.google.com/document/d/1Hj3BXkmW1quIEWqmN7xeJY29nSPfXP2bmoZvpOsEeJQ/
+  </description>
+
+  <interface name="ext_input_trigger_action_manager_v1" version="1">
+    <description summary="used to register interest in input actions">
+      This interface allows a Wayland client to register interest in
+      input trigger actions.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy input trigger activation manager object">
+        This informs the compositor that the input trigger activation manager
+        object will no longer be used. Existing objects created through this
+        interface remain valid.
+      </description>
+    </request>
+
+    <request name="get_input_trigger_action">
+      <description summary="register interest in input trigger action">
+        This request creates an input trigger action object.
+
+        The token should be one issued by the compositor, if not then the
+        compositor can raise a protocol error.
+
+        If the token has been issued by the compositor, but is no longer
+        available, then an ext_input_trigger_action_v1.unavailable event
+        should be sent immediately.
+      </description>
+      <arg name="token" type="string" summary="the exported action token"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_action_v1"/>
+    </request>
+  </interface>
+
+  <interface name="ext_input_trigger_action_v1" version="1">
+    <description summary="receives notifications of input trigger actions">
+      The compositor sends notification of the triggering of the associated
+      action.
+    </description>
+
+    <event name="begin">
+      <description summary="begin the input action">
+        One of the input triggers associated with the action has occurred.
+
+        The app may begin the activity it associates with the action.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="activation_token" type="string" summary="an xdg_activation token"/>
+    </event>
+
+    <event name="update">
+      <description summary="progress an the input action">
+        The input trigger that led to the "begin" event has changed.
+
+        This will be sent between the "begin" and "end" events when there is a
+        meaningful update to the input trigger. (E.g. a multi-touch drag)
+
+        The app may update the activity it associates with the action.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="activation_token" type="string" summary="an xdg_activation token"/>
+      <arg name="progress" type="fixed" summary="progress normalized to [0.0, 1.0]"/>
+    </event>
+
+    <event name="end">
+      <description summary="end the input action">
+        The input trigger that led to the "begin" event has stopped.
+
+        The app may end (or begin!) the activity it associates with the action.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="activation_token" type="string" summary="an xdg_activation token"/>
+    </event>
+
+    <event name="unavailable">
+      <description summary="the input action is (or has become) unavailable">
+        Sent if the token is or becomes unavailable.
+
+        This means the object is of no further use and should be destroyed.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the input trigger activation">
+        This informs the compositor that the input trigger activation will no
+        longer be used.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/src/protocol/ext-input-trigger-registration-v1.xml b/src/protocol/ext-input-trigger-registration-v1.xml
new file mode 100644
index 0000000..5617ea4
--- /dev/null
+++ b/src/protocol/ext-input-trigger-registration-v1.xml
@@ -0,0 +1,352 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_input_trigger_registration_v1">
+  <copyright>
+    Copyright 2025 Canonical Limited
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+  </copyright>
+
+  <description summary="Registration of global input triggers and associated actions">
+    This protocol allows for a privileged Wayland client to register ownership
+    of input trigger events and associate them with actions.
+
+    ext_input_trigger_registration_v1 and the associated ext_input_trigger_action_v1
+    are based on the following discussion document:
+    https://docs.google.com/document/d/1Hj3BXkmW1quIEWqmN7xeJY29nSPfXP2bmoZvpOsEeJQ/
+  </description>
+
+  <interface name="ext_input_trigger_registration_manager_v1" version="1">
+    <description summary="used to register input triggers and actions">
+      This interface allows a Wayland client to register ownership of input
+      trigger events and associate them with actions.
+    </description>
+
+    <enum name="capability" bitfield="true">
+      <description summary="the types of inputs that support triggers">
+        This is a bitmask of capabilities this system has; if a member is
+        set, then triggers can be set.
+      </description>
+      <entry name="keyboard" value="0x01" summary="key combinations can be used as triggers"/>
+      <entry name="modifiers" value="0x02" summary="keyboard modifier taps and/or holds can be used as triggers"/>
+      <entry name="pointer" value="0x04" summary="pointer gestures can be used as triggers"/>
+      <entry name="touch_drag" value="0x08" summary="touch drag gestures can be used as triggers"/>
+      <entry name="touch_tap" value="0x10" summary="touch taps can be used as triggers"/>
+    </enum>
+
+    <event name="capabilities">
+      <description summary="input trigger capabilities">
+        This is emitted when ext_input_trigger_registration_manager_v1 is bound
+        and whenever a system gains or loses the capabilities. The argument is
+        a capability enum containing the complete set of capabilities.
+      </description>
+      <arg name="capabilities" type="uint" enum="capability" summary="types of inputs that support triggers"/>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy input trigger registration manager object">
+        This informs the compositor that the input trigger registration manager
+        object will no longer be used. Existing objects created through this
+        interface remain valid.
+      </description>
+    </request>
+
+    <enum name="modifiers" bitfield="true">
+      <description summary="modifier keys">
+        The various shift modifiers on the keyboard
+      </description>
+      <entry name="alt" value="0x01" summary="any Alt key"/>
+      <entry name="alt_left" value="0x02" summary="left Alt key"/>
+      <entry name="alt_right" value="0x04" summary="Right Alt key"/>
+      <entry name="shift" value="0x08" summary="any Shift key"/>
+      <entry name="shift_left" value="0x10" summary="left Shift key"/>
+      <entry name="shift_right" value="0x20" summary="right Shift key"/>
+      <entry name="sym" value="0x40" summary="Sym key"/>
+      <entry name="function" value="0x80" summary="Function key"/>
+      <entry name="ctrl" value="0x100" summary="any Ctrl key"/>
+      <entry name="ctrl_left" value="0x200" summary="left Ctrl key"/>
+      <entry name="ctrl_right" value="0x400" summary="right Ctrl key"/>
+      <entry name="meta" value="0x800" summary="any Meta key"/>
+      <entry name="meta_left" value="0x1000" summary="left Meta key"/>
+      <entry name="meta_right" value="0x2000" summary="right Meta key"/>
+      <!-- no need for caps/num/scroll lock? -->
+    </enum>
+
+    <request name="register_keyboard_sym_trigger">
+      <description summary="register input trigger">
+        This request creates an input trigger and asks the compositor to reserve
+        it to the manager. This allows triggering on a character key combination
+        such as "Meta+a".
+
+        The trigger begins when the combination of modifiers and keysym are
+        pressed and ends when that changes. The keysym parameter is interpreted
+        according to xkbcommon-keysyms.h.
+
+        The compositor will send either the ext_input_trigger_v1.done or
+        ext_input_trigger_v1.failed event on the created object in
+        response to this request.
+
+        Input actions triggered by this request will result in an
+        ext_input_trigger_action_v1.begin event when the key combination is
+        depressed and ext_input_trigger_action_v1.end when the key combination
+        changes.
+      </description>
+      <arg name="modifiers" type="uint" enum="modifiers"/>
+      <arg name="keysym" type="uint" summary="the key to trigger the action"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_v1"/>
+    </request>
+
+    <request name="register_keyboard_code_trigger">
+      <description summary="register input trigger">
+        This request creates an input trigger and asks the compositor to reserve
+        it to the manager. This allows triggering on a specific key combination
+        such "Alt+the-key-above-tab".
+
+        The trigger begins when the combination of modifiers and keycode are
+        pressed and ends when that changes.
+
+        The compositor will send either the ext_input_trigger_v1.done or
+        ext_input_trigger_v1.failed event on the created object in
+        response to this request.
+
+        Input actions triggered by this request will result in an
+        ext_input_trigger_action_v1.begin event when the key combination is
+        depressed and ext_input_trigger_action_v1.end when the key combination
+        changes.
+      </description>
+      <arg name="modifiers" type="uint" enum="modifiers"/>
+      <arg name="keycode" type="uint" summary="the key to trigger the action"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_v1"/>
+    </request>
+
+    <request name="register_modifier_trigger">
+      <description summary="register input trigger">
+        This request creates an input trigger and asks the compositor to reserve
+        it to the manager.
+
+        This describes a trigger based on holding or tapping one or more
+        modifier keys. As modifiers are used normally in combination with other
+        keys, the hold_delay and tap_count should not both be zero.
+
+        The compositor will send either the ext_input_trigger_v1.done or
+        ext_input_trigger_v1.failed event on the created object in
+        response to this request.
+
+        Input actions triggered by this request will result in an
+        ext_input_trigger_action_v1.begin event when triggered
+        target edge(s) and ext_input_trigger_action_v1.end when the trigger ends.
+      </description>
+      <arg name="modifiers" type="uint" enum="modifiers"/>
+      <arg name="hold_delay" type="uint" summary="minimum milliseconds pressed before triggering"/>
+      <arg name="tap_count" type="uint" summary="number of consecutive taps before triggering"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_v1"/>
+    </request>
+
+    <enum name="screen_edges" bitfield="true">
+      <description summary="edge values for pointer_trigger">
+        These values are used to indicate which edge of the screen
+        triggers a global input action.
+      </description>
+      <entry name="top" value="1" summary="top edge"/>
+      <entry name="bottom" value="2" summary="bottom edge"/>
+      <entry name="left" value="4" summary="left edge"/>
+      <entry name="top_left" value="5" summary="top left corner"/>
+      <entry name="bottom_left" value="6" summary="bottom left corner"/>
+      <entry name="right" value="8" summary="right edge"/>
+      <entry name="top_right" value="9" summary="top right corner"/>
+      <entry name="bottom_right" value="10" summary="bottom right corner"/>
+    </enum>
+
+    <request name="register_pointer_trigger">
+      <description summary="register input trigger">
+        This request creates an input trigger and asks the compositor to reserve
+        it to the manager.
+
+        The compositor will send either the ext_input_trigger_v1.done or
+        ext_input_trigger_v1.failed event on the created object in
+        response to this request.
+
+        Input actions triggered by this request will result in an
+        ext_input_trigger_action_v1.begin event when the pointer is pushed to the
+        target edge(s) and ext_input_trigger_action_v1.end when pointer moves away.
+      </description>
+      <arg name="edges" type="uint" enum="screen_edges"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_v1"/>
+    </request>
+
+    <enum name="drag_direction" bitfield="false">
+      <description summary="directions for drag">
+        These values are used to indicate which touch drag direction triggers
+        a global input action.
+      </description>
+      <entry name="up" value="1" summary="upwards"/>
+      <entry name="down" value="2" summary="downwards"/>
+      <entry name="left" value="3" summary="leftwards"/>
+      <entry name="up_left" value="4" summary="up to left"/>
+      <entry name="down_left" value="5" summary="down to left"/>
+      <entry name="right" value="6" summary="rightwards"/>
+      <entry name="up_right" value="7" summary="up to right"/>
+      <entry name="down_right" value="8" summary="down to right"/>
+    </enum>
+
+    <request name="register_touch_drag_trigger">
+      <description summary="register input trigger">
+        This request creates an input trigger and asks the compositor to reserve
+        it to the manager.
+
+        This describes a trigger based on dragging three (or more) touchpoints.
+        If advertising the touch_drag capability the compositor must support
+        three touchpoints. Fewer touchpoints are typically reserved for apps,
+        requesting more than three touchpoints may result in a failed event.
+
+        The compositor will send either the ext_input_trigger_v1.done or
+        ext_input_trigger_v1.failed event on the created object in
+        response to this request.
+
+        Input actions triggered by this request will result in an
+        ext_input_trigger_action_v1.begin event when the mult-touch moves in the
+        drag direction, ext_input_trigger_action_v1.update as move continues and
+        ext_input_trigger_action_v1.end when touches change.
+      </description>
+      <arg name="touches" type="uint" summary="number of touches"/>
+      <arg name="direction" type="uint" enum="drag_direction"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_v1"/>
+    </request>
+
+    <request name="register_touch_tap_trigger">
+      <description summary="register input trigger">
+        This request creates an input trigger and asks the compositor to reserve
+        it to the manager.
+
+        This describes a trigger based on tapping three (or more) touchpoints.
+        If advertising the touch_tap capability the compositor must support
+        three touchpoints. Fewer touchpoints are typically reserved for apps,
+        requesting more than three touchpoints may result in a failed event.
+
+        The compositor will send either the ext_input_trigger_v1.done or
+        ext_input_trigger_v1.failed event on the created object in
+        response to this request.
+
+        Input actions triggered by this request will result in an
+        ext_input_trigger_action_v1.begin and end events when the mult-touch is
+        held for at least hold_delay and released without a touch drag.
+      </description>
+      <arg name="touches" type="uint" summary="number of touches"/>
+      <arg name="hold_delay" type="uint" summary="minimum milliseconds pressed before triggering"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_v1"/>
+    </request>
+
+    <request name="get_action_control">
+      <description summary="get input trigger action control object">
+        This request creates an action control object.
+
+        The name parameter describes the action (it has no semantic content and
+        may be duplicated across actions).
+
+        The compositor will send the ext_input_trigger_action_control_v1.done event in
+        response to this request.
+      </description>
+      <arg name="name" type="string" summary="a description of the action"/>
+      <arg name="id" type="new_id" interface="ext_input_trigger_action_control_v1"/>
+    </request>
+  </interface>
+
+  <interface name="ext_input_trigger_v1" version="1">
+    <description summary="represents the (attempted) registration of an input trigger">
+      In response to the creation of this object the compositor must send
+      either the done or failed event.
+
+      The done event indicates that the trigger is "owned" by the manager.
+      This means the compositor will not allow this, or any other manager to
+      register the trigger event.
+
+      The failed event indicates that the trigger is not "owned" by the manager.
+      This the object is of no further use and should be destroyed.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the input trigger">
+        This informs the compositor that the input trigger will no longer be
+        used.
+      </description>
+    </request>
+
+    <event name="done">
+      <description summary="input trigger successfully registered">
+        This client is now responsible for handling this input trigger.
+      </description>
+    </event>
+
+    <event name="failed">
+      <description summary="input trigger failed to register">
+        The failed event indicates that the trigger is not "owned" by the manager.
+        This means the object is of no further use and should be destroyed.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="ext_input_trigger_action_control_v1" version="1">
+    <description summary="Allows configuration of an input trigger action">
+      In response to the creation of this object the compositor must send
+      the done event.
+    </description>
+
+    <request name="add_input_trigger_event">
+      <description summary="add an input trigger to the action">
+        This request adds an input trigger to those that activate the action.
+      </description>
+      <arg name="trigger" type="object" interface="ext_input_trigger_v1" summary="the trigger being added"/>
+    </request>
+
+    <request name="drop_input_trigger_event">
+      <description summary="drop an input trigger from the action">
+        This request drops an input trigger from those that activate the action.
+      </description>
+      <arg name="trigger" type="object" interface="ext_input_trigger_v1" summary="the trigger being dropped"/>
+    </request>
+
+    <event name="done">
+      <description summary="the exported action token">
+        The 'done' event contains the unique token of this action and notifies
+        that the provider is done. The action token is usable by the
+        ext_input_trigger_action_v1 protocol. The token can be used by this
+        or another client (or clients).
+      </description>
+      <arg name="token" type="string" summary="the exported action token"/>
+    </event>
+
+    <request name="cancel" type="destructor">
+      <description summary="purge the input trigger action">
+        This informs the compositor that the input trigger action will no
+        longer be used.
+
+        Any ext_input_trigger_action_v1 created from the associated token
+        by this or other clients will become unavailable.
+      </description>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the input trigger action">
+        This informs the compositor that the input trigger action will no
+        longer be used.
+        Any ext_input_trigger_action_v1 created from the associated token
+        by this or other clients will be unaffected.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/tests/input_trigger_v1.cpp b/tests/input_trigger_v1.cpp
new file mode 100644
index 0000000..ff2759b
--- /dev/null
+++ b/tests/input_trigger_v1.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2025 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Tarek Ismail <tarek.ismail@canonical.com>
+ */
+
+
+#include "generated/ext-input-trigger-registration-v1-client.h"
+#include "generated/ext-input-trigger-action-v1-client.h"
+#include "in_process_server.h"
+#include "version_specifier.h"
+
+#include "gmock/gmock.h"
+#include <xkbcommon/xkbcommon.h>
+
+using namespace testing;
+using namespace wlcs;
+
+namespace wlcs
+{
+WLCS_CREATE_INTERFACE_DESCRIPTOR(ext_input_trigger_registration_manager_v1);
+WLCS_CREATE_INTERFACE_DESCRIPTOR(ext_input_trigger_action_manager_v1);
+WLCS_CREATE_INTERFACE_DESCRIPTOR(ext_input_trigger_action_v1);
+WLCS_CREATE_INTERFACE_DESCRIPTOR(ext_input_trigger_action_control_v1);
+}
+
+class TestInputTrigger: public StartedInProcessServer
+{
+
+};
+
+TEST_F(TestInputTrigger, foo)
+{
+    Client client{the_server()};
+
+    auto const registration_manager =
+        client.bind_if_supported<ext_input_trigger_registration_manager_v1>(AtLeastVersion{1});
+    auto const action_manager = client.bind_if_supported<ext_input_trigger_action_manager_v1>(AtLeastVersion{1});
+
+    auto const trigger = ext_input_trigger_registration_manager_v1_register_keyboard_sym_trigger(
+        registration_manager,
+        EXT_INPUT_TRIGGER_REGISTRATION_MANAGER_V1_MODIFIERS_SHIFT |
+            EXT_INPUT_TRIGGER_REGISTRATION_MANAGER_V1_MODIFIERS_CTRL,
+        XKB_KEY_C);
+    ext_input_trigger_v1_listener const trigger_listener = {
+        .done =
+            [](void* data, auto* trigger)
+        {
+            (void)data;
+            (void)trigger;
+        },
+        .failed =
+            [](auto...)
+        {
+            FAIL() << "Unexpected call to ext_input_trigger_v1.failed";
+        },
+    };
+    ext_input_trigger_v1_add_listener(trigger, &trigger_listener, nullptr);
+
+    std::string action_control_token{};
+    auto const action_control =
+        ext_input_trigger_registration_manager_v1_get_action_control(registration_manager, "ctrl_alt_c");
+    ext_input_trigger_action_control_v1_listener const action_control_listener = {
+        .done = [](void* data, auto* action_control, char const* token)
+        {
+            (void)action_control;
+            auto* action_control_token = static_cast<std::string*>(data);
+            *action_control_token = std::string{token};
+        }};
+    ext_input_trigger_action_control_v1_add_listener(action_control, &action_control_listener, &action_control_token);
+
+    ext_input_trigger_action_control_v1_add_input_trigger_event(action_control, trigger);
+
+    // wait for done event with token
+    client.roundtrip();
+
+    // Make sure that we get a token
+    EXPECT_THAT(action_control_token, Not(StrEq("")));
+
+    // get corresponding action
+    auto const action =
+        ext_input_trigger_action_manager_v1_get_input_trigger_action(action_manager, action_control_token.c_str());
+
+    EXPECT_THAT(action, Ne(nullptr));
+}