From 20154d1e95a72631fca5c22e39bfaf04884bf15e Mon Sep 17 00:00:00 2001 From: Hayodea Hakol Date: Tue, 14 Jan 2025 20:59:28 -0400 Subject: [PATCH] xcbXorg: Use apiParams to choose match method for window attachment We now use param keys in the API params to choose what type of ID the deviceSelector holds, and how to match it. * dev-id/devid: matches by ID. * dev-substr/dev-substring/devsubstr: Matches window name by substring. * dev-string/devstr/dev-str: matches window name by exact whole string. --- senseApis/xcbXorg/xcbXorg.cpp | 94 ++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 29 deletions(-) diff --git a/senseApis/xcbXorg/xcbXorg.cpp b/senseApis/xcbXorg/xcbXorg.cpp index 267cc3a..4d9ea61 100644 --- a/senseApis/xcbXorg/xcbXorg.cpp +++ b/senseApis/xcbXorg/xcbXorg.cpp @@ -127,12 +127,15 @@ namespace xcb_window_search { void operator()(xcb_get_property_reply_t* p) { free(p); } }; + enum class MatchType { SUBSTRING, EXACT, ID }; + static xcb_window_t findById( xcb_connection_t* conn, xcb_window_t root, uint32_t targetId); static xcb_window_t findByName( xcb_connection_t* conn, xcb_window_t root, - const std::string& targetName, std::string& outWindowName); + const std::string& targetName, std::string& outWindowName, + MatchType matchType); } class AttachedDevice @@ -140,23 +143,31 @@ class AttachedDevice public: struct WindowSelector { + xcb_window_search::MatchType matchType; + XcbConnection::XConnectionIdentifier xconn; struct { uint32_t id; std::string name; } window; - bool useWindowId; std::string stringify() const { std::ostringstream os; - os << "Display: " << xconn.display - << ", Screen: " << xconn.screen - << ", Window: " << (useWindowId - ? std::to_string(window.id) - : "\"" + window.name + "\""); + << ", Screen: " << xconn.screen << ", Window: "; + if (matchType == xcb_window_search::MatchType::ID) { + os << window.id; + } else { + os << "\"" << window.name << "\""; + } + os << " (matchType=" + << (matchType == xcb_window_search::MatchType::EXACT + ? "exact" : + (matchType == xcb_window_search::MatchType::SUBSTRING) + ? "substring" : "id") + << ")"; return os.str(); } }; @@ -169,7 +180,7 @@ public: { windowSelector.xconn.display = getRequiredParamAsInt(spec, "display"); windowSelector.xconn.screen = getRequiredParamAsInt(spec, "screen"); - parseWindowSelector(spec.deviceSelector, windowSelector); + parseWindowSelector(spec, windowSelector); // Get the root window const xcb_setup_t* setup = xcb_get_setup(connection->connection.get()); @@ -181,7 +192,7 @@ public: // Search for window xcb_window_t targetWindow = 0; - if (windowSelector.useWindowId) + if (windowSelector.matchType == xcb_window_search::MatchType::ID) { targetWindow = xcb_window_search::findById( connection->connection.get(), root, windowSelector.window.id); @@ -190,14 +201,15 @@ public: { targetWindow = xcb_window_search::findByName( connection->connection.get(), root, - windowSelector.window.name, actualWindowName); + windowSelector.window.name, actualWindowName, + windowSelector.matchType); } if (!targetWindow) { throw std::runtime_error( "Failed to find window " - + (windowSelector.useWindowId + + (windowSelector.matchType == xcb_window_search::MatchType::ID ? std::to_string(windowSelector.window.id) : "\"" + windowSelector.window.name + "\"") + " on display " + std::to_string(windowSelector.xconn.display) @@ -239,30 +251,47 @@ public: } static void parseWindowSelector( - const std::string& selector, + const hk::device::SenseDeviceSpec& spec, WindowSelector& windowSelector) { - if (selector.length() >= 2 && - ((selector[0] == '"' && selector.back() == '"') || - (selector[0] == '\'' && selector.back() == '\'') || - (selector[0] == '`' && selector.back() == '`'))) + // Default match type + windowSelector.matchType = xcb_window_search::MatchType::SUBSTRING; + + // Check if 'dev-id', 'dev-string', or 'dev-substring' is specified + for (const auto& param : spec.apiParams) { - windowSelector.window.name = selector.substr( - 1, selector.length() - 2); - windowSelector.useWindowId = false; + if (param.first == "dev-id" || param.first == "devid") + { + windowSelector.matchType = xcb_window_search::MatchType::ID; + break; + } + if (param.first == "dev-string" + || param.first == "dev-str" || param.first == "devstr") + { + windowSelector.matchType = xcb_window_search::MatchType::EXACT; + } + if (param.first == "dev-substring" + || param.first == "dev-substr" || param.first == "devsubstr") + { + windowSelector.matchType = xcb_window_search:: + MatchType::SUBSTRING; + } } - else + + if (windowSelector.matchType == xcb_window_search::MatchType::ID) { try { - // Allow hex numbers - windowSelector.window.id = std::stoul(selector, nullptr, 0); - windowSelector.useWindowId = true; + windowSelector.window.id = std::stoul( + spec.deviceSelector, nullptr, 0); } catch (const std::exception&) { throw std::runtime_error( - "Window selector must be either a quoted string or a " - "numeric ID"); + "Window selector: 'dev-id' present, but selector is not " + "numeric"); } } + else { + windowSelector.window.name = spec.deviceSelector; + } } }; @@ -310,7 +339,8 @@ static xcb_window_t findById( static xcb_window_t findByName( xcb_connection_t* conn, xcb_window_t root, - const std::string& targetName, std::string& outWindowName) + const std::string& targetName, std::string& outWindowName, + MatchType matchType) { xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root); std::unique_ptr reply( @@ -332,7 +362,10 @@ static xcb_window_t findByName( if (len > 0) { std::string windowName(name, len); - if (windowName == targetName) + if ((matchType == MatchType::EXACT + && windowName == targetName) + || (matchType == MatchType::SUBSTRING + && windowName.find(targetName) != std::string::npos)) { outWindowName = windowName; return root; @@ -359,7 +392,10 @@ static xcb_window_t findByName( if (len > 0) { std::string windowName(name, len); - if (windowName == targetName) + if ((matchType == MatchType::EXACT + && windowName == targetName) + || (matchType == MatchType::SUBSTRING + && windowName.find(targetName) != std::string::npos)) { outWindowName = windowName; return children[i]; @@ -369,7 +405,7 @@ static xcb_window_t findByName( // Recursively search this child's subtree if (xcb_window_t result = findByName( - conn, children[i], targetName, outWindowName)) + conn, children[i], targetName, outWindowName, matchType)) { return result; }