From 45112ccfcfb1a5607832bc9923aa28278dbf7829 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 19:30:34 +0000 Subject: [PATCH] Implement percentage-based keymap storage for better device compatibility Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com> --- lib/pages/device.dart | 30 +++++++++++++++++++--- lib/utils/keymap/apps/custom_app.dart | 8 +++--- lib/utils/keymap/keymap.dart | 37 ++++++++++++++++++++++++--- lib/utils/settings/settings.dart | 22 ++++++++++++++-- 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/lib/pages/device.dart b/lib/pages/device.dart index ccff03f..0f4df88 100644 --- a/lib/pages/device.dart +++ b/lib/pages/device.dart @@ -31,11 +31,21 @@ class _DevicePageState extends State { List _getAllApps() { final baseApps = SupportedApp.supportedApps.where((app) => app is! CustomApp).toList(); final customProfiles = settings.getCustomAppProfiles(); + + // Get screen size for percentage-based decoding + Size? screenSize; + try { + final view = WidgetsBinding.instance.platformDispatcher.views.first; + screenSize = view.physicalSize / view.devicePixelRatio; + } catch (e) { + screenSize = MediaQuery.maybeOf(context)?.size; + } + final customApps = customProfiles.map((profile) { final customApp = CustomApp(profileName: profile); final savedKeymap = settings.getCustomAppKeymap(profile); if (savedKeymap != null) { - customApp.decodeKeymap(savedKeymap); + customApp.decodeKeymap(savedKeymap, screenSize: screenSize); } return customApp; }).toList(); @@ -227,7 +237,14 @@ ${it.firmwareVersion != null ? ' - Firmware Version: ${it.firmwareVersion}' : '' final customApp = CustomApp(profileName: newName); final savedKeymap = settings.getCustomAppKeymap(newName); if (savedKeymap != null) { - customApp.decodeKeymap(savedKeymap); + Size? screenSize; + try { + final view = WidgetsBinding.instance.platformDispatcher.views.first; + screenSize = view.physicalSize / view.devicePixelRatio; + } catch (e) { + screenSize = MediaQuery.maybeOf(context)?.size; + } + customApp.decodeKeymap(savedKeymap, screenSize: screenSize); } actionHandler.supportedApp = customApp; await settings.setApp(customApp); @@ -241,7 +258,14 @@ ${it.firmwareVersion != null ? ' - Firmware Version: ${it.firmwareVersion}' : '' final customApp = CustomApp(profileName: newName); final savedKeymap = settings.getCustomAppKeymap(newName); if (savedKeymap != null) { - customApp.decodeKeymap(savedKeymap); + Size? screenSize; + try { + final view = WidgetsBinding.instance.platformDispatcher.views.first; + screenSize = view.physicalSize / view.devicePixelRatio; + } catch (e) { + screenSize = MediaQuery.maybeOf(context)?.size; + } + customApp.decodeKeymap(savedKeymap, screenSize: screenSize); } actionHandler.supportedApp = customApp; await settings.setApp(customApp); diff --git a/lib/utils/keymap/apps/custom_app.dart b/lib/utils/keymap/apps/custom_app.dart index b3379f6..06f4ec6 100644 --- a/lib/utils/keymap/apps/custom_app.dart +++ b/lib/utils/keymap/apps/custom_app.dart @@ -22,19 +22,19 @@ class CustomApp extends SupportedApp { return keyPair.touchPosition; } - List encodeKeymap() { + List encodeKeymap({Size? screenSize}) { // encode to save in preferences - return keymap.keyPairs.map((e) => e.encode()).toList(); + return keymap.keyPairs.map((e) => e.encode(screenSize: screenSize)).toList(); } - void decodeKeymap(List data) { + void decodeKeymap(List data, {Size? screenSize}) { // decode from preferences if (data.isEmpty) { return; } - final keyPairs = data.map((e) => KeyPair.decode(e)).whereNotNull().toList(); + final keyPairs = data.map((e) => KeyPair.decode(e, screenSize: screenSize)).whereNotNull().toList(); if (keyPairs.isEmpty) { return; } diff --git a/lib/utils/keymap/keymap.dart b/lib/utils/keymap/keymap.dart index 7289666..d135f3e 100644 --- a/lib/utils/keymap/keymap.dart +++ b/lib/utils/keymap/keymap.dart @@ -73,23 +73,52 @@ class KeyPair { }; } - String encode() { + String encode({Size? screenSize}) { // encode to save in preferences + // If screenSize is provided, store as percentages for better compatibility across devices + final touchPosData = screenSize != null && touchPosition != Offset.zero + ? { + 'x_percent': touchPosition.dx / screenSize.width, + 'y_percent': touchPosition.dy / screenSize.height, + } + : {'x': touchPosition.dx, 'y': touchPosition.dy}; + return jsonEncode({ 'actions': buttons.map((e) => e.name).toList(), 'logicalKey': logicalKey?.keyId.toString() ?? '0', 'physicalKey': physicalKey?.usbHidUsage.toString() ?? '0', - 'touchPosition': {'x': touchPosition.dx, 'y': touchPosition.dy}, + 'touchPosition': touchPosData, 'isLongPress': isLongPress, }); } - static KeyPair? decode(String data) { + static KeyPair? decode(String data, {Size? screenSize}) { // decode from preferences final decoded = jsonDecode(data); if (decoded['actions'] == null || decoded['logicalKey'] == null || decoded['physicalKey'] == null) { return null; } + + // Support both percentage-based (new) and pixel-based (old) formats + final touchPosData = decoded['touchPosition']; + final Offset touchPosition; + + if (touchPosData.containsKey('x_percent') && touchPosData.containsKey('y_percent')) { + // New percentage-based format + if (screenSize != null) { + touchPosition = Offset( + touchPosData['x_percent'] * screenSize.width, + touchPosData['y_percent'] * screenSize.height, + ); + } else { + // Fallback if no screen size provided + touchPosition = Offset.zero; + } + } else { + // Old pixel-based format + touchPosition = Offset(touchPosData['x'], touchPosData['y']); + } + return KeyPair( buttons: decoded['actions'] @@ -98,7 +127,7 @@ class KeyPair { logicalKey: int.parse(decoded['logicalKey']) != 0 ? LogicalKeyboardKey(int.parse(decoded['logicalKey'])) : null, physicalKey: int.parse(decoded['physicalKey']) != 0 ? PhysicalKeyboardKey(int.parse(decoded['physicalKey'])) : null, - touchPosition: Offset(decoded['touchPosition']['x'], decoded['touchPosition']['y']), + touchPosition: touchPosition, isLongPress: decoded['isLongPress'] ?? false, ); } diff --git a/lib/utils/settings/settings.dart b/lib/utils/settings/settings.dart index ad6c6ba..27c2858 100644 --- a/lib/utils/settings/settings.dart +++ b/lib/utils/settings/settings.dart @@ -1,4 +1,5 @@ import 'package:dartx/dartx.dart'; +import 'package:flutter/widgets.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:swift_control/utils/keymap/apps/supported_app.dart'; @@ -31,7 +32,15 @@ class Settings { final customApp = CustomApp(profileName: appName); final appSetting = _prefs.getStringList('customapp_$appName'); if (appSetting != null) { - customApp.decodeKeymap(appSetting); + // Get screen size for percentage-based decoding + Size? screenSize; + try { + final view = WidgetsBinding.instance.platformDispatcher.views.first; + screenSize = view.physicalSize / view.devicePixelRatio; + } catch (e) { + screenSize = null; + } + customApp.decodeKeymap(appSetting, screenSize: screenSize); } actionHandler.init(customApp); } else { @@ -52,7 +61,16 @@ class Settings { Future setApp(SupportedApp app) async { if (app is CustomApp) { - await _prefs.setStringList('customapp_${app.profileName}', app.encodeKeymap()); + // Get screen size for percentage-based encoding + Size? screenSize; + try { + final view = WidgetsBinding.instance.platformDispatcher.views.first; + screenSize = view.physicalSize / view.devicePixelRatio; + } catch (e) { + // Fallback if screen size is not available + screenSize = null; + } + await _prefs.setStringList('customapp_${app.profileName}', app.encodeKeymap(screenSize: screenSize)); } await _prefs.setString('app', app.name); }