mirror of
https://github.com/jonasbark/swiftcontrol.git
synced 2026-02-18 00:17:40 +01:00
attempt to fix #3
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
### 1.0.0+4 (2025-03-29)
|
||||
- Zwift Ride: attempt to fix button parsing
|
||||
|
||||
### 1.0.0+3 (2025-03-29)
|
||||
|
||||
- Windows: fix connection by using a different Bluetooth stack (issue #1)
|
||||
|
||||
@@ -15,6 +15,10 @@ class Constants {
|
||||
static const RC1_LEFT_SIDE = 0x03;
|
||||
static const RC1_RIGHT_SIDE = 0x02;
|
||||
|
||||
// Zwift Ride
|
||||
static const RIDE_RIGHT_SIDE = 0x07;
|
||||
static const RIDE_LEFT_SIDE = 0x08;
|
||||
|
||||
// Zwift Click = BC1
|
||||
static const BC1 = 0x09;
|
||||
|
||||
@@ -33,7 +37,7 @@ class Constants {
|
||||
// not figured out the protobuf type this really is, the content is just two varints.
|
||||
static const int CLICK_NOTIFICATION_MESSAGE_TYPE = 55;
|
||||
static const int PLAY_NOTIFICATION_MESSAGE_TYPE = 7;
|
||||
static const int RIDE_NOTIFICATION_MESSAGE_TYPE = 35;
|
||||
static const int RIDE_NOTIFICATION_MESSAGE_TYPE = 35; // 0x23
|
||||
|
||||
// see this if connected to Core then Zwift connects to it. just one byte
|
||||
static const DISCONNECT_MESSAGE_TYPE = 0xFE;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:accessibility/accessibility.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:swift_control/utils/devices/zwift_click.dart';
|
||||
import 'package:swift_control/utils/messages/controller_notification.dart';
|
||||
import 'package:swift_control/utils/messages/play_notification.dart';
|
||||
|
||||
import '../../main.dart';
|
||||
import '../ble.dart';
|
||||
@@ -9,14 +9,14 @@ import '../ble.dart';
|
||||
class ZwiftPlay extends ZwiftClick {
|
||||
ZwiftPlay(super.scanResult);
|
||||
|
||||
ControllerNotification? _lastControllerNotification;
|
||||
PlayNotification? _lastControllerNotification;
|
||||
|
||||
@override
|
||||
List<int> get startCommand => Constants.RIDE_ON + Constants.RESPONSE_START_PLAY;
|
||||
|
||||
@override
|
||||
void processClickNotification(Uint8List message) {
|
||||
final ControllerNotification clickNotification = ControllerNotification(message);
|
||||
final PlayNotification clickNotification = PlayNotification(message);
|
||||
if (_lastControllerNotification == null || _lastControllerNotification != clickNotification) {
|
||||
_lastControllerNotification = clickNotification;
|
||||
actionStreamInternal.add(clickNotification);
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import 'package:swift_control/utils/devices/zwift_play.dart';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:accessibility/accessibility.dart';
|
||||
import 'package:swift_control/main.dart';
|
||||
import 'package:swift_control/utils/devices/zwift_click.dart';
|
||||
import 'package:swift_control/utils/messages/ride_notification.dart';
|
||||
|
||||
import '../ble.dart';
|
||||
|
||||
class ZwiftRide extends ZwiftPlay {
|
||||
class ZwiftRide extends ZwiftClick {
|
||||
ZwiftRide(super.scanResult);
|
||||
|
||||
@override
|
||||
@@ -10,4 +15,30 @@ class ZwiftRide extends ZwiftPlay {
|
||||
|
||||
@override
|
||||
bool get supportsEncryption => false;
|
||||
|
||||
RideNotification? _lastControllerNotification;
|
||||
|
||||
@override
|
||||
void processClickNotification(Uint8List message) {
|
||||
final RideNotification clickNotification = RideNotification(message);
|
||||
if (_lastControllerNotification == null || _lastControllerNotification != clickNotification) {
|
||||
_lastControllerNotification = clickNotification;
|
||||
actionStreamInternal.add(clickNotification);
|
||||
|
||||
if (clickNotification.analogLR.abs() == 100) {
|
||||
actionHandler.increaseGear();
|
||||
} else if (clickNotification.analogUD.abs() == 100) {
|
||||
actionHandler.decreaseGear();
|
||||
}
|
||||
if (clickNotification.buttonA) {
|
||||
actionHandler.controlMedia(MediaAction.next);
|
||||
} else if (clickNotification.buttonY) {
|
||||
actionHandler.controlMedia(MediaAction.volumeUp);
|
||||
} else if (clickNotification.buttonB) {
|
||||
actionHandler.controlMedia(MediaAction.volumeDown);
|
||||
} else if (clickNotification.buttonZ) {
|
||||
actionHandler.controlMedia(MediaAction.playPause);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import 'package:swift_control/utils/messages/notification.dart';
|
||||
|
||||
import '../../protocol/zwift.pb.dart';
|
||||
|
||||
class ControllerNotification extends BaseNotification {
|
||||
class PlayNotification extends BaseNotification {
|
||||
static const int BTN_PRESSED = 0;
|
||||
|
||||
late bool rightPad, buttonY, buttonZ, buttonA, buttonB, buttonOn, buttonShift;
|
||||
late int analogLR, analogUD;
|
||||
|
||||
ControllerNotification(Uint8List message) {
|
||||
PlayNotification(Uint8List message) {
|
||||
final status = PlayKeyPadStatus.fromBuffer(message);
|
||||
|
||||
rightPad = status.rightPad.value == BTN_PRESSED;
|
||||
@@ -41,7 +41,7 @@ class ControllerNotification extends BaseNotification {
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is ControllerNotification &&
|
||||
other is PlayNotification &&
|
||||
runtimeType == other.runtimeType &&
|
||||
rightPad == other.rightPad &&
|
||||
buttonY == other.buttonY &&
|
||||
140
lib/utils/messages/ride_notification.dart
Normal file
140
lib/utils/messages/ride_notification.dart
Normal file
@@ -0,0 +1,140 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:swift_control/utils/messages/notification.dart';
|
||||
|
||||
import '../../protocol/zwift.pb.dart';
|
||||
|
||||
enum _RideButtonMask {
|
||||
LEFT_BTN(0x00001),
|
||||
UP_BTN(0x00002),
|
||||
RIGHT_BTN(0x00004),
|
||||
DOWN_BTN(0x00008),
|
||||
A_BTN(0x00010),
|
||||
B_BTN(0x00020),
|
||||
Y_BTN(0x00040),
|
||||
|
||||
Z_BTN(0x00100),
|
||||
SHFT_UP_L_BTN(0x00200),
|
||||
SHFT_DN_L_BTN(0x00400),
|
||||
POWERUP_L_BTN(0x00800),
|
||||
ONOFF_L_BTN(0x01000),
|
||||
SHFT_UP_R_BTN(0x02000),
|
||||
SHFT_DN_R_BTN(0x04000),
|
||||
|
||||
POWERUP_R_BTN(0x10000),
|
||||
ONOFF_R_BTN(0x20000);
|
||||
|
||||
final int mask;
|
||||
|
||||
const _RideButtonMask(this.mask);
|
||||
}
|
||||
|
||||
class RideNotification extends BaseNotification {
|
||||
static const int BTN_PRESSED = 0;
|
||||
|
||||
late bool buttonLeft, buttonRight, buttonUp, buttonDown;
|
||||
late bool buttonA, buttonB, buttonY, buttonZ;
|
||||
late bool buttonShiftUpLeft, buttonShiftDownLeft;
|
||||
late bool buttonShiftUpRight, buttonShiftDownRight;
|
||||
late bool buttonPowerUpLeft, buttonPowerDownLeft;
|
||||
late bool buttonOnOffLeft, buttonOnOffRight;
|
||||
|
||||
late int analogLR, analogUD;
|
||||
|
||||
RideNotification(Uint8List message) {
|
||||
final status = RideKeyPadStatus.fromBuffer(message);
|
||||
|
||||
buttonLeft = status.buttonMap & _RideButtonMask.LEFT_BTN.mask == BTN_PRESSED;
|
||||
buttonRight = status.buttonMap & _RideButtonMask.RIGHT_BTN.mask == BTN_PRESSED;
|
||||
buttonUp = status.buttonMap & _RideButtonMask.UP_BTN.mask == BTN_PRESSED;
|
||||
buttonDown = status.buttonMap & _RideButtonMask.DOWN_BTN.mask == BTN_PRESSED;
|
||||
buttonA = status.buttonMap & _RideButtonMask.A_BTN.mask == BTN_PRESSED;
|
||||
buttonB = status.buttonMap & _RideButtonMask.B_BTN.mask == BTN_PRESSED;
|
||||
buttonY = status.buttonMap & _RideButtonMask.Y_BTN.mask == BTN_PRESSED;
|
||||
buttonZ = status.buttonMap & _RideButtonMask.Z_BTN.mask == BTN_PRESSED;
|
||||
buttonShiftUpLeft = status.buttonMap & _RideButtonMask.SHFT_UP_L_BTN.mask == BTN_PRESSED;
|
||||
buttonShiftDownLeft = status.buttonMap & _RideButtonMask.SHFT_DN_L_BTN.mask == BTN_PRESSED;
|
||||
buttonShiftUpRight = status.buttonMap & _RideButtonMask.SHFT_UP_R_BTN.mask == BTN_PRESSED;
|
||||
buttonShiftDownRight = status.buttonMap & _RideButtonMask.SHFT_DN_R_BTN.mask == BTN_PRESSED;
|
||||
buttonPowerUpLeft = status.buttonMap & _RideButtonMask.POWERUP_L_BTN.mask == BTN_PRESSED;
|
||||
buttonPowerDownLeft = status.buttonMap & _RideButtonMask.POWERUP_R_BTN.mask == BTN_PRESSED;
|
||||
buttonOnOffLeft = status.buttonMap & _RideButtonMask.ONOFF_L_BTN.mask == BTN_PRESSED;
|
||||
buttonOnOffRight = status.buttonMap & _RideButtonMask.ONOFF_R_BTN.mask == BTN_PRESSED;
|
||||
|
||||
for (final analogue in status.analogButtons.groupStatus) {
|
||||
if (analogue.location == RideAnalogLocation.LEFT) {
|
||||
analogLR = analogue.analogValue;
|
||||
} else if (analogue.location == RideAnalogLocation.DOWN) {
|
||||
analogUD = analogue.analogValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final allTrueParameters = [
|
||||
if (buttonLeft) 'buttonLeft',
|
||||
if (buttonRight) 'buttonRight',
|
||||
if (buttonUp) 'buttonUp',
|
||||
if (buttonDown) 'buttonDown',
|
||||
if (buttonA) 'buttonA',
|
||||
if (buttonB) 'buttonB',
|
||||
if (buttonY) 'buttonY',
|
||||
if (buttonZ) 'buttonZ',
|
||||
if (buttonShiftUpLeft) 'buttonShiftUpLeft',
|
||||
if (buttonShiftDownLeft) 'buttonShiftDownLeft',
|
||||
if (buttonShiftUpRight) 'buttonShiftUpRight',
|
||||
if (buttonShiftDownRight) 'buttonShiftDownRight',
|
||||
if (buttonPowerUpLeft) 'buttonPowerUpLeft',
|
||||
if (buttonPowerDownLeft) 'buttonPowerDownLeft',
|
||||
if (buttonOnOffLeft) 'buttonOnOffLeft',
|
||||
if (buttonOnOffRight) 'buttonOnOffRight',
|
||||
];
|
||||
return '{$allTrueParameters, analogLR: $analogLR, analogUD: $analogUD}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is RideNotification &&
|
||||
runtimeType == other.runtimeType &&
|
||||
buttonLeft == other.buttonLeft &&
|
||||
buttonRight == other.buttonRight &&
|
||||
buttonUp == other.buttonUp &&
|
||||
buttonDown == other.buttonDown &&
|
||||
buttonA == other.buttonA &&
|
||||
buttonB == other.buttonB &&
|
||||
buttonY == other.buttonY &&
|
||||
buttonZ == other.buttonZ &&
|
||||
buttonShiftUpLeft == other.buttonShiftUpLeft &&
|
||||
buttonShiftDownLeft == other.buttonShiftDownLeft &&
|
||||
buttonShiftUpRight == other.buttonShiftUpRight &&
|
||||
buttonShiftDownRight == other.buttonShiftDownRight &&
|
||||
buttonPowerUpLeft == other.buttonPowerUpLeft &&
|
||||
buttonPowerDownLeft == other.buttonPowerDownLeft &&
|
||||
buttonOnOffLeft == other.buttonOnOffLeft &&
|
||||
buttonOnOffRight == other.buttonOnOffRight &&
|
||||
analogLR == other.analogLR &&
|
||||
analogUD == other.analogUD;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
buttonLeft.hashCode ^
|
||||
buttonRight.hashCode ^
|
||||
buttonUp.hashCode ^
|
||||
buttonDown.hashCode ^
|
||||
buttonA.hashCode ^
|
||||
buttonB.hashCode ^
|
||||
buttonY.hashCode ^
|
||||
buttonZ.hashCode ^
|
||||
buttonShiftUpLeft.hashCode ^
|
||||
buttonShiftDownLeft.hashCode ^
|
||||
buttonShiftUpRight.hashCode ^
|
||||
buttonShiftDownRight.hashCode ^
|
||||
buttonPowerUpLeft.hashCode ^
|
||||
buttonPowerDownLeft.hashCode ^
|
||||
buttonOnOffLeft.hashCode ^
|
||||
buttonOnOffRight.hashCode ^
|
||||
analogLR.hashCode ^
|
||||
analogUD.hashCode;
|
||||
}
|
||||
@@ -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: 1.0.0+3
|
||||
version: 1.0.0+4
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.0
|
||||
|
||||
Reference in New Issue
Block a user