The code from Karan works, but when the app is in Debug Mode, instead of using the event.logicalKey.debugName == "Arrow Up", we could use event.logicalKey == LogicalKeyboardKey.arrowUp which works in both the debug and release mode.
class _MyKeyboardScrollingPageState extends State<MyKeyboardScrollingPage> { final ScrollController _controller = ScrollController(); final FocusNode _focusNode = FocusNode(); void _handleKeyEvent(RawKeyEvent event) { var offset = _controller.offset; if (event.logicalKey == LogicalKeyboardKey.arrowUp) { setState(() { if (kReleaseMode) { _controller.animateTo(offset - 200, duration: Duration(milliseconds: 30), curve: Curves.ease); } else { _controller.animateTo(offset - 200, duration: Duration(milliseconds: 30), curve: Curves.ease); } }); } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) { setState(() { if (kReleaseMode) { _controller.animateTo(offset + 200, duration: Duration(milliseconds: 30), curve: Curves.ease); } else { _controller.animateTo(offset + 200, duration: Duration(milliseconds: 30), curve: Curves.ease); } }); } } @override void dispose() { _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: RawKeyboardListener( autoFocus = true, focusNode = _focusNode, onKey: _handleKeyEvent, child: SingleChildScrollView( controller: _controller, child: SomeAwesomeWidget(), ), ), ); } }