mirror of
https://github.com/jonasbark/swiftcontrol.git
synced 2026-02-18 00:17:40 +01:00
Add Android global actions support
Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
This commit is contained in:
@@ -90,6 +90,23 @@ enum class MediaAction(val raw: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
enum class GlobalAction(val raw: Int) {
|
||||
BACK(0),
|
||||
DPAD_CENTER(1),
|
||||
DOWN(2),
|
||||
RIGHT(3),
|
||||
UP(4),
|
||||
LEFT(5),
|
||||
HOME(6),
|
||||
RECENTS(7);
|
||||
|
||||
companion object {
|
||||
fun ofRaw(raw: Int): GlobalAction? {
|
||||
return values().firstOrNull { it.raw == raw }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class WindowEvent (
|
||||
val packageName: String,
|
||||
@@ -174,6 +191,11 @@ private open class AccessibilityApiPigeonCodec : StandardMessageCodec() {
|
||||
MediaAction.ofRaw(it.toInt())
|
||||
}
|
||||
}
|
||||
132.toByte() -> {
|
||||
return (readValue(buffer) as Long?)?.let {
|
||||
GlobalAction.ofRaw(it.toInt())
|
||||
}
|
||||
}
|
||||
130.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
WindowEvent.fromList(it)
|
||||
@@ -193,6 +215,10 @@ private open class AccessibilityApiPigeonCodec : StandardMessageCodec() {
|
||||
stream.write(129)
|
||||
writeValue(stream, value.raw)
|
||||
}
|
||||
is GlobalAction -> {
|
||||
stream.write(132)
|
||||
writeValue(stream, value.raw)
|
||||
}
|
||||
is WindowEvent -> {
|
||||
stream.write(130)
|
||||
writeValue(stream, value.toList())
|
||||
@@ -213,6 +239,7 @@ interface Accessibility {
|
||||
fun hasPermission(): Boolean
|
||||
fun openPermissions()
|
||||
fun performTouch(x: Double, y: Double, isKeyDown: Boolean, isKeyUp: Boolean)
|
||||
fun performGlobalAction(action: GlobalAction)
|
||||
fun controlMedia(action: MediaAction)
|
||||
fun isRunning(): Boolean
|
||||
fun ignoreHidDevices()
|
||||
@@ -279,6 +306,24 @@ interface Accessibility {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.accessibility.Accessibility.performGlobalAction$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val actionArg = args[0] as GlobalAction
|
||||
val wrapped: List<Any?> = try {
|
||||
api.performGlobalAction(actionArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
AccessibilityApiPigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.accessibility.Accessibility.controlMedia$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.jonasbark.accessibility
|
||||
|
||||
import AKeyEvent
|
||||
import Accessibility
|
||||
import GlobalAction
|
||||
import HidKeyPressedStreamHandler
|
||||
import MediaAction
|
||||
import PigeonEventSink
|
||||
@@ -66,6 +67,10 @@ class AccessibilityPlugin: FlutterPlugin, Accessibility {
|
||||
Observable.toService?.performTouch(x = x, y = y, isKeyUp = isKeyUp, isKeyDown = isKeyDown) ?: error("Service not running")
|
||||
}
|
||||
|
||||
override fun performGlobalAction(action: GlobalAction) {
|
||||
Observable.toService?.performGlobalAction(action) ?: error("Service not running")
|
||||
}
|
||||
|
||||
override fun controlMedia(action: MediaAction) {
|
||||
val audioService = context.getSystemService(Context.AUDIO_SERVICE) as android.media.AudioManager
|
||||
when (action) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.view.KeyEvent
|
||||
import android.view.ViewConfiguration
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
|
||||
import GlobalAction
|
||||
|
||||
|
||||
class AccessibilityService : AccessibilityService(), Listener {
|
||||
@@ -97,6 +98,20 @@ class AccessibilityService : AccessibilityService(), Listener {
|
||||
}
|
||||
}
|
||||
|
||||
override fun performGlobalAction(action: GlobalAction) {
|
||||
val mappedAction = when (action) {
|
||||
GlobalAction.BACK -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_BACK
|
||||
GlobalAction.DPAD_CENTER -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_DPAD_CENTER
|
||||
GlobalAction.DOWN -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_DPAD_DOWN
|
||||
GlobalAction.RIGHT -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_DPAD_RIGHT
|
||||
GlobalAction.UP -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_DPAD_UP
|
||||
GlobalAction.LEFT -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_DPAD_LEFT
|
||||
GlobalAction.HOME -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_HOME
|
||||
GlobalAction.RECENTS -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_RECENTS
|
||||
}
|
||||
performGlobalAction(mappedAction)
|
||||
}
|
||||
|
||||
override fun performTouch(x: Double, y: Double, isKeyDown: Boolean, isKeyUp: Boolean) {
|
||||
val gestureBuilder = GestureDescription.Builder()
|
||||
val path = Path()
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.jonasbark.accessibility
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.KeyEvent
|
||||
import GlobalAction
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object Observable {
|
||||
@@ -15,6 +16,7 @@ object Observable {
|
||||
|
||||
interface Listener {
|
||||
fun performTouch(x: Double, y: Double, isKeyDown: Boolean, isKeyUp: Boolean)
|
||||
fun performGlobalAction(action: GlobalAction)
|
||||
}
|
||||
|
||||
interface Receiver {
|
||||
|
||||
@@ -8,6 +8,8 @@ abstract class Accessibility {
|
||||
|
||||
void performTouch(double x, double y, {bool isKeyDown = true, bool isKeyUp = false});
|
||||
|
||||
void performGlobalAction(GlobalAction action);
|
||||
|
||||
void controlMedia(MediaAction action);
|
||||
|
||||
bool isRunning();
|
||||
@@ -19,6 +21,17 @@ abstract class Accessibility {
|
||||
|
||||
enum MediaAction { playPause, next, volumeUp, volumeDown }
|
||||
|
||||
enum GlobalAction {
|
||||
back,
|
||||
dpadCenter,
|
||||
down,
|
||||
right,
|
||||
up,
|
||||
left,
|
||||
home,
|
||||
recents,
|
||||
}
|
||||
|
||||
class WindowEvent {
|
||||
final String packageName;
|
||||
final int top;
|
||||
|
||||
@@ -36,6 +36,17 @@ enum MediaAction {
|
||||
volumeDown,
|
||||
}
|
||||
|
||||
enum GlobalAction {
|
||||
back,
|
||||
dpadCenter,
|
||||
down,
|
||||
right,
|
||||
up,
|
||||
left,
|
||||
home,
|
||||
recents,
|
||||
}
|
||||
|
||||
class WindowEvent {
|
||||
WindowEvent({
|
||||
required this.packageName,
|
||||
@@ -164,6 +175,9 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
} else if (value is MediaAction) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.index);
|
||||
} else if (value is GlobalAction) {
|
||||
buffer.putUint8(132);
|
||||
writeValue(buffer, value.index);
|
||||
} else if (value is WindowEvent) {
|
||||
buffer.putUint8(130);
|
||||
writeValue(buffer, value.encode());
|
||||
@@ -181,6 +195,9 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
case 129:
|
||||
final int? value = readValue(buffer) as int?;
|
||||
return value == null ? null : MediaAction.values[value];
|
||||
case 132:
|
||||
final int? value = readValue(buffer) as int?;
|
||||
return value == null ? null : GlobalAction.values[value];
|
||||
case 130:
|
||||
return WindowEvent.decode(readValue(buffer)!);
|
||||
case 131:
|
||||
@@ -280,6 +297,29 @@ class Accessibility {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> performGlobalAction(GlobalAction action) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.accessibility.Accessibility.performGlobalAction$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[action]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: pigeonVar_replyList[0]! as String,
|
||||
message: pigeonVar_replyList[1] as String?,
|
||||
details: pigeonVar_replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> controlMedia(MediaAction action) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.accessibility.Accessibility.controlMedia$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
|
||||
@@ -201,6 +201,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
_keyPair.isLongPress = keyPairAction.isLongPress;
|
||||
_keyPair.inGameAction = keyPairAction.inGameAction;
|
||||
_keyPair.inGameActionValue = keyPairAction.inGameActionValue;
|
||||
_keyPair.androidAction = null;
|
||||
setState(() {});
|
||||
},
|
||||
child: Text(keyPairAction.toString()),
|
||||
@@ -227,6 +228,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
keyPair: _keyPair,
|
||||
),
|
||||
);
|
||||
_keyPair.androidAction = null;
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
},
|
||||
@@ -243,6 +245,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
}
|
||||
_keyPair.physicalKey = null;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
await Navigator.of(context).push<bool?>(
|
||||
MaterialPageRoute(
|
||||
builder: (c) => TouchAreaSetupPage(
|
||||
@@ -272,6 +275,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (c) {
|
||||
_keyPair.physicalKey = PhysicalKeyboardKey.mediaPlayPause;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
@@ -283,6 +287,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (c) {
|
||||
_keyPair.physicalKey = PhysicalKeyboardKey.mediaStop;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
@@ -294,6 +299,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (c) {
|
||||
_keyPair.physicalKey = PhysicalKeyboardKey.mediaTrackPrevious;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
@@ -305,6 +311,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (c) {
|
||||
_keyPair.physicalKey = PhysicalKeyboardKey.mediaTrackNext;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
@@ -316,6 +323,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (c) {
|
||||
_keyPair.physicalKey = PhysicalKeyboardKey.audioVolumeUp;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
@@ -328,6 +336,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (c) {
|
||||
_keyPair.physicalKey = PhysicalKeyboardKey.audioVolumeDown;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
@@ -339,6 +348,43 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
},
|
||||
),
|
||||
),
|
||||
if (core.logic.showLocalControl &&
|
||||
core.settings.getLocalEnabled() &&
|
||||
core.actionHandler is AndroidActions)
|
||||
Builder(
|
||||
builder: (context) => SelectableCard(
|
||||
icon: Icons.settings_remote_outlined,
|
||||
isActive: _keyPair.androidAction != null,
|
||||
title: Text('Android System Action'),
|
||||
value: _keyPair.androidAction?.title,
|
||||
onPressed: () {
|
||||
showDropdown(
|
||||
context: context,
|
||||
builder: (c) => DropdownMenu(
|
||||
children: AndroidSystemAction.values
|
||||
.map(
|
||||
(action) => MenuButton(
|
||||
leading: Icon(action.icon),
|
||||
onPressed: (_) {
|
||||
_keyPair.androidAction = action;
|
||||
_keyPair.physicalKey = null;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.modifiers = [];
|
||||
_keyPair.touchPosition = Offset.zero;
|
||||
_keyPair.inGameAction = null;
|
||||
_keyPair.inGameActionValue = null;
|
||||
setState(() {});
|
||||
widget.onUpdate();
|
||||
},
|
||||
child: Text(action.title),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
if (core.connection.accessories.isNotEmpty) ...[
|
||||
@@ -368,6 +414,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (_) {
|
||||
_keyPair.inGameAction = InGameAction.headwindSpeed;
|
||||
_keyPair.inGameActionValue = value;
|
||||
_keyPair.androidAction = null;
|
||||
widget.onUpdate();
|
||||
setState(() {});
|
||||
},
|
||||
@@ -381,6 +428,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
onPressed: (_) {
|
||||
_keyPair.inGameAction = InGameAction.headwindHeartRateMode;
|
||||
_keyPair.inGameActionValue = null;
|
||||
_keyPair.androidAction = null;
|
||||
widget.onUpdate();
|
||||
setState(() {});
|
||||
},
|
||||
@@ -415,6 +463,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
_keyPair.touchPosition = Offset.zero;
|
||||
_keyPair.inGameAction = null;
|
||||
_keyPair.inGameActionValue = null;
|
||||
_keyPair.androidAction = null;
|
||||
widget.onUpdate();
|
||||
setState(() {});
|
||||
},
|
||||
@@ -450,16 +499,17 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
children: action.possibleValues!.map(
|
||||
(ingame) {
|
||||
return MenuButton(
|
||||
child: Text(ingame.toString()),
|
||||
onPressed: (_) {
|
||||
_keyPair.touchPosition = Offset.zero;
|
||||
_keyPair.physicalKey = null;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.inGameAction = action;
|
||||
_keyPair.inGameActionValue = ingame;
|
||||
widget.onUpdate();
|
||||
setState(() {});
|
||||
},
|
||||
child: Text(ingame.toString()),
|
||||
onPressed: (_) {
|
||||
_keyPair.touchPosition = Offset.zero;
|
||||
_keyPair.physicalKey = null;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
_keyPair.inGameAction = action;
|
||||
_keyPair.inGameActionValue = ingame;
|
||||
widget.onUpdate();
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
@@ -469,6 +519,7 @@ class _ButtonEditPageState extends State<ButtonEditPage> {
|
||||
_keyPair.touchPosition = Offset.zero;
|
||||
_keyPair.physicalKey = null;
|
||||
_keyPair.logicalKey = null;
|
||||
_keyPair.androidAction = null;
|
||||
_keyPair.inGameAction = action;
|
||||
_keyPair.inGameActionValue = null;
|
||||
widget.onUpdate();
|
||||
|
||||
@@ -79,6 +79,15 @@ class AndroidActions extends BaseActions {
|
||||
return Success("Key pressed: ${keyPair.toString()}");
|
||||
}
|
||||
|
||||
if (keyPair.androidAction != null) {
|
||||
if (!core.settings.getLocalEnabled() || !core.logic.showLocalControl || !isKeyDown) {
|
||||
return Ignored('Global action ignored');
|
||||
}
|
||||
await accessibilityHandler.performGlobalAction(keyPair.androidAction!.globalAction);
|
||||
await IAPManager.instance.incrementCommandCount();
|
||||
return Success("Global action: ${keyPair.androidAction!.title}");
|
||||
}
|
||||
|
||||
final point = await resolveTouchPosition(keyPair: keyPair, windowInfo: windowInfo);
|
||||
if (point != Offset.zero) {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:accessibility/accessibility.dart';
|
||||
import 'package:bike_control/gen/l10n.dart';
|
||||
import 'package:bike_control/main.dart';
|
||||
import 'package:bike_control/utils/actions/android.dart';
|
||||
@@ -13,6 +14,23 @@ import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||
import '../actions/base_actions.dart';
|
||||
import 'apps/custom_app.dart';
|
||||
|
||||
enum AndroidSystemAction {
|
||||
back('Back', Icons.arrow_back, GlobalAction.back),
|
||||
dpadCenter('DPAD Center', Icons.radio_button_checked_outlined, GlobalAction.dpadCenter),
|
||||
down('DPAD Down', Icons.arrow_downward, GlobalAction.down),
|
||||
right('DPAD Right', Icons.arrow_forward, GlobalAction.right),
|
||||
up('DPAD Up', Icons.arrow_upward, GlobalAction.up),
|
||||
left('DPAD Left', Icons.keyboard_arrow_left, GlobalAction.left),
|
||||
home('Home', Icons.home_outlined, GlobalAction.home),
|
||||
recents('Recents', Icons.apps, GlobalAction.recents);
|
||||
|
||||
final String title;
|
||||
final IconData icon;
|
||||
final GlobalAction globalAction;
|
||||
|
||||
const AndroidSystemAction(this.title, this.icon, this.globalAction);
|
||||
}
|
||||
|
||||
class Keymap {
|
||||
static Keymap custom = Keymap(keyPairs: []);
|
||||
|
||||
@@ -50,6 +68,7 @@ class Keymap {
|
||||
keyPair.isLongPress = false;
|
||||
keyPair.inGameAction = null;
|
||||
keyPair.inGameActionValue = null;
|
||||
keyPair.androidAction = null;
|
||||
}
|
||||
_updateStream.add(null);
|
||||
}
|
||||
@@ -112,6 +131,7 @@ class KeyPair {
|
||||
bool isLongPress;
|
||||
InGameAction? inGameAction;
|
||||
int? inGameActionValue;
|
||||
AndroidSystemAction? androidAction;
|
||||
|
||||
KeyPair({
|
||||
required this.buttons,
|
||||
@@ -122,6 +142,7 @@ class KeyPair {
|
||||
this.isLongPress = false,
|
||||
this.inGameAction,
|
||||
this.inGameActionValue,
|
||||
this.androidAction,
|
||||
});
|
||||
|
||||
bool get isSpecialKey =>
|
||||
@@ -146,6 +167,11 @@ class KeyPair {
|
||||
//_ when inGameAction != null && core.logic.emulatorEnabled => Icons.link,
|
||||
_ when inGameAction != null && inGameAction!.icon != null => inGameAction!.icon,
|
||||
|
||||
_ when androidAction != null &&
|
||||
core.logic.showLocalControl &&
|
||||
core.settings.getLocalEnabled() &&
|
||||
core.actionHandler is AndroidActions =>
|
||||
androidAction!.icon,
|
||||
_ when physicalKey != null && core.actionHandler.supportedModes.contains(SupportedMode.keyboard) =>
|
||||
RadixIcons.keyboard,
|
||||
_
|
||||
@@ -159,7 +185,11 @@ class KeyPair {
|
||||
}
|
||||
|
||||
bool get hasNoAction =>
|
||||
logicalKey == null && physicalKey == null && touchPosition == Offset.zero && inGameAction == null;
|
||||
logicalKey == null &&
|
||||
physicalKey == null &&
|
||||
touchPosition == Offset.zero &&
|
||||
inGameAction == null &&
|
||||
androidAction == null;
|
||||
|
||||
bool get hasActiveAction =>
|
||||
screenshotMode ||
|
||||
@@ -167,6 +197,10 @@ class KeyPair {
|
||||
core.logic.showLocalControl &&
|
||||
core.settings.getLocalEnabled() &&
|
||||
core.actionHandler.supportedModes.contains(SupportedMode.keyboard)) ||
|
||||
(androidAction != null &&
|
||||
core.logic.showLocalControl &&
|
||||
core.settings.getLocalEnabled() &&
|
||||
core.actionHandler is AndroidActions) ||
|
||||
(touchPosition != Offset.zero &&
|
||||
core.logic.showLocalRemoteOptions &&
|
||||
core.actionHandler.supportedModes.contains(SupportedMode.touch)) ||
|
||||
@@ -193,6 +227,8 @@ class KeyPair {
|
||||
inGameAction!.title,
|
||||
if (inGameActionValue != null) '$inGameActionValue',
|
||||
].joinToString(separator: ': ')
|
||||
: (androidAction != null && core.logic.showLocalControl && core.actionHandler is AndroidActions)
|
||||
? androidAction!.title
|
||||
: (isSpecialKey && core.actionHandler.supportedModes.contains(SupportedMode.media))
|
||||
? switch (physicalKey) {
|
||||
PhysicalKeyboardKey.mediaPlayPause => AppLocalizations.current.playPause,
|
||||
@@ -247,6 +283,7 @@ class KeyPair {
|
||||
'isLongPress': isLongPress,
|
||||
'inGameAction': inGameAction?.name,
|
||||
'inGameActionValue': inGameActionValue,
|
||||
'androidAction': androidAction?.name,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -295,6 +332,9 @@ class KeyPair {
|
||||
? InGameAction.values.firstOrNullWhere((element) => element.name == decoded['inGameAction'])
|
||||
: null,
|
||||
inGameActionValue: decoded['inGameActionValue'],
|
||||
androidAction: decoded.containsKey('androidAction')
|
||||
? AndroidSystemAction.values.firstOrNullWhere((element) => element.name == decoded['androidAction'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -309,7 +349,8 @@ class KeyPair {
|
||||
touchPosition == other.touchPosition &&
|
||||
isLongPress == other.isLongPress &&
|
||||
inGameAction == other.inGameAction &&
|
||||
inGameActionValue == other.inGameActionValue;
|
||||
inGameActionValue == other.inGameActionValue &&
|
||||
androidAction == other.androidAction;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
@@ -320,5 +361,6 @@ class KeyPair {
|
||||
isLongPress,
|
||||
inGameAction,
|
||||
inGameActionValue,
|
||||
androidAction,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user