9 #include <netinet/in.h>
10 #include <sys/select.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
27 #include <QCoreApplication>
29 #include <QKeySequence>
30 #include <QStringList>
40 #define LOC QString("LIRC: ")
42 #if !defined(__suseconds_t)
87 m_mainWindow(main_window),
88 m_lircdDevice(std::move(lircd_device)),
89 m_program(std::move(our_program)),
90 m_configFile(std::move(config_file)),
104 QObject::deleteLater();
109 QMutexLocker locker(&
m_lock);
125 static QByteArray
get_ip(
const QString &h)
127 QByteArray hba = h.toLatin1();
128 struct in_addr sin_addr {};
129 if (inet_aton(hba.constData(), &sin_addr))
132 struct addrinfo hints {};
133 hints.ai_family = AF_INET;
134 hints.ai_socktype = SOCK_STREAM;
135 hints.ai_protocol = IPPROTO_TCP;
137 struct addrinfo *result =
nullptr;
138 int err = getaddrinfo(hba.constData(),
nullptr, &hints, &result);
141 LOG(VB_GENERAL, LOG_DEBUG,
142 QString(
"get_ip: %1").arg(gai_strerror(err)));
143 return QString(
"").toLatin1();
146 int addrlen = result->ai_addrlen;
149 freeaddrinfo(result);
150 return QString(
"").toLatin1();
153 if (result->ai_addr->sa_family != AF_INET)
155 freeaddrinfo(result);
156 return QString(
"").toLatin1();
159 sin_addr = ((
struct sockaddr_in*)(result->ai_addr))->sin_addr;
160 hba = QByteArray(inet_ntoa(sin_addr));
161 freeaddrinfo(result);
168 QMutexLocker locker(&
m_lock);
172 uint64_t vtype = (0 ==
m_retryCount) ? VB_GENERAL : VB_FILE;
174 int lircd_socket = -1;
178 struct sockaddr_un addr {};
179 addr.sun_family = AF_UNIX;
180 static constexpr
int max_copy =
sizeof(addr.sun_path) - 1;
182 if (dev.size() > max_copy)
186 " is too long for the 'unix' socket API");
191 lircd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
192 if (lircd_socket < 0)
194 LOG(vtype, LOG_ERR,
LOC + QString(
"Failed to open Unix socket '%1'")
200 strncpy(addr.sun_path, dev.constData(), max_copy);
202 int ret = ::connect(lircd_socket, (
struct sockaddr*) &addr,
208 QString(
"Failed to connect to Unix socket '%1'")
217 lircd_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
218 if (lircd_socket < 0)
220 LOG(vtype, LOG_ERR,
LOC + QString(
"Failed to open TCP socket '%1'")
232 port = (
tmp[1].toUInt()) ?
tmp[1].toUInt() : port;
234 QByteArray device =
get_ip(dev);
235 struct sockaddr_in addr {};
236 addr.sin_family = AF_INET;
237 addr.sin_port = htons(port);
239 if (!inet_aton(device.constData(), &addr.sin_addr))
241 LOG(vtype, LOG_ERR,
LOC + QString(
"Failed to parse IP address '%1'")
248 int ret = ::connect(lircd_socket, (
struct sockaddr*) &addr,
253 QString(
"Failed to connect TCP socket '%1'")
263 int flags = fcntl(lircd_socket, F_GETFD);
266 ret = fcntl(lircd_socket, F_SETFD, flags |
O_NONBLOCK);
269 LOG(VB_GENERAL, LOG_WARNING,
LOC +
270 QString(
"Failed set flags for socket '%1'")
277 ret = setsockopt(lircd_socket, SOL_SOCKET, SO_OOBINLINE, &i,
sizeof(i));
280 LOG(VB_GENERAL, LOG_WARNING,
LOC +
281 QString(
"Failed setting OOBINLINE option for socket '%1'")
285 ret = setsockopt(lircd_socket, SOL_SOCKET, SO_KEEPALIVE, &i,
sizeof(i));
288 LOG(VB_GENERAL, LOG_WARNING,
LOC +
289 QString(
"Failed setting KEEPALIVE option for socket '%1'")
310 QString(
"Failed to read config file '%1'").arg(
m_configFile));
318 LOG(VB_GENERAL, LOG_INFO,
LOC +
319 QString(
"Successfully initialized '%1' using '%2' config")
327 QMutexLocker locker(&
m_lock);
331 LOG(VB_GENERAL, LOG_ERR,
"start() called without lircd socket");
341 QMutexLocker locker(&
m_lock);
350 char *code =
nullptr;
354 while ((0 == ret) && code)
356 QString lirctext(code);
357 QString qtcode = code;
358 qtcode.replace(
"ctrl-",
"ctrl+", Qt::CaseInsensitive);
359 qtcode.replace(
"alt-",
"alt+", Qt::CaseInsensitive);
360 qtcode.replace(
"shift-",
"shift+", Qt::CaseInsensitive);
361 qtcode.replace(
"meta-",
"meta+", Qt::CaseInsensitive);
362 QKeySequence a(qtcode);
369 QCoreApplication::postEvent(
372 (Qt::KeyboardModifiers)
374 QString(), lirctext));
377 std::vector<LircKeycodeEvent*> keyReleases;
379 for (
int i = 0; i < a.count(); i++)
381 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
383 Qt::KeyboardModifiers mod = Qt::NoModifier;
384 mod |= (Qt::SHIFT & keycode) ? Qt::ShiftModifier : Qt::NoModifier;
385 mod |= (Qt::META & keycode) ? Qt::MetaModifier : Qt::NoModifier;
386 mod |= (Qt::CTRL & keycode) ? Qt::ControlModifier: Qt::NoModifier;
387 mod |= (Qt::ALT & keycode) ? Qt::AltModifier : Qt::NoModifier;
389 keycode &= ~Qt::MODIFIER_MASK;
391 int keycode = a[i].key();
392 Qt::KeyboardModifiers mod = a[i].keyboardModifiers();
397 text = QString(QChar(keycode));
399 QCoreApplication::postEvent(
401 QEvent::KeyPress, keycode, mod, text, lirctext));
403 keyReleases.push_back(
405 QEvent::KeyRelease, keycode, mod, text, lirctext));
408 for (
int i = (
int)keyReleases.size() - 1; i>=0; i--)
409 QCoreApplication::postEvent(
m_mainWindow, keyReleases[i]);
420 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"run -- start");
426 std::this_thread::sleep_for(100ms);
430 QMutexLocker locker(&
m_lock);
434 LOG(VB_GENERAL, LOG_ERR,
LOC +
435 "Failed to reconnect, exiting LIRC thread.");
439 LOG(VB_FILE, LOG_WARNING,
LOC +
"EOF -- reconnecting");
448 std::this_thread::sleep_for(2s);
463 if (ret < 0 && errno != EINTR)
465 LOG(VB_GENERAL, LOG_ERR,
LOC +
"select() failed" +
ENO);
474 QList<QByteArray> codes =
GetCodes();
475 for (
const auto & code : std::as_const(codes))
479 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"run -- end");
486 QList<QByteArray> ret;
490 m_buf.resize(buf_size);
508 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"GetCodes -- EOF?");
513 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Could not read socket" +
ENO);
521 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"GetCodes -- eof?");
531 ret =
m_buf.split(
'\n');
532 if (
m_buf.endsWith(
'\n'))
538 m_buf = ret.takeLast();