WaylandMouseInput.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include "WaylandMouseInput.h"
  2. #include "WallpaperEngine/Render/Drivers/WaylandOpenGLDriver.h"
  3. #include <glm/common.hpp>
  4. #include <chrono>
  5. #include <cstdlib>
  6. #include <cstring>
  7. #include <regex>
  8. #include <string>
  9. #include <sys/socket.h>
  10. #include <sys/time.h>
  11. #include <sys/un.h>
  12. #include <unistd.h>
  13. using namespace WallpaperEngine::Input::Drivers;
  14. WaylandMouseInput::WaylandMouseInput (const WallpaperEngine::Render::Drivers::WaylandOpenGLDriver& driver) :
  15. m_waylandDriver (driver) { }
  16. void WaylandMouseInput::update () {
  17. if (!this->m_waylandDriver.getApp ().getContext ().settings.mouse.enabled) {
  18. this->m_pos = { 0, 0 };
  19. return;
  20. }
  21. if (m_waylandDriver.viewportInFocus && m_waylandDriver.viewportInFocus->rendering) {
  22. this->m_pos = m_waylandDriver.viewportInFocus->mousePos;
  23. return;
  24. }
  25. const auto now = std::chrono::steady_clock::now ();
  26. if (now - this->m_lastHyprlandQuery < std::chrono::milliseconds (16)) {
  27. return;
  28. }
  29. this->m_lastHyprlandQuery = now;
  30. const auto globalCursor = this->queryHyprlandCursorPosition ();
  31. if (!globalCursor.has_value ()) {
  32. this->m_pos = { 0, 0 };
  33. return;
  34. }
  35. for (const auto* viewport : this->m_waylandDriver.m_screens) {
  36. if (!viewport || viewport->size.x <= 0 || viewport->size.y <= 0) {
  37. continue;
  38. }
  39. const double localX = globalCursor->x - viewport->position.x;
  40. const double localY = globalCursor->y - viewport->position.y;
  41. if (localX < 0.0 || localY < 0.0 || localX > viewport->size.x || localY > viewport->size.y) {
  42. continue;
  43. }
  44. this->m_pos = { localX * viewport->scale, (viewport->size.y - localY) * viewport->scale };
  45. return;
  46. }
  47. this->m_pos = { 0, 0 };
  48. }
  49. glm::dvec2 WaylandMouseInput::position () const {
  50. if (!this->m_waylandDriver.getApp ().getContext ().settings.mouse.enabled) {
  51. return { 0, 0 };
  52. }
  53. if (m_waylandDriver.viewportInFocus && m_waylandDriver.viewportInFocus->rendering) {
  54. return m_waylandDriver.viewportInFocus->mousePos;
  55. }
  56. return this->m_pos;
  57. }
  58. WallpaperEngine::Input::MouseClickStatus WaylandMouseInput::leftClick () const {
  59. if (m_waylandDriver.viewportInFocus && m_waylandDriver.viewportInFocus->rendering) {
  60. return m_waylandDriver.viewportInFocus->leftClick;
  61. }
  62. return MouseClickStatus::Released;
  63. }
  64. std::optional<glm::dvec2> WaylandMouseInput::queryHyprlandCursorPosition () const {
  65. const char* signature = std::getenv ("HYPRLAND_INSTANCE_SIGNATURE");
  66. const char* runtime = std::getenv ("XDG_RUNTIME_DIR");
  67. if (!signature || !runtime) {
  68. return std::nullopt;
  69. }
  70. const std::string socketPath = std::string (runtime) + "/hypr/" + signature + "/.socket.sock";
  71. int fd = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
  72. if (fd < 0) {
  73. return std::nullopt;
  74. }
  75. timeval timeout {};
  76. timeout.tv_usec = 50000;
  77. if (
  78. setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof (timeout)) != 0
  79. || setsockopt (fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof (timeout)) != 0
  80. ) {
  81. close (fd);
  82. return std::nullopt;
  83. }
  84. sockaddr_un addr {};
  85. addr.sun_family = AF_UNIX;
  86. if (socketPath.size () >= sizeof (addr.sun_path)) {
  87. close (fd);
  88. return std::nullopt;
  89. }
  90. std::strncpy (addr.sun_path, socketPath.c_str (), sizeof (addr.sun_path) - 1);
  91. if (connect (fd, reinterpret_cast<sockaddr*> (&addr), sizeof (addr)) != 0) {
  92. close (fd);
  93. return std::nullopt;
  94. }
  95. constexpr const char* request = "j/cursorpos";
  96. if (send (fd, request, std::strlen (request), 0) < 0) {
  97. close (fd);
  98. return std::nullopt;
  99. }
  100. shutdown (fd, SHUT_WR);
  101. std::string response;
  102. char buffer[256];
  103. ssize_t readBytes = 0;
  104. while ((readBytes = recv (fd, buffer, sizeof (buffer), 0)) > 0) {
  105. response.append (buffer, static_cast<std::size_t> (readBytes));
  106. }
  107. close (fd);
  108. static const std::regex xRegex (R"("x"\s*:\s*(-?\d+(?:\.\d+)?))");
  109. static const std::regex yRegex (R"("y"\s*:\s*(-?\d+(?:\.\d+)?))");
  110. std::smatch xMatch;
  111. std::smatch yMatch;
  112. if (!std::regex_search (response, xMatch, xRegex) || !std::regex_search (response, yMatch, yRegex)) {
  113. return std::nullopt;
  114. }
  115. try {
  116. return glm::dvec2 { std::stod (xMatch[1].str ()), std::stod (yMatch[1].str ()) };
  117. } catch (const std::exception&) {
  118. return std::nullopt;
  119. }
  120. }
  121. WallpaperEngine::Input::MouseClickStatus WaylandMouseInput::rightClick () const {
  122. if (m_waylandDriver.viewportInFocus && m_waylandDriver.viewportInFocus->rendering) {
  123. return m_waylandDriver.viewportInFocus->rightClick;
  124. }
  125. return MouseClickStatus::Released;
  126. }