From 05939dcf1e0b0287a140cee3449cc5ecc2d73d89 Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Fri, 24 Oct 2025 09:44:06 +0200 Subject: [PATCH] implement fix for issue #38 --- lib/pages/device.dart | 13 +------------ lib/utils/actions/android.dart | 15 ++++++++++++++- lib/utils/actions/base_actions.dart | 18 +++++++++++++++--- lib/utils/actions/desktop.dart | 2 +- lib/utils/actions/remote.dart | 5 +++-- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/lib/pages/device.dart b/lib/pages/device.dart index d880d46..be66f72 100644 --- a/lib/pages/device.dart +++ b/lib/pages/device.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:io'; -import 'package:device_auto_rotate_checker/device_auto_rotate_checker.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -11,7 +10,6 @@ import 'package:swift_control/bluetooth/devices/zwift/zwift_device.dart'; import 'package:swift_control/main.dart'; import 'package:swift_control/pages/markdown.dart'; import 'package:swift_control/pages/touch_area.dart'; -import 'package:swift_control/utils/actions/android.dart'; import 'package:swift_control/utils/actions/desktop.dart'; import 'package:swift_control/utils/actions/link.dart'; import 'package:swift_control/utils/keymap/manager.dart'; @@ -45,8 +43,6 @@ class _DevicePageState extends State with WidgetsBindingObserver { late StreamSubscription _connectionStateSubscription; final controller = TextEditingController(text: actionHandler.supportedApp?.name); - bool _showAutoRotateWarning = false; - List _getAllApps() { final baseApps = SupportedApp.supportedApps.where((app) => app is! CustomApp).toList(); final customProfiles = settings.getCustomAppProfiles(); @@ -86,13 +82,6 @@ class _DevicePageState extends State with WidgetsBindingObserver { ), ); }); - } else if (actionHandler is AndroidActions) { - DeviceAutoRotateChecker.checkAutoRotate().then((autoRotate) => _showAutoRotateWarning = !autoRotate); - _deviceAutoRotateStream = DeviceAutoRotateChecker.autoRotateStream.listen((autoRotate) { - setState(() { - _showAutoRotateWarning = !autoRotate; - }); - }); } _connectionStateSubscription = connection.connectionStream.listen((state) async { setState(() {}); @@ -165,7 +154,7 @@ class _DevicePageState extends State with WidgetsBindingObserver { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (_showAutoRotateWarning) + if (!kIsWeb && Platform.isAndroid) Warning( children: [ Text('Enable auto-rotation on your device to make sure the app works correctly.'), diff --git a/lib/utils/actions/android.dart b/lib/utils/actions/android.dart index 374f5a7..bc2d364 100644 --- a/lib/utils/actions/android.dart +++ b/lib/utils/actions/android.dart @@ -6,11 +6,24 @@ import 'package:swift_control/utils/keymap/apps/custom_app.dart'; import 'package:swift_control/utils/keymap/buttons.dart'; import 'package:swift_control/widgets/keymap_explanation.dart'; +import '../keymap/apps/supported_app.dart'; import '../single_line_exception.dart'; class AndroidActions extends BaseActions { + WindowEvent? windowInfo; + AndroidActions({super.supportedModes = const [SupportedMode.touch, SupportedMode.media]}); + @override + void init(SupportedApp? supportedApp) { + super.init(supportedApp); + streamEvents().listen((windowEvent) { + if (supportedApp != null) { + windowInfo = windowEvent; + } + }); + } + @override Future performAction(ControllerButton button, {bool isKeyDown = true, bool isKeyUp = false}) async { if (supportedApp == null) { @@ -30,7 +43,7 @@ class AndroidActions extends BaseActions { return "Key pressed: ${keyPair.toString()}"; } } - final point = await resolveTouchPosition(action: button); + final point = await resolveTouchPosition(action: button, windowInfo: windowInfo); if (point != Offset.zero) { try { await accessibilityHandler.performTouch(point.dx, point.dy, isKeyDown: isKeyDown, isKeyUp: isKeyUp); diff --git a/lib/utils/actions/base_actions.dart b/lib/utils/actions/base_actions.dart index b034493..ced3897 100644 --- a/lib/utils/actions/base_actions.dart +++ b/lib/utils/actions/base_actions.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'dart:math'; +import 'package:accessibility/accessibility.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:screen_retriever/screen_retriever.dart'; @@ -22,7 +24,7 @@ abstract class BaseActions { this.supportedApp = supportedApp; } - Future resolveTouchPosition({required ControllerButton action}) async { + Future resolveTouchPosition({required ControllerButton action, required WindowEvent? windowInfo}) async { final keyPair = supportedApp!.keymap.getKeyPair(action); if (keyPair != null && keyPair.touchPosition != Offset.zero) { // convert relative position to absolute position based on window info @@ -43,8 +45,18 @@ abstract class BaseActions { late final Size physicalSize; if (this is AndroidActions) { - // display size is already in physical pixels - physicalSize = displaySize; + if (windowInfo != null && windowInfo.packageName != 'de.jonasbark.swiftcontrol') { + // a trainer app is in foreground, so use the always assume landscape + final windowWidth = (windowInfo.right - windowInfo.left).toDouble(); + final windowHeight = (windowInfo.bottom - windowInfo.top).toDouble(); + physicalSize = Size( + max(windowWidth, windowHeight), + min(windowWidth, windowHeight), + ); + } else { + // display size is already in physical pixels + physicalSize = displaySize; + } } else if (this is DesktopActions) { // display size is in logical pixels, convert to physical pixels // TODO on macOS the notch is included here, but it's not part of the usable screen area, so we should exclude it diff --git a/lib/utils/actions/desktop.dart b/lib/utils/actions/desktop.dart index c2b5f65..567eb44 100644 --- a/lib/utils/actions/desktop.dart +++ b/lib/utils/actions/desktop.dart @@ -33,7 +33,7 @@ class DesktopActions extends BaseActions { return 'Key released: $keyPair'; } } else { - final point = await resolveTouchPosition(action: action); + final point = await resolveTouchPosition(action: action, windowInfo: null); if (isKeyDown && isKeyUp) { await keyPressSimulator.simulateMouseClickDown(point); // slight move to register clicks on some apps, see issue #116 diff --git a/lib/utils/actions/remote.dart b/lib/utils/actions/remote.dart index 019fcfd..5cd3810 100644 --- a/lib/utils/actions/remote.dart +++ b/lib/utils/actions/remote.dart @@ -1,5 +1,6 @@ import 'dart:ui'; +import 'package:accessibility/accessibility.dart'; import 'package:bluetooth_low_energy/bluetooth_low_energy.dart'; import 'package:flutter/foundation.dart'; import 'package:swift_control/bluetooth/devices/zwift/zwift_click.dart'; @@ -32,7 +33,7 @@ class RemoteActions extends BaseActions { if (keyPair.physicalKey != null && keyPair.touchPosition == Offset.zero) { return ('Physical key actions are not supported, yet'); } else { - final point = await resolveTouchPosition(action: action); + final point = await resolveTouchPosition(action: action, windowInfo: null); final point2 = point; //Offset(100, 99.0); await sendAbsMouseReport(0, point2.dx.toInt(), point2.dy.toInt()); await sendAbsMouseReport(1, point2.dx.toInt(), point2.dy.toInt()); @@ -43,7 +44,7 @@ class RemoteActions extends BaseActions { } @override - Future resolveTouchPosition({required ControllerButton action, bool isAppInForeground = false}) async { + Future resolveTouchPosition({required ControllerButton action, required WindowEvent? windowInfo}) async { // for remote actions we use the relative position only final keyPair = supportedApp!.keymap.getKeyPair(action); if (keyPair != null && keyPair.touchPosition != Offset.zero) {