Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input device updates #2510

Merged
merged 6 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pixman = dependency('pixman-1')
xkbcommon = dependency('xkbcommon')
libdl = meson.get_compiler('cpp').find_library('dl')
json = dependency('nlohmann_json', version: '>= 3.11.2')
udev = dependency('libudev')

# We're not to use system wlroots: So we'll use the subproject
if get_option('use_system_wlroots').disabled()
Expand Down
5 changes: 5 additions & 0 deletions metadata/input-device.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,10 @@
<option name="output" type="string">
<default></default>
</option>
<option name="calibration" type="string">
<_short>Calibration matrix</_short>
<_long>Calibration matrix for touch devices, uses udev/libinput format (2x3 matrix, 6 floats separated by space).</_long>
<default></default>
</option>
</object>
</wayfire>
6 changes: 3 additions & 3 deletions src/api/wayfire/config-backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ class config_backend_t
/**
* Find the output section for a given input device.
*
* The returned section must be a valid output object as
* described in input-device.xml
* The returned section must be a valid config object as described
* in <@prefix>.xml (typically input.xml or input-device.xml).
*/
virtual std::shared_ptr<config::section_t> get_input_device_section(
wlr_input_device *device);
std::string const & prefix, wlr_input_device *device);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs API/ABI version bump :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, I forgot to bump! :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you must have forgotten to push a commit upstream, because this also hasn't been resolved ...


virtual ~config_backend_t() = default;

Expand Down
26 changes: 14 additions & 12 deletions src/api/wayfire/debug.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,31 @@ namespace log
enum class logging_category : size_t
{
// Transactions - general
TXN = 0,
TXN = 0,
// Transactions - individual objects
TXNI = 1,
TXNI = 1,
// Views - events
VIEWS = 2,
VIEWS = 2,
// Wlroots messages
WLR = 3,
WLR = 3,
// Direct scanout
SCANOUT = 4,
SCANOUT = 4,
// Pointer events
POINTER = 5,
POINTER = 5,
// Workspace set events
WSET = 6,
WSET = 6,
// Keyboard-related events
KBD = 7,
KBD = 7,
// Xwayland-related events
XWL = 8,
XWL = 8,
// Layer-shell-related events
LSHELL = 9,
LSHELL = 9,
// Input-Method-related events
IM = 10,
IM = 10,
// Rendering-related events
RENDER = 11,
RENDER = 11,
// Input-device-related events
INPUT_DEVICES = 12,
TOTAL,
};

Expand Down
2 changes: 1 addition & 1 deletion src/api/wayfire/plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class plugin_interface_t
using wayfire_plugin_load_func = wf::plugin_interface_t * (*)();

/** The version of Wayfire's API/ABI */
constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2024'12'20;
constexpr uint32_t WAYFIRE_API_ABI_VERSION = 2025'02'18;

/**
* Each plugin must also provide a function which returns the Wayfire API/ABI
Expand Down
2 changes: 1 addition & 1 deletion src/core/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ void wf::compositor_core_impl_t::post_init()
seat->focus_output(wo);

// Refresh device mappings when we have all outputs and devices
input->refresh_device_mappings();
input->configure_input_devices();

// Start processing cursor events
seat->priv->cursor->setup_listeners();
Expand Down
66 changes: 60 additions & 6 deletions src/core/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "wayfire/signal-definitions.hpp"
#include <wayfire/util/log.hpp>
#include <wayfire/config-backend.hpp>
#include <libudev.h>

void wf::plugin_interface_t::fini()
{}
Expand All @@ -27,18 +28,71 @@ std::shared_ptr<config::section_t> wf::config_backend_t::get_output_section(
return config.get_section(name);
}

static struct udev_property_and_desc
{
char const *property_name;
char const *description;
} properties_and_descs[] =
{
{"ID_PATH", "stable physical connection path"},
{"ID_SERIAL", "stable vendor+pn+sn info"},
{"LIBINPUT_DEVICE_GROUP", "stable libinput info"},
// sometimes it contains info "by path", sometimes "by id"
{"DEVPATH", "unstable devpath"},
// used for debugging, to find DEVPATH and match the right
// device in `udevadm info --tree`
};

std::shared_ptr<config::section_t> wf::config_backend_t::get_input_device_section(
wlr_input_device *device)
std::string const & prefix, wlr_input_device *device)
{
std::string name = nonull(device->name);
name = "input-device:" + name;
auto& config = wf::get_core().config;
if (!config.get_section(name))
std::shared_ptr<wf::config::section_t> section;

if (wlr_input_device_is_libinput(device))
{
config.merge_section(
config.get_section("input-device")->clone_with_name(name));
auto libinput_dev = wlr_libinput_get_device_handle(device);
if (libinput_dev)
{
udev_device *udev_dev = libinput_device_get_udev_device(libinput_dev);
if (udev_dev)
{
for (struct udev_property_and_desc const & pd : properties_and_descs)
{
const char *value = udev_device_get_property_value(udev_dev, pd.property_name);
if (value == nullptr)
{
continue;
}

std::string name = prefix + ":" + nonull(value);
LOGC(INPUT_DEVICES, "Checking for config section [", name, "] ",
pd.property_name, " (", pd.description, ")");
section = config.get_section(name);
if (section)
{
LOGC(INPUT_DEVICES, "Using config section [", name, "] for ", nonull(device->name));
return section;
}
}
}
}
}

std::string name = nonull(device->name);
name = prefix + ":" + name;
LOGC(INPUT_DEVICES, "Checking for config section [", name, "]");
section = config.get_section(name);
if (section)
{
LOGC(INPUT_DEVICES, "Using config section [", name, "]");
return section;
}

config.merge_section(
config.get_section(prefix)->clone_with_name(name));

LOGC(INPUT_DEVICES, "Using config section [", name, "]");
return config.get_section(name);
}

Expand Down
86 changes: 46 additions & 40 deletions src/core/seat/input-manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
#include "wayfire/core.hpp"
#include "wayfire/signal-definitions.hpp"
#include "../core-impl.hpp"
#include "../../output/output-impl.hpp"
#include "touch.hpp"
#include "keyboard.hpp"
#include "cursor.hpp"
#include "input-manager.hpp"
#include "wayfire/output-layout.hpp"
#include "wayfire/view.hpp"
#include "wayfire/workspace-set.hpp"
#include <wayfire/util/log.hpp>
#include <wayfire/debug.hpp>

Expand Down Expand Up @@ -52,53 +49,64 @@ void wf::input_manager_t::handle_new_input(wlr_input_device *dev)
data.device = nonstd::make_observer(input_devices.back().get());
wf::get_core().emit(&data);

refresh_device_mappings();
configure_input_devices();
}

void wf::input_manager_t::refresh_device_mappings()
void wf::input_manager_t::configure_input_device(std::unique_ptr<wf::input_device_impl_t> & device)
{
// Might trigger motion events which we want to avoid at other stages
auto state = wf::get_core().get_current_state();
if (state != wf::compositor_state_t::RUNNING)
auto dev = device->get_wlr_handle();
auto cursor = wf::get_core().get_wlr_cursor();
auto section =
wf::get_core().config_backend->get_input_device_section("input-device", dev);

auto calibration_matrix = section->get_option("calibration")->get_value_str();
if (!calibration_matrix.empty())
{
return;
device->calibrate_touch_device(calibration_matrix);
}

auto cursor = wf::get_core().get_wlr_cursor();
for (auto& device : this->input_devices)
auto mapped_output = section->get_option("output")->get_value_str();
if (mapped_output.empty())
{
wlr_input_device *dev = device->get_wlr_handle();
auto section =
wf::get_core().config_backend->get_input_device_section(dev);

auto mapped_output = section->get_option("output")->get_value_str();
if (mapped_output.empty())
if (dev->type == WLR_INPUT_DEVICE_POINTER)
{
if (dev->type == WLR_INPUT_DEVICE_POINTER)
{
mapped_output = nonull(wlr_pointer_from_input_device(
dev)->output_name);
} else if (dev->type == WLR_INPUT_DEVICE_TOUCH)
{
mapped_output =
nonull(wlr_touch_from_input_device(dev)->output_name);
} else
{
mapped_output = nonull(dev->name);
}
}

auto wo = wf::get_core().output_layout->find_output(mapped_output);
if (wo)
mapped_output = nonull(wlr_pointer_from_input_device(
dev)->output_name);
} else if (dev->type == WLR_INPUT_DEVICE_TOUCH)
{
LOGD("Mapping input ", dev->name, " to output ", wo->to_string(), ".");
wlr_cursor_map_input_to_output(cursor, dev, wo->handle);
mapped_output =
nonull(wlr_touch_from_input_device(dev)->output_name);
} else
{
LOGD("Mapping input ", dev->name, " to output null.");
wlr_cursor_map_input_to_output(cursor, dev, nullptr);
mapped_output = nonull(dev->name);
}
}

auto wo = wf::get_core().output_layout->find_output(mapped_output);
if (wo)
{
LOGC(INPUT_DEVICES, "Mapping input ", dev->name, " to output ", wo->to_string(), ".");
wlr_cursor_map_input_to_output(cursor, dev, wo->handle);
} else
{
LOGC(INPUT_DEVICES, "Mapping input ", dev->name, " to output null.");
wlr_cursor_map_input_to_output(cursor, dev, nullptr);
}
}

void wf::input_manager_t::configure_input_devices()
{
// Might trigger motion events which we want to avoid at other stages
auto state = wf::get_core().get_current_state();
if (state != wf::compositor_state_t::RUNNING)
{
return;
}

for (auto& device : this->input_devices)
{
configure_input_device(device);
}
}

void wf::input_manager_t::handle_input_destroyed(wlr_input_device *dev)
Expand Down Expand Up @@ -141,8 +149,6 @@ void load_locked_mods_from_config(xkb_mod_mask_t& locked_mods)

wf::input_manager_t::input_manager_t()
{
wf::pointing_device_t::config.load();

load_locked_mods_from_config(locked_mods);

input_device_created.set_callback([&] (void *data)
Expand Down Expand Up @@ -170,7 +176,7 @@ wf::input_manager_t::input_manager_t()
ev->output->set_inhibited(true);
}

refresh_device_mappings();
configure_input_devices();
});
wf::get_core().output_layout->connect(&output_added);
}
Expand Down
8 changes: 7 additions & 1 deletion src/core/seat/input-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ class input_manager_t
*/
uint32_t locked_mods = 0;

/**
* Map a single input device to output as specified in the
* config file or by hints in the wlroots backend.
*/
void configure_input_device(std::unique_ptr<wf::input_device_impl_t> & device);

/**
* Go through all input devices and map them to outputs as specified in the
* config file or by hints in the wlroots backend.
*/
void refresh_device_mappings();
void configure_input_devices();

input_manager_t();
~input_manager_t() = default;
Expand Down
20 changes: 12 additions & 8 deletions src/core/seat/keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,18 @@ void wf::keyboard_t::setup_listeners()
wf::keyboard_t::keyboard_t(wlr_input_device *dev) :
handle(wlr_keyboard_from_input_device(dev)), device(dev)
{
model.load_option("input/xkb_model");
variant.load_option("input/xkb_variant");
layout.load_option("input/xkb_layout");
options.load_option("input/xkb_options");
rules.load_option("input/xkb_rules");

repeat_rate.load_option("input/kb_repeat_rate");
repeat_delay.load_option("input/kb_repeat_delay");
auto section =
wf::get_core().config_backend->get_input_device_section("input", dev);
auto section_name = section->get_name();

model.load_option(section_name + "/xkb_model");
variant.load_option(section_name + "/xkb_variant");
layout.load_option(section_name + "/xkb_layout");
options.load_option(section_name + "/xkb_options");
rules.load_option(section_name + "/xkb_rules");

repeat_rate.load_option(section_name + "/kb_repeat_rate");
repeat_delay.load_option(section_name + "/kb_repeat_delay");

// When the configuration options change, mark them as dirty.
// They are applied at the config-reloaded signal.
Expand Down
5 changes: 2 additions & 3 deletions src/core/seat/pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,8 @@ void wf::pointer_t::handle_pointer_axis(wlr_pointer_axis_event *ev,
}

/* Calculate speed settings */
double mult = ev->source == WL_POINTER_AXIS_SOURCE_FINGER ?
wf::pointing_device_t::config.touchpad_scroll_speed :
wf::pointing_device_t::config.mouse_scroll_speed;
wf::pointing_device_t *pd = (wf::pointing_device_t*)ev->pointer->base.data;
double mult = pd->get_scroll_speed(&ev->pointer->base, ev->source == WL_POINTER_AXIS_SOURCE_FINGER);

ev->delta *= mult;
ev->delta_discrete *= mult;
Expand Down
Loading