input: Map touch devices and tablets bound to an output (#3544)

* Map bound touch devices and tablets to an output

* Add "[[Auto]]" default option for auto detecting outputs for touch inputs

* Bind new monitors to configured touch and tablet devices

* Use Monitor::matchesStaticSelector in CConfigManager::getMonitorRuleFor

* Use Monitor::matchesStaticSelector in CCompositor::getMonitorFromString
This commit is contained in:
Philip Damianik 2024-02-27 23:11:59 +01:00 committed by GitHub
parent 98034fea3c
commit 60f81b8a23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 71 additions and 51 deletions

View file

@ -2080,7 +2080,11 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
} }
CMonitor* CCompositor::getMonitorFromString(const std::string& name) { CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
if (name[0] == '+' || name[0] == '-') { if (name == "current")
return g_pCompositor->m_pLastMonitor;
else if (isDirection(name))
return getMonitorInDirection(name[0]);
else if (name[0] == '+' || name[0] == '-') {
// relative // relative
if (m_vMonitors.size() == 1) if (m_vMonitors.size() == 1)
@ -2135,33 +2139,15 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1"); Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1");
return nullptr; return nullptr;
} }
} else if (name.starts_with("desc:")) { } else {
const auto DESCRIPTION = name.substr(5);
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
if (!m->output) if (!m->output)
continue; continue;
if (m->szDescription.starts_with(DESCRIPTION)) { if (m->matchesStaticSelector(name)) {
return m.get(); return m.get();
} }
} }
return nullptr;
} else {
if (name == "current")
return g_pCompositor->m_pLastMonitor;
if (isDirection(name)) {
const auto PMONITOR = getMonitorInDirection(name[0]);
return PMONITOR;
} else {
for (auto& m : m_vMonitors) {
if (m->szName == name) {
return m.get();
}
}
}
} }
return nullptr; return nullptr;

View file

@ -465,7 +465,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("input:touchpad:drag_lock", {0L}); m_pConfig->addConfigValue("input:touchpad:drag_lock", {0L});
m_pConfig->addConfigValue("input:touchpad:scroll_factor", {1.f}); m_pConfig->addConfigValue("input:touchpad:scroll_factor", {1.f});
m_pConfig->addConfigValue("input:touchdevice:transform", {0L}); m_pConfig->addConfigValue("input:touchdevice:transform", {0L});
m_pConfig->addConfigValue("input:touchdevice:output", {STRVAL_EMPTY}); m_pConfig->addConfigValue("input:touchdevice:output", {"[[Auto]]"});
m_pConfig->addConfigValue("input:touchdevice:enabled", {1L}); m_pConfig->addConfigValue("input:touchdevice:enabled", {1L});
m_pConfig->addConfigValue("input:tablet:transform", {0L}); m_pConfig->addConfigValue("input:tablet:transform", {0L});
m_pConfig->addConfigValue("input:tablet:output", {STRVAL_EMPTY}); m_pConfig->addConfigValue("input:tablet:output", {STRVAL_EMPTY});
@ -907,33 +907,21 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s
return VAL; return VAL;
} }
SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const std::string& displayName) { SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
SMonitorRule* found = nullptr;
for (auto& r : m_dMonitorRules) { for (auto& r : m_dMonitorRules) {
if (r.name == name || if (PMONITOR.matchesStaticSelector(r.name)) {
(r.name.starts_with("desc:") && return r;
(r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
found = &r;
break;
} }
} }
if (found) Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName);
return *found;
Debug::log(WARN, "No rule found for {}, trying to use the first.", name);
for (auto& r : m_dMonitorRules) { for (auto& r : m_dMonitorRules) {
if (r.name == "") { if (r.name == "") {
found = &r; return r;
break;
} }
} }
if (found)
return *found;
Debug::log(WARN, "No rules configured. Using the default hardcoded one."); Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-INT32_MAX, -INT32_MAX), .scale = -1}; // 0, 0 is preferred and -1, -1 is auto return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-INT32_MAX, -INT32_MAX), .scale = -1}; // 0, 0 is preferred and -1, -1 is auto
@ -1173,7 +1161,7 @@ void CConfigManager::performMonitorReload() {
if (!m->output || m->isUnsafeFallback) if (!m->output || m->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(m->szName, m->szDescription); auto rule = getMonitorRuleFor(*m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true; overAgain = true;
@ -1230,7 +1218,7 @@ void CConfigManager::ensureMonitorStatus() {
if (!rm->output || rm->isUnsafeFallback) if (!rm->output || rm->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(rm->szName, rm->szDescription); auto rule = getMonitorRuleFor(*rm);
if (rule.disabled == rm->m_bEnabled) if (rule.disabled == rm->m_bEnabled)
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);

View file

@ -102,7 +102,7 @@ class CConfigManager {
static std::string getConfigDir(); static std::string getConfigDir();
static std::string getMainConfigPath(); static std::string getMainConfigPath();
SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = ""); SMonitorRule getMonitorRuleFor(const CMonitor&);
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*); SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
std::string getDefaultWorkspaceFor(const std::string&); std::string getDefaultWorkspaceFor(const std::string&);

View file

@ -64,7 +64,7 @@ void CMonitor::onConnect(bool noRule) {
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : ""); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
@ -142,6 +142,20 @@ void CMonitor::onConnect(bool noRule) {
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
for (const auto& PTOUCHDEV : g_pInputManager->m_lTouchDevices) {
if (matchesStaticSelector(PTOUCHDEV.boundOutput)) {
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV.name, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTOUCHDEV.pWlrDevice, output);
}
}
for (const auto& PTABLET : g_pInputManager->m_lTablets) {
if (matchesStaticSelector(PTABLET.boundOutput)) {
Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
}
}
if (!state.commit()) if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit"); Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
@ -343,6 +357,19 @@ bool CMonitor::isMirror() {
return pMirrorOf != nullptr; return pMirrorOf != nullptr;
} }
bool CMonitor::matchesStaticSelector(const std::string& selector) const {
if (selector.starts_with("desc:")) {
// match by description
const auto DESCRIPTIONSELECTOR = selector.substr(5);
const auto DESCRIPTION = removeBeginEndSpacesTabs(szDescription.substr(0, szDescription.find_first_of('(')));
return DESCRIPTIONSELECTOR == szDescription || DESCRIPTIONSELECTOR == DESCRIPTION;
} else {
// match by selector
return szName == selector;
}
}
int CMonitor::findAvailableDefaultWS() { int CMonitor::findAvailableDefaultWS() {
for (size_t i = 1; i < INT32_MAX; ++i) { for (size_t i = 1; i < INT32_MAX; ++i) {
if (g_pCompositor->getWorkspaceByID(i)) if (g_pCompositor->getWorkspaceByID(i))
@ -422,7 +449,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr; pMirrorOf = nullptr;
// set rule // set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : ""); const auto RULE = g_pConfigManager->getMonitorRuleFor(*this);
vecPosition = RULE.offset; vecPosition = RULE.offset;

View file

@ -140,6 +140,7 @@ class CMonitor {
void addDamage(const CBox* box); void addDamage(const CBox* box);
void setMirror(const std::string&); void setMirror(const std::string&);
bool isMirror(); bool isMirror();
bool matchesStaticSelector(const std::string& selector) const;
float getDefaultScale(); float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false); void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false); void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);

View file

@ -259,6 +259,8 @@ struct STablet {
std::string name = ""; std::string name = "";
std::string boundOutput = "";
// //
bool operator==(const STablet& b) const { bool operator==(const STablet& b) const {
return wlrDevice == b.wlrDevice; return wlrDevice == b.wlrDevice;

View file

@ -1632,7 +1632,7 @@ void CKeybindManager::forceRendererReload(std::string args) {
if (!m->output) if (!m->output)
continue; continue;
auto rule = g_pConfigManager->getMonitorRuleFor(m->szName, m->szDescription); auto rule = g_pConfigManager->getMonitorRuleFor(*m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) {
overAgain = true; overAgain = true;
break; break;

View file

@ -1491,14 +1491,27 @@ void CInputManager::setTouchDeviceConfigs(STouchDevice* dev) {
libinput_device_config_send_events_set_mode(LIBINPUTDEV, mode); libinput_device_config_send_events_set_mode(LIBINPUTDEV, mode);
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7); const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7);
Debug::log(LOG, "Setting calibration matrix for device {}", PTOUCHDEV->name);
if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV)) if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV))
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]); libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
const auto OUTPUT = g_pConfigManager->getDeviceString(PTOUCHDEV->name, "output", "input:touchdevice:output"); auto output = g_pConfigManager->getDeviceString(PTOUCHDEV->name, "output", "input:touchdevice:output");
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY) bool bound = !output.empty() && output != STRVAL_EMPTY;
PTOUCHDEV->boundOutput = OUTPUT; const bool AUTODETECT = output == "[[Auto]]";
else if (!bound && AUTODETECT) {
PTOUCHDEV->boundOutput = ""; const auto DEFAULTOUTPUT = wlr_touch_from_input_device(PTOUCHDEV->pWlrDevice)->output_name;
if (DEFAULTOUTPUT) {
output = DEFAULTOUTPUT;
bound = true;
}
}
PTOUCHDEV->boundOutput = bound ? output : "";
const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr;
if (PMONITOR) {
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->name, PMONITOR->szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTOUCHDEV->pWlrDevice, PMONITOR->output);
} else if (bound)
Debug::log(ERR, "Failed to bind touch device {} to output '{}': monitor not found", PTOUCHDEV->name, output);
} }
}; };
@ -1529,9 +1542,12 @@ void CInputManager::setTabletConfigs() {
const auto OUTPUT = g_pConfigManager->getDeviceString(t.name, "output", "input:tablet:output"); const auto OUTPUT = g_pConfigManager->getDeviceString(t.name, "output", "input:tablet:output");
const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT); const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT);
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) { if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) {
Debug::log(LOG, "Binding tablet {} to output {}", t.name, PMONITOR->szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output); wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output);
wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr); wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr);
} t.boundOutput = OUTPUT;
} else if (!PMONITOR)
Debug::log(ERR, "Failed to bind tablet {} to output '{}': monitor not found", t.name, OUTPUT);
const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position"); const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position");
const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size"); const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size");