| 1631 | } |
| 1632 | |
| 1633 | QVector<Device> scanGameControllers() { |
| 1634 | QVector<Device> out; |
| 1635 | QDir base("/sys/class/power_supply"); |
| 1636 | if (!base.exists()) |
| 1637 | return out; |
| 1638 | |
| 1639 | for (const QString &entry : base.entryList( |
| 1640 | QDir::AllEntries | QDir::NoDotAndDotDot)) { |
| 1641 | QString path = QFileInfo( |
| 1642 | base.absoluteFilePath(entry)).canonicalFilePath(); |
| 1643 | QString type = readSysFile(path + "/type"); |
| 1644 | if (type != "Battery") |
| 1645 | continue; |
| 1646 | if (!isControllerBattery(path)) |
| 1647 | continue; |
| 1648 | |
| 1649 | // walk up sysfs to find the HID device name, driver, and bus type |
| 1650 | QString name; |
| 1651 | QString mfr; |
| 1652 | QString driverName; |
| 1653 | QString hidId; // "BUS:VENDOR:PRODUCT" — BUS 0005=BT, 0003=USB |
| 1654 | QString hidUniq; // unique address (BT MAC for Bluetooth devices) |
| 1655 | QDir dir(path); |
| 1656 | int depth = 0; |
| 1657 | while (dir.cdUp() && ++depth <= 20) { |
| 1658 | QString dirPath = dir.absolutePath(); |
| 1659 | QString uevent = readSysFile(dirPath + "/uevent"); |
| 1660 | for (const QString &line : uevent.split('\n')) { |
| 1661 | if (line.startsWith("HID_NAME=") && name.isEmpty()) |
| 1662 | name = line.mid(9).trimmed(); |
| 1663 | else if (line.startsWith("DRIVER=") && driverName.isEmpty()) |
| 1664 | driverName = line.mid(7).trimmed(); |
| 1665 | else if (line.startsWith("HID_ID=") && hidId.isEmpty()) |
| 1666 | hidId = line.mid(7).trimmed(); |
| 1667 | else if (line.startsWith("HID_UNIQ=") && hidUniq.isEmpty()) |
| 1668 | hidUniq = line.mid(9).trimmed(); |
| 1669 | } |
| 1670 | if (mfr.isEmpty()) { |
| 1671 | QString m = readSysFile(dirPath + "/manufacturer"); |
| 1672 | if (!m.isEmpty()) |
| 1673 | mfr = m; |
| 1674 | } |
| 1675 | if (!name.isEmpty()) break; |
| 1676 | if (dirPath == "/sys/devices") break; |
| 1677 | } |
| 1678 | |
| 1679 | if (name.isEmpty()) |
| 1680 | name = readSysFile(path + "/model_name"); |
| 1681 | if (name.isEmpty()) |
| 1682 | name = entry; |
| 1683 | |
| 1684 | // HID_UNIQ holds the BT MAC for Bluetooth devices; fall back to |
| 1685 | // extracting a MAC from the entry name for older kernel layouts. |
| 1686 | QString btAddr = hidUniq; |
| 1687 | if (btAddr.isEmpty()) { |
| 1688 | static const QRegularExpression btAddrRe( |
| 1689 | R"(([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})$)"); |
| 1690 | auto addrMatch = btAddrRe.match(entry); |
no test coverage detected