mirror of
https://github.com/jonasbark/swiftcontrol.git
synced 2026-02-18 00:17:40 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1b8822e20 | ||
|
|
6bf83b1034 |
@@ -1,3 +1,6 @@
|
||||
#### 2.0.4 (2025-04-10)
|
||||
- vibrate Zwift Play / Zwift Ride controller on gear shift (thanks @cagnulein, closes #16)
|
||||
|
||||
#### 2.0.3 (2025-04-08)
|
||||
- adjust TrainingPeaks Virtual key mapping (#12)
|
||||
- attempt to reconnect device if connection is lost
|
||||
|
||||
@@ -35,7 +35,9 @@ Get the latest version here: https://github.com/jonasbark/swiftcontrol/releases
|
||||
## Supported Platforms
|
||||
- Android
|
||||
- macOS
|
||||
- Windows (make sure you have installed the "[Microsoft Visual C++ Runtime libraries](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170)")
|
||||
- Windows
|
||||
- make sure you have installed the "[Microsoft Visual C++ Runtime libraries](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170)"
|
||||
- Windows may flag the app as virus. I think it does so because the app does control the mouse and keyboard.
|
||||
- [Web](https://jonasbark.github.io/swiftcontrol/) (you won't be able to do much)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -23,6 +23,7 @@ class Constants {
|
||||
static const BC1 = 0x09;
|
||||
|
||||
static final RIDE_ON = Uint8List.fromList([0x52, 0x69, 0x64, 0x65, 0x4f, 0x6e]);
|
||||
static final VIBRATE_PATTERN = Uint8List.fromList([0x12, 0x12, 0x08, 0x0A, 0x06, 0x08, 0x02, 0x10, 0x00, 0x18]);
|
||||
|
||||
// these don't actually seem to matter, its just the header has to be 7 bytes RIDEON + 2
|
||||
static final REQUEST_START = Uint8List.fromList([0, 9]); //byteArrayOf(1, 2)
|
||||
|
||||
@@ -27,6 +27,7 @@ abstract class BaseDevice {
|
||||
|
||||
bool supportsEncryption = true;
|
||||
|
||||
BleCharacteristic? syncRxCharacteristic;
|
||||
Timer? _longPressTimer;
|
||||
|
||||
List<int> get startCommand => Constants.RIDE_ON + Constants.RESPONSE_START_CLICK;
|
||||
@@ -114,7 +115,7 @@ abstract class BaseDevice {
|
||||
final syncTxCharacteristic = customService.characteristics.firstOrNullWhere(
|
||||
(characteristic) => characteristic.uuid == BleUuid.ZWIFT_SYNC_TX_CHARACTERISTIC_UUID,
|
||||
);
|
||||
final syncRxCharacteristic = customService.characteristics.firstOrNullWhere(
|
||||
syncRxCharacteristic = customService.characteristics.firstOrNullWhere(
|
||||
(characteristic) => characteristic.uuid == BleUuid.ZWIFT_SYNC_RX_CHARACTERISTIC_UUID,
|
||||
);
|
||||
|
||||
@@ -135,15 +136,15 @@ abstract class BaseDevice {
|
||||
BleInputProperty.indication,
|
||||
);
|
||||
|
||||
await _setupHandshake(syncRxCharacteristic);
|
||||
await _setupHandshake();
|
||||
}
|
||||
|
||||
Future<void> _setupHandshake(BleCharacteristic syncRxCharacteristic) async {
|
||||
Future<void> _setupHandshake() async {
|
||||
if (supportsEncryption) {
|
||||
await UniversalBle.writeValue(
|
||||
device.deviceId,
|
||||
customServiceId,
|
||||
syncRxCharacteristic.uuid,
|
||||
syncRxCharacteristic!.uuid,
|
||||
Uint8List.fromList([
|
||||
...Constants.RIDE_ON,
|
||||
...Constants.REQUEST_START,
|
||||
@@ -155,7 +156,7 @@ abstract class BaseDevice {
|
||||
await UniversalBle.writeValue(
|
||||
device.deviceId,
|
||||
customServiceId,
|
||||
syncRxCharacteristic.uuid,
|
||||
syncRxCharacteristic!.uuid,
|
||||
Constants.RIDE_ON,
|
||||
BleOutputProperty.withoutResponse,
|
||||
);
|
||||
@@ -246,15 +247,11 @@ abstract class BaseDevice {
|
||||
// we don't want to trigger the long press timer for the on/off buttons
|
||||
_longPressTimer?.cancel();
|
||||
_longPressTimer = Timer.periodic(const Duration(milliseconds: 250), (timer) async {
|
||||
for (final action in buttonsClicked) {
|
||||
actionStreamInternal.add(LogNotification(await actionHandler.performAction(action)));
|
||||
}
|
||||
_performActions(buttonsClicked, true);
|
||||
});
|
||||
}
|
||||
|
||||
for (final action in buttonsClicked) {
|
||||
actionStreamInternal.add(LogNotification(await actionHandler.performAction(action)));
|
||||
}
|
||||
_performActions(buttonsClicked, false);
|
||||
}
|
||||
})
|
||||
.catchError((e) {
|
||||
@@ -265,4 +262,25 @@ abstract class BaseDevice {
|
||||
}
|
||||
|
||||
Future<List<ZwiftButton>?> processClickNotification(Uint8List message);
|
||||
|
||||
Future<void> _performActions(List<ZwiftButton> buttonsClicked, bool repeated) async {
|
||||
if (!repeated &&
|
||||
buttonsClicked.any(((e) => e.action == InGameAction.shiftDown || e.action == InGameAction.shiftUp))) {
|
||||
await _vibrate();
|
||||
}
|
||||
for (final action in buttonsClicked) {
|
||||
actionStreamInternal.add(LogNotification(await actionHandler.performAction(action)));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _vibrate() async {
|
||||
final vibrateCommand = Uint8List.fromList([...Constants.VIBRATE_PATTERN, 0x20]);
|
||||
await UniversalBle.writeValue(
|
||||
device.deviceId,
|
||||
customServiceId,
|
||||
syncRxCharacteristic!.uuid,
|
||||
supportsEncryption ? zapEncryption.encrypt(vibrateCommand) : vibrateCommand,
|
||||
BleOutputProperty.withoutResponse,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: swift_control
|
||||
description: "SwiftControl - Control your virtual riding"
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
version: 2.0.3+0
|
||||
version: 2.0.4+0
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.0
|
||||
|
||||
Reference in New Issue
Block a user