mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
2 Commits
ant-remote
...
Zwift-Ride
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b56ec844d5 | ||
|
|
0eab69fb20 |
@@ -113,6 +113,8 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
}
|
||||
}
|
||||
|
||||
services << QBluetoothUuid::HumanInterfaceDevice;
|
||||
|
||||
advertisingData.setServices(services);
|
||||
//! [Advertising Data]
|
||||
|
||||
@@ -431,6 +433,38 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
serviceDataChanged.addCharacteristic(charData);
|
||||
}
|
||||
|
||||
QLowEnergyCharacteristicData reportMapChar;
|
||||
reportMapChar.setUuid(QBluetoothUuid::ReportMap);
|
||||
reportMapChar.setValue(getHIDReportDescriptor());
|
||||
reportMapChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
|
||||
// HID Information Characteristic
|
||||
QLowEnergyCharacteristicData hidInfoChar;
|
||||
hidInfoChar.setUuid(QBluetoothUuid::HIDInformation);
|
||||
QByteArray hidInfo;
|
||||
hidInfo.append((char)0x11); // HID version 1.1
|
||||
hidInfo.append((char)0x01); // Country code
|
||||
hidInfo.append((char)0x00); // Flags
|
||||
hidInfoChar.setValue(hidInfo);
|
||||
hidInfoChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
|
||||
// Report Characteristic
|
||||
QLowEnergyCharacteristicData reportChar;
|
||||
reportChar.setUuid(QBluetoothUuid::Report);
|
||||
reportChar.setProperties(QLowEnergyCharacteristic::Notify | QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write);
|
||||
QByteArray descriptor;
|
||||
descriptor.append((char)0x01);
|
||||
descriptor.append((char)0x00);
|
||||
const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::ClientCharacteristicConfiguration, descriptor);
|
||||
reportChar.addDescriptor(clientConfig);
|
||||
|
||||
// Configure service
|
||||
serviceDataHID.setType(QLowEnergyServiceData::ServiceTypePrimary);
|
||||
serviceDataHID.setUuid(QBluetoothUuid::HumanInterfaceDevice);
|
||||
serviceDataHID.addCharacteristic(reportMapChar);
|
||||
serviceDataHID.addCharacteristic(hidInfoChar);
|
||||
serviceDataHID.addCharacteristic(reportChar);
|
||||
|
||||
//! [Start Advertising]
|
||||
leController = QLowEnergyController::createPeripheral();
|
||||
Q_ASSERT(leController);
|
||||
@@ -473,6 +507,9 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
serviceHR = leController->addService(serviceDataHR);
|
||||
}
|
||||
|
||||
QThread::msleep(100); // give time to Android to add the service async.ly
|
||||
serviceHID = leController->addService(serviceDataHID);
|
||||
|
||||
if (!echelon && !ifit) {
|
||||
if (!heart_only) {
|
||||
if (!cadence && !power) {
|
||||
@@ -482,6 +519,8 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
&virtualbike::characteristicChanged);
|
||||
QObject::connect(serviceZwiftPlayBike, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualbike::characteristicChanged);
|
||||
QObject::connect(serviceHID, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualbike::characteristicChanged);
|
||||
} else {
|
||||
QObject::connect(service, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualbike::characteristicChanged);
|
||||
@@ -1345,6 +1384,9 @@ void virtualbike::reconnect() {
|
||||
|
||||
if (!this->noHeartService || heart_only)
|
||||
serviceHR = leController->addService(serviceDataHR);
|
||||
|
||||
QThread::msleep(100); // give time to Android to add the service async.ly
|
||||
serviceHID = leController->addService(serviceDataHID);
|
||||
#endif
|
||||
|
||||
QLowEnergyAdvertisingParameters pars;
|
||||
@@ -1373,6 +1415,8 @@ void virtualbike::bikeProvider() {
|
||||
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
|
||||
sendMouseReport(10, 0);
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
if (h) {
|
||||
|
||||
@@ -43,6 +43,29 @@ class virtualbike : public virtualdevice {
|
||||
return lastDirconFTMSFrameReceived;
|
||||
}
|
||||
|
||||
// Function to send mouse input reports
|
||||
void sendMouseReport(int8_t x, int8_t y, uint8_t buttons = 0, int8_t wheel = 0) {
|
||||
if (!serviceHID || !hidEnabled || leController->state() != QLowEnergyController::ConnectedState) {
|
||||
qDebug() << "HID service not available or not connected";
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray report;
|
||||
report.append(buttons); // Button state
|
||||
report.append(x); // X movement
|
||||
report.append(y); // Y movement
|
||||
report.append(wheel); // Wheel movement
|
||||
|
||||
// Find the report characteristic
|
||||
QLowEnergyCharacteristic reportChar = serviceHID->characteristic(QBluetoothUuid(quint16(0x2A4D)));
|
||||
if (!reportChar.isValid()) {
|
||||
qDebug() << "HID report characteristic not found";
|
||||
return;
|
||||
}
|
||||
|
||||
writeCharacteristic(serviceHID, reportChar, report);
|
||||
}
|
||||
|
||||
private:
|
||||
QLowEnergyController *leController = nullptr;
|
||||
QLowEnergyService *serviceHR = nullptr;
|
||||
@@ -106,6 +129,44 @@ class virtualbike : public virtualdevice {
|
||||
};
|
||||
VarintResult decodeVarint(const QByteArray& bytes, int startIndex);
|
||||
qint32 decodeSInt(const QByteArray& bytes);
|
||||
|
||||
QLowEnergyServiceData serviceDataHID;
|
||||
QLowEnergyService* serviceHID = nullptr;
|
||||
bool hidEnabled = false;
|
||||
|
||||
// HID report descriptor for mouse
|
||||
QByteArray getHIDReportDescriptor() {
|
||||
static const char reportDesc[] = {
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x02, // Usage (Mouse)
|
||||
static_cast<char>(0xA1), 0x01, // Collection (Application)
|
||||
0x09, 0x01, // Usage (Pointer)
|
||||
static_cast<char>(0xA1), 0x00, // Collection (Physical)
|
||||
0x05, 0x09, // Usage Page (Button)
|
||||
0x19, 0x01, // Usage Minimum (1)
|
||||
0x29, 0x03, // Usage Maximum (3)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
static_cast<char>(0x95), 0x03, // Report Count (3)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
static_cast<char>(0x81), 0x02, // Input (Data, Variable, Absolute)
|
||||
static_cast<char>(0x95), 0x01, // Report Count (1)
|
||||
0x75, 0x05, // Report Size (5)
|
||||
static_cast<char>(0x81), 0x01, // Input (Constant)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x38, // Usage (Wheel)
|
||||
0x15, static_cast<char>(0x81), // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
static_cast<char>(0x95), 0x03, // Report Count (3)
|
||||
static_cast<char>(0x81), 0x06, // Input (Data, Variable, Relative)
|
||||
static_cast<char>(0xC0), // End Collection
|
||||
static_cast<char>(0xC0) // End Collection
|
||||
};
|
||||
return QByteArray(reportDesc, sizeof(reportDesc));
|
||||
}
|
||||
|
||||
signals:
|
||||
void changeInclination(double grade, double percentage);
|
||||
|
||||
Reference in New Issue
Block a user