feat, trackpad speed

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou 2025-05-08 16:50:09 +08:00
parent 9475743b4e
commit 4c30def7dc
7 changed files with 171 additions and 8 deletions

View file

@ -1623,6 +1623,43 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
msgBoxCommon(ffi.dialogManager, 'Custom Image Quality', content, [btnClose]);
}
trackpadSpeedDialog(SessionID sessionId, FFI ffi) async {
final speed = await bind.sessionGetFlutterOption(
sessionId: sessionId, k: kKeyTrackpadSpeed);
var initSpeed = kDefaultTrackpadSpeed;
if (speed != null && speed.isNotEmpty) {
try {
initSpeed = double.parse(speed);
} catch (e) {
debugPrint('Failed to parse the trackpad speed, "$speed": $e');
}
}
if (initSpeed < kMinTrackpadSpeed || initSpeed > kMaxTrackpadSpeed) {
initSpeed = kDefaultTrackpadSpeed;
}
final curSpeed = SimpleWrapper(initSpeed);
final btnClose = dialogButton('Close', onPressed: () async {
if (curSpeed.value <= kMaxTrackpadSpeed &&
curSpeed.value >= kMinTrackpadSpeed &&
(curSpeed.value - initSpeed).abs() > 0.01) {
await bind.sessionSetFlutterOption(
sessionId: sessionId,
k: kKeyTrackpadSpeed,
v: curSpeed.value.toString());
await ffi.inputModel.updateTrackpadSpeed();
}
ffi.dialogManager.dismissAll();
});
msgBoxCommon(
ffi.dialogManager,
'Trackpad speed',
TrackpadSpeedWidget(
value: curSpeed,
),
[btnClose]);
}
void deleteConfirmDialog(Function onSubmit, String title) async {
gFFI.dialogManager.show(
(setState, close, context) {

View file

@ -248,3 +248,76 @@ List<(String, String)> otherDefaultSettings() {
return v;
}
class TrackpadSpeedWidget extends StatefulWidget {
final SimpleWrapper<double> value;
TrackpadSpeedWidget({Key? key, required this.value});
@override
TrackpadSpeedWidgetState createState() => TrackpadSpeedWidgetState();
}
class TrackpadSpeedWidgetState extends State<TrackpadSpeedWidget> {
final TextEditingController _controller = TextEditingController();
set value(double v) => widget.value.value = v;
double get value => widget.value.value;
void updateValue(double newValue) {
setState(() {
value = newValue.clamp(kMinTrackpadSpeed, kMaxTrackpadSpeed);
_controller.text = ((value * 100.0).round()).toString();
});
}
@override
Widget build(BuildContext context) {
if (_controller.text.isEmpty) {
_controller.text = ((value * 100.0).round()).toString();
}
return Row(
children: [
Expanded(
flex: 3,
child: Slider(
value: value,
min: kMinTrackpadSpeed,
max: kMaxTrackpadSpeed,
divisions: ((kMaxTrackpadSpeed - kMinTrackpadSpeed) / 0.1).round(),
onChanged: (double v) => updateValue(v),
),
),
Expanded(
flex: 1,
child: Row(
children: [
SizedBox(
width: 56,
child: TextField(
controller: _controller,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
onSubmitted: (text) {
int? v = int.tryParse(text);
if (v != null) {
updateValue(v.toDouble() / 100.0);
}
},
style: const TextStyle(fontSize: 13),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0),
),
),
).marginOnly(right: 8.0),
Text(
'%',
style: const TextStyle(fontSize: 15),
)
],
)),
],
);
}
}

View file

@ -226,6 +226,12 @@ const double kDefaultQuality = 50;
const double kMaxQuality = 100;
const double kMaxMoreQuality = 2000;
// trackpad speed
const String kKeyTrackpadSpeed = 'trackpad-speed';
const double kMinTrackpadSpeed = 0.1;
const double kDefaultTrackpadSpeed = 1.0;
const double kMaxTrackpadSpeed = 10;
// incomming (should be incoming) is kept, because change it will break the previous setting.
const String kKeyPrinterIncomingJobAction = 'printer-incomming-job-action';
const String kValuePrinterIncomingJobDismiss = 'dismiss';

View file

@ -4,6 +4,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hbb/common/widgets/audio_input.dart';
import 'package:flutter_hbb/common/widgets/dialog.dart';
import 'package:flutter_hbb/common/widgets/toolbar.dart';
import 'package:flutter_hbb/models/chat_model.dart';
import 'package:flutter_hbb/models/state_model.dart';
@ -1594,10 +1595,28 @@ class _KeyboardMenu extends StatelessWidget {
viewMode(),
Divider(),
...toolbarToggles(),
...mouseSpeed(),
...mobileActions(),
]);
}
mouseSpeed() {
final speedWidgets = [];
final sessionId = ffi.sessionId;
if (isDesktop) {
if (ffi.ffiModel.keyboard) {
final enabled = !ffi.ffiModel.viewOnly;
final trackpad = MenuButton(
child: Text(translate('Trackpad speed')).paddingOnly(left: 26.0),
onPressed: enabled ? () => trackpadSpeedDialog(sessionId, ffi) : null,
ffi: ffi,
);
speedWidgets.add(trackpad);
}
}
return speedWidgets;
}
keyboardMode() {
return futureBuilder(future: () async {
return await bind.sessionGetKeyboardMode(sessionId: ffi.sessionId) ??

View file

@ -345,8 +345,10 @@ class InputModel {
var _fling = false;
Timer? _flingTimer;
final _flingBaseDelay = 30;
// trackpad, peer linux
final _trackpadSpeed = 0.06;
final _trackpadAdjustPeerLinux = 0.06;
// This is an experience value.
final _trackpadAdjustMacToWin = 2.50;
double _trackpadSpeed = kDefaultTrackpadSpeed;
var _trackpadScrollUnsent = Offset.zero;
var _lastScale = 1.0;
@ -385,6 +387,22 @@ class InputModel {
}
}
Future<void> updateTrackpadSpeed() async {
final speed = await bind.sessionGetFlutterOption(
sessionId: sessionId, k: kKeyTrackpadSpeed);
if (speed != null && speed.isNotEmpty) {
try {
_trackpadSpeed = double.parse(speed);
} catch (e) {
debugPrint('Failed to parse the trackpad speed, "$speed": $e');
}
}
if (_trackpadSpeed < kMinTrackpadSpeed ||
_trackpadSpeed > kMaxTrackpadSpeed) {
_trackpadSpeed = kDefaultTrackpadSpeed;
}
}
void handleKeyDownEventModifiers(KeyEvent e) {
KeyUpEvent upEvent(e) => KeyUpEvent(
physicalKey: e.physicalKey,
@ -888,13 +906,16 @@ class InputModel {
}
}
final delta = e.panDelta;
var delta = e.panDelta * _trackpadSpeed;
if (isMacOS && peerPlatform == kPeerPlatformWindows) {
delta *= _trackpadAdjustMacToWin;
}
_trackpadLastDelta = delta;
var x = delta.dx.toInt();
var y = delta.dy.toInt();
if (peerPlatform == kPeerPlatformLinux) {
_trackpadScrollUnsent += (delta * _trackpadSpeed);
_trackpadScrollUnsent += (delta * _trackpadAdjustPeerLinux);
x = _trackpadScrollUnsent.dx.truncate();
y = _trackpadScrollUnsent.dy.truncate();
_trackpadScrollUnsent -= Offset(x.toDouble(), y.toDouble());
@ -942,8 +963,8 @@ class InputModel {
var dx = x.toInt();
var dy = y.toInt();
if (parent.target?.ffiModel.pi.platform == kPeerPlatformLinux) {
dx = (x * _trackpadSpeed).toInt();
dy = (y * _trackpadSpeed).toInt();
dx = (x * _trackpadAdjustPeerLinux).toInt();
dy = (y * _trackpadAdjustPeerLinux).toInt();
}
var delay = _flingBaseDelay;
@ -989,7 +1010,10 @@ class InputModel {
_stopFling = false;
// 2.0 is an experience value
double minFlingValue = 2.0;
double minFlingValue = 2.0 * _trackpadSpeed;
if (isMacOS && peerPlatform == kPeerPlatformWindows) {
minFlingValue *= _trackpadAdjustMacToWin;
}
if (_trackpadLastDelta.dx.abs() > minFlingValue ||
_trackpadLastDelta.dy.abs() > minFlingValue) {
_fling = true;

View file

@ -2991,6 +2991,10 @@ class FFI {
textureModel.updateCurrentDisplay(display ?? 0);
}
if (isDesktop) {
inputModel.updateTrackpadSpeed();
}
// CAUTION: `sessionStart()` and `sessionStartWithDisplays()` are an async functions.
// Though the stream is returned immediately, the stream may not be ready.
// Any operations that depend on the stream should be carefully handled.

@ -1 +1 @@
Subproject commit 7839dcf4e4ddc3feab9b52b0ae1903d443bc084d
Subproject commit 751b9711febb8a1a8c40d98b156381072a9459a0