From abd06c827f04a56b2ae31389af6b76c01e48ff9b Mon Sep 17 00:00:00 2001 From: marwen Date: Tue, 28 May 2024 09:47:57 +0000 Subject: [PATCH 1/2] Logging Key Events, Sanitizing Input, Character Encoding and Conversion --- lib/flutter_barcode_listener.dart | 69 ++++++++----------------------- 1 file changed, 18 insertions(+), 51 deletions(-) diff --git a/lib/flutter_barcode_listener.dart b/lib/flutter_barcode_listener.dart index 2dd724d..e16e6f8 100644 --- a/lib/flutter_barcode_listener.dart +++ b/lib/flutter_barcode_listener.dart @@ -7,51 +7,21 @@ import 'package:flutter/services.dart'; typedef BarcodeScannedCallback = void Function(String barcode); -/// This widget will listen for raw PHYSICAL keyboard events -/// even when other controls have primary focus. -/// It will buffer all characters coming in specifed `bufferDuration` time frame -/// that end with line feed character and call callback function with result. -/// Keep in mind this widget will listen for events even when not visible. -/// Windows seems to be using the [RawKeyDownEvent] instead of the -/// [RawKeyUpEvent], this behaviour can be managed by setting [useKeyDownEvent]. class BarcodeKeyboardListener extends StatefulWidget { final Widget child; final BarcodeScannedCallback _onBarcodeScanned; final Duration _bufferDuration; final bool useKeyDownEvent; - - /// Make barcode scanner return case sensitive characters - /// - /// Default value is false, It will sent scanned barcode with case sensitive - /// characters. It listen to [LogicalKeyboardKey.shiftLeft] - /// Currently support for Android final bool caseSensitive; - /// This widget will listen for raw PHYSICAL keyboard events - /// even when other controls have primary focus. - /// It will buffer all characters coming in specifed `bufferDuration` time frame - /// that end with line feed character and call callback function with result. - /// Keep in mind this widget will listen for events even when not visible. - BarcodeKeyboardListener( - {Key? key, - - /// Child widget to be displayed. - required this.child, - - /// Callback to be called when barcode is scanned. - required Function(String) onBarcodeScanned, - - /// When experiencing issueswith empty barcodes on Windows, - /// set this value to true. Default value is `false`. - this.useKeyDownEvent = false, - - /// Maximum time between two key events. - /// If time between two key events is longer than this value - /// previous keys will be ignored. - Duration bufferDuration = hundredMs, - this.caseSensitive = false, - }) - : _onBarcodeScanned = onBarcodeScanned, + BarcodeKeyboardListener({ + Key? key, + required this.child, + required Function(String) onBarcodeScanned, + this.useKeyDownEvent = false, + Duration bufferDuration = hundredMs, + this.caseSensitive = false, + }) : _onBarcodeScanned = onBarcodeScanned, _bufferDuration = bufferDuration, super(key: key); @@ -71,13 +41,9 @@ class _BarcodeKeyboardListenerState extends State { final BarcodeScannedCallback _onBarcodeScannedCallback; final Duration _bufferDuration; - final _controller = StreamController(); - final bool _useKeyDownEvent; - final bool _caseSensitive; - bool _isShiftPressed = false; _BarcodeKeyboardListenerState(this._onBarcodeScannedCallback, @@ -88,15 +54,17 @@ class _BarcodeKeyboardListenerState extends State { } void onKeyEvent(String? char) { - //remove any pending characters older than bufferDuration value checkPendingCharCodesToClear(); _lastScannedCharCodeTime = DateTime.now(); if (char == lineFeed) { - _onBarcodeScannedCallback.call(_scannedChars.join()); + String scannedCode = _scannedChars.join(); + print("Scanned barcode: $scannedCode"); + _onBarcodeScannedCallback.call(scannedCode); resetScannedCharCodes(); } else { - //add character to list of scanned characters; - _scannedChars.add(char!); + if (char != null && RegExp(r'^[a-zA-Z0-9]$').hasMatch(char)) { + _scannedChars.add(char); + } } } @@ -114,11 +82,9 @@ class _BarcodeKeyboardListenerState extends State { _scannedChars = []; } - void addScannedCharCode(String charCode) { - _scannedChars.add(charCode); - } - void _keyBoardCallback(RawKeyEvent keyEvent) { + print("Key event: ${keyEvent.character}, Logical key: ${keyEvent.logicalKey}"); + if (keyEvent.logicalKey.keyId > 255 && keyEvent.data.logicalKey != LogicalKeyboardKey.enter && keyEvent.data.logicalKey != LogicalKeyboardKey.shiftLeft) return; @@ -131,7 +97,8 @@ class _BarcodeKeyboardListenerState extends State { if (_isShiftPressed && _caseSensitive) { _isShiftPressed = false; _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataAndroid).codePoint).toUpperCase()); + ((keyEvent.data) as RawKeyEventDataAndroid).codePoint) + .toUpperCase()); } else { _controller.sink.add(String.fromCharCode( ((keyEvent.data) as RawKeyEventDataAndroid).codePoint)); From 1d005a9fa0ca75ff1b79e66821ee91f470e02afe Mon Sep 17 00:00:00 2001 From: marwen Date: Tue, 28 May 2024 13:55:12 +0000 Subject: [PATCH 2/2] migrate to hardwarekeyboard instead rawkeyboard --- lib/flutter_barcode_listener.dart | 52 +++++++++---------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/lib/flutter_barcode_listener.dart b/lib/flutter_barcode_listener.dart index e16e6f8..2784a55 100644 --- a/lib/flutter_barcode_listener.dart +++ b/lib/flutter_barcode_listener.dart @@ -1,7 +1,6 @@ library flutter_barcode_listener; import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -48,7 +47,7 @@ class _BarcodeKeyboardListenerState extends State { _BarcodeKeyboardListenerState(this._onBarcodeScannedCallback, this._bufferDuration, this._useKeyDownEvent, this._caseSensitive) { - RawKeyboard.instance.addListener(_keyBoardCallback); + HardwareKeyboard.instance.addListener(_keyBoardCallback); _keyboardSubscription = _controller.stream.where((char) => char != null).listen(onKeyEvent); } @@ -82,49 +81,28 @@ class _BarcodeKeyboardListenerState extends State { _scannedChars = []; } - void _keyBoardCallback(RawKeyEvent keyEvent) { - print("Key event: ${keyEvent.character}, Logical key: ${keyEvent.logicalKey}"); + void _keyBoardCallback(KeyboardEvent keyEvent) { + print("Key event: ${keyEvent.character}, Physical key: ${keyEvent.physicalKey}"); - if (keyEvent.logicalKey.keyId > 255 && - keyEvent.data.logicalKey != LogicalKeyboardKey.enter && - keyEvent.data.logicalKey != LogicalKeyboardKey.shiftLeft) return; - if ((!_useKeyDownEvent && keyEvent is RawKeyUpEvent) || - (_useKeyDownEvent && keyEvent is RawKeyDownEvent)) { - if (keyEvent.data is RawKeyEventDataAndroid) { - if (keyEvent.data.logicalKey == LogicalKeyboardKey.shiftLeft) { + if (keyEvent.physicalKey.usbHidUsage > 255 && + keyEvent.physicalKey != PhysicalKeyboardKey.enter && + keyEvent.physicalKey != PhysicalKeyboardKey.shiftLeft) return; + if ((!_useKeyDownEvent && keyEvent is KeyUpEvent) || + (_useKeyDownEvent && keyEvent is KeyDownEvent)) { + if (keyEvent is KeyDownEvent) { + if (keyEvent.physicalKey == PhysicalKeyboardKey.shiftLeft) { _isShiftPressed = true; } else { if (_isShiftPressed && _caseSensitive) { _isShiftPressed = false; - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataAndroid).codePoint) - .toUpperCase()); + _controller.sink.add(keyEvent.character?.toUpperCase()); } else { - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataAndroid).codePoint)); + _controller.sink.add(keyEvent.character); } } - } else if (keyEvent.data is RawKeyEventDataFuchsia) { - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataFuchsia).codePoint)); - } else if (keyEvent.data.logicalKey == LogicalKeyboardKey.enter) { + } + if (keyEvent.physicalKey == PhysicalKeyboardKey.enter) { _controller.sink.add(lineFeed); - } else if (keyEvent.data is RawKeyEventDataWeb) { - _controller.sink.add(((keyEvent.data) as RawKeyEventDataWeb).keyLabel); - } else if (keyEvent.data is RawKeyEventDataLinux) { - _controller.sink - .add(((keyEvent.data) as RawKeyEventDataLinux).keyLabel); - } else if (keyEvent.data is RawKeyEventDataWindows) { - _controller.sink.add(String.fromCharCode( - ((keyEvent.data) as RawKeyEventDataWindows).keyCode)); - } else if (keyEvent.data is RawKeyEventDataMacOs) { - _controller.sink - .add(((keyEvent.data) as RawKeyEventDataMacOs).characters); - } else if (keyEvent.data is RawKeyEventDataIos) { - _controller.sink - .add(((keyEvent.data) as RawKeyEventDataIos).characters); - } else { - _controller.sink.add(keyEvent.character); } } } @@ -138,7 +116,7 @@ class _BarcodeKeyboardListenerState extends State { void dispose() { _keyboardSubscription.cancel(); _controller.close(); - RawKeyboard.instance.removeListener(_keyBoardCallback); + HardwareKeyboard.instance.removeListener(_keyBoardCallback); super.dispose(); } }