Skip to content

Commit 248a11b

Browse files
victorsanniDBowen33
authored andcommitted
Make CupertinoButton interactive by keyboard shortcuts (flutter#153126)
This should have been added with flutter#150721.
1 parent 27af7ac commit 248a11b

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

packages/flutter/lib/src/cupertino/button.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
library;
77

88
import 'package:flutter/foundation.dart';
9+
import 'package:flutter/semantics.dart';
910
import 'package:flutter/widgets.dart';
1011

1112
import 'colors.dart';
@@ -300,6 +301,13 @@ class _CupertinoButtonState extends State<CupertinoButton> with SingleTickerProv
300301
}
301302
}
302303

304+
void _handleTap([Intent? _]) {
305+
if (widget.onPressed != null) {
306+
widget.onPressed!();
307+
context.findRenderObject()!.sendSemanticsEvent(const TapSemanticEvent());
308+
}
309+
}
310+
303311
void _animate() {
304312
if (_animationController.isAnimating) {
305313
return;
@@ -321,6 +329,10 @@ class _CupertinoButtonState extends State<CupertinoButton> with SingleTickerProv
321329
});
322330
}
323331

332+
late final Map<Type, Action<Intent>> _actionMap = <Type, Action<Intent>>{
333+
ActivateIntent: CallbackAction<ActivateIntent>(onInvoke: _handleTap),
334+
};
335+
324336
@override
325337
Widget build(BuildContext context) {
326338
final bool enabled = widget.enabled;
@@ -368,6 +380,7 @@ class _CupertinoButtonState extends State<CupertinoButton> with SingleTickerProv
368380
return MouseRegion(
369381
cursor: enabled && kIsWeb ? SystemMouseCursors.click : MouseCursor.defer,
370382
child: FocusableActionDetector(
383+
actions: _actionMap,
371384
focusNode: widget.focusNode,
372385
autofocus: widget.autofocus,
373386
onFocusChange: widget.onFocusChange,

packages/flutter/test/cupertino/button_test.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart';
77
import 'package:flutter/gestures.dart';
88
import 'package:flutter/rendering.dart';
99
import 'package:flutter/scheduler.dart';
10+
import 'package:flutter/services.dart';
1011
import 'package:flutter_test/flutter_test.dart';
1112

1213
import '../widgets/semantics_tester.dart';
@@ -731,6 +732,41 @@ void main() {
731732
),
732733
);
733734
});
735+
736+
testWidgets('Button can be activated by keyboard shortcuts', (WidgetTester tester) async {
737+
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
738+
bool value = true;
739+
await tester.pumpWidget(CupertinoApp(
740+
home: Center(
741+
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
742+
return CupertinoButton(
743+
onPressed: () {
744+
setState(() {
745+
value = !value;
746+
});
747+
},
748+
autofocus: true,
749+
child: const Text('Tap me'),
750+
);
751+
}),
752+
),
753+
),
754+
);
755+
await tester.pump();
756+
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
757+
await tester.pump();
758+
// On web, buttons don't respond to the enter key.
759+
expect(value, kIsWeb ? isTrue : isFalse);
760+
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
761+
await tester.pump();
762+
expect(value, isTrue);
763+
await tester.sendKeyEvent(LogicalKeyboardKey.space);
764+
await tester.pump();
765+
expect(value, isFalse);
766+
await tester.sendKeyEvent(LogicalKeyboardKey.space);
767+
await tester.pump();
768+
expect(value, isTrue);
769+
});
734770
}
735771

736772
Widget boilerplate({ required Widget child }) {

0 commit comments

Comments
 (0)