mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 16:05:58 +01:00
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:
parent
98034fea3c
commit
60f81b8a23
8 changed files with 71 additions and 51 deletions
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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&);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in a new issue