├── .gitignore ├── CHANGELOG.txt ├── README.md ├── jquery.scannerdetection.compatibility.js ├── jquery.scannerdetection.js └── scannerdetection.jquery.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | # Exclude Eclipse project files and directories 46 | .project 47 | .settings 48 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | 1.2.1 2 | Add a onKeyDetect callback being called if any key (even non-chars) is detected 3 | Changed default scanButtonKeyCode to false (it turned out, that the previous value of '0' was actually used by some scanners) 4 | 1.2.0 5 | Add options startChar, ignoreIfFocusOn, scanButtonKeyCode, scanButtonLongPressThreshold 6 | 7 | 1.1.4 8 | Add script to extend compatibility to IE<9 9 | 10 | 1.1.3 11 | Change event.timestamp to Date.now() because Firefox has an issue with that 12 | 13 | 1.1.2 14 | Fix issue with tab key 15 | 16 | 1.1.1 17 | Fix issue with $(selector).scannerDetection('scanned string') 18 | 19 | 1.1.0 20 | Add events scannerDetectionComplete, scannerDetectionError, scannerDetectionReceive 21 | 22 | 1.0.0 23 | Initial version 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jQuery Scanner Detection 2 | ======================== 3 | 4 | **UNMAINTAINED**: this plugin is not maintained anymore! Use [onScan.js](https://github.com/axenox/onscan.js) instead - a completely rewritten vanilla JS library with enhanced functionality, support for latest mobile devices, paste-mode scanners and more. 5 | 6 | jQuery Scanner Detection is a small plugin to detect when user use a scanner (barcode, QR Code...) instead of a keyboard, and call specific callbacks. 7 | 8 | 9 | How use it 10 | ---------- 11 | To initialize the detection, 2 ways: 12 | 13 | $(selector).scannerDetection(); // Initialize with default options 14 | $(selector).scannerDetection({...}); // Initialize with an object that contains options 15 | $(selector).scannerDetection(function(){...}); // Initialize with a function that is onComplete callback 16 | 17 | To simulate a scanning after initialisation: 18 | 19 | $(selector).scannerDetection('scanned string'); 20 | 21 | To disable the detection (deinitialize): 22 | 23 | $(selector).scannerDetection(false); 24 | 25 | See a detailed tutorial with presets for different scanner models and first steps to take when starting [here](http://a.kabachnik.info/jquery-scannerdetection-tutorial.html). 26 | 27 | 28 | Options 29 | ------- 30 | ### onComplete 31 | Default: false 32 | Callback after detection of a successful scanning 33 | ### onError 34 | Default: false 35 | Callback after detection of a unsuccessful scanning (scanned string in parameter) 36 | ### onReceive 37 | Default: false 38 | Callback after receiving and processing a char (scanned char in parameter) 39 | ### onKeyDetect 40 | Default: false 41 | Callback after detecting a keyDown (key char in parameter) - in contrast to onReceive, this fires for non-character keys like tab, arrows, etc. too! 42 | ### onScanButtonLongPressed 43 | Default: false 44 | Callback after detection of a successfull scan while the scan button was pressed and held down. This can only be used if the scan button behaves as a key itself (see scanButtonKeyCode). This long press event can be used to add a secondary action. For example, if the primary action is to count some items with barcodes (e.g. products at goods-in), it is comes very handy if a number pad pops up on the screen when the scan button is held. Large number can then be easily typed it instead of scanning fifty times in a row. 45 | Note: this option requires scanButtonKeyCode to be set to a valid key code! 46 | ### timeBeforeScanTest 47 | Default: 100 48 | Wait duration (ms) after keypress event to check if scanning is finished 49 | ### avgTimeByChar 50 | Default: 30 51 | Average time (ms) between 2 chars. Used to do difference between keyboard typing and scanning 52 | ### minLength 53 | Default: 6 54 | Minimum length for a scanning 55 | ### endChar 56 | Default: [9,13] 57 | Chars to remove and means end of scanning 58 | ### startChar 59 | Default: [] 60 | Chars to remove and means start of scanning 61 | ### ignoreIfFocusOn 62 | Default: false 63 | Ignore scans if the currently focused element matches this selector. Per example, if you set this option to 'input', scanner detection will be disable if an input is focused, when the scan occurs. 64 | ### scanButtonKeyCode 65 | Default: false 66 | Key code of the scanner hardware button (if the scanner button a acts as a key itself). Knowing this key code is important, because it is not part of the scanned code and must be ignored. On the other hand, knowing it can be usefull: pressing the button multiple times fast normally results just in one scan, but you still could count the number of times pressed, allowing the user to input quantities this way (typical use case would be counting product at goods-in). 67 | ### scanButtonLongPressThreshold 68 | Default: 3 69 | You can let the user perform some special action by pressing and holding the scan button. In this case the button will issue multiple keydown events. This parameter sets, how many sequential events should be interpreted as holding the button down. 70 | ### stopPropagation 71 | Default: false 72 | Stop immediate propagation on keypress event 73 | ### preventDefault 74 | Default: false 75 | Prevent default action on keypress event 76 | 77 | 78 | Events 79 | ------ 80 | All callbacks are of type function and can also be bound as event listeners. 81 | Like this, you can add multiple callbacks for each event. 82 | Of course, events exist only if plugin is initialized on selector. 83 | 84 | $(selector) 85 | .bind('scannerDetectionComplete',function(e,data){...}) 86 | .bind('scannerDetectionError',function(e,data){...}) 87 | .bind('scannerDetectionReceive',function(e,data){...}) 88 | 89 | ### scannerDetectionComplete 90 | Callback after detection of a successful scanning 91 | Event data: {string: "scanned string"} 92 | ### scannerDetectionError 93 | Callback after detection of a unsuccessful scanning 94 | Event data: {string: "scanned string"} 95 | ### scannerDetectionReceive 96 | Callback after receive and process a char 97 | Event data: {evt: {original keypress event}} 98 | ### scannerDetectionKeyDetect 99 | Callback after detecting a keyDown - in contrast to onReceive, this fires for non-character keys like tab, arrows, etc. too! 100 | Event data: {evt: {original keypress event}} 101 | 102 | Requirements 103 | ------------ 104 | jQuery > 1.4.4. Note, that some odd side effects may occur before version 1.6, if your event handlers rely on using the event object (for example calling e.which from within the onKeyDetect handler). 105 | 106 | Browser compatibility 107 | --------------------- 108 | On old IE browser (IE<9), `Date.now()` and `Array.indexOf()` are not implemented. 109 | If you plan to use this plugin on these browsers, please add jquery.scannerdetection.compatibility.js file before the plugin. 110 | -------------------------------------------------------------------------------- /jquery.scannerdetection.compatibility.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Scanner Detection 3 | * 4 | * Copyright (c) 2013 Julien Maurel 5 | * 6 | * Licensed under the MIT license: 7 | * http://www.opensource.org/licenses/mit-license.php 8 | * 9 | * Project home: 10 | * https://github.com/julien-maurel/jQuery-Scanner-Detection 11 | * 12 | * Version: 1.2.0 13 | * 14 | * Implement some functions that not exist on old IE browser (IE<9) 15 | */ 16 | if (!Date.now) { 17 | Date.now = function now() { 18 | return new Date().getTime(); 19 | }; 20 | } 21 | 22 | if (!Array.prototype.indexOf) { 23 | Array.prototype.indexOf = function (searchElement, fromIndex) { 24 | if ( this === undefined || this === null ) { 25 | throw new TypeError( '"this" is null or not defined' ); 26 | } 27 | 28 | var length = this.length >>> 0; // Hack to convert object.length to a UInt32 29 | 30 | fromIndex = +fromIndex || 0; 31 | 32 | if (Math.abs(fromIndex) === Infinity) { 33 | fromIndex = 0; 34 | } 35 | 36 | if (fromIndex < 0) { 37 | fromIndex += length; 38 | if (fromIndex < 0) { 39 | fromIndex = 0; 40 | } 41 | } 42 | 43 | for (;fromIndex < length; fromIndex++) { 44 | if (this[fromIndex] === searchElement) { 45 | return fromIndex; 46 | } 47 | } 48 | 49 | return -1; 50 | }; 51 | } -------------------------------------------------------------------------------- /jquery.scannerdetection.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Scanner Detection 3 | * 4 | * Copyright (c) 2013 Julien Maurel 5 | * 6 | * Licensed under the MIT license: 7 | * http://www.opensource.org/licenses/mit-license.php 8 | * 9 | * Project home: 10 | * https://github.com/julien-maurel/jQuery-Scanner-Detection 11 | * 12 | * Version: 1.2.1 13 | * 14 | */ 15 | (function($){ 16 | $.fn.scannerDetection=function(options){ 17 | 18 | // If string given, call onComplete callback 19 | if(typeof options==="string"){ 20 | this.each(function(){ 21 | this.scannerDetectionTest(options); 22 | }); 23 | return this; 24 | } 25 | 26 | // If false (boolean) given, deinitialize plugin 27 | if(options === false){ 28 | this.each(function(){ 29 | this.scannerDetectionOff(); 30 | }); 31 | return this; 32 | } 33 | 34 | var defaults={ 35 | onComplete:false, // Callback after detection of a successfull scanning (scanned string in parameter) 36 | onError:false, // Callback after detection of a unsuccessfull scanning (scanned string in parameter) 37 | onReceive:false, // Callback after receiving and processing a char (scanned char in parameter) 38 | onKeyDetect:false, // Callback after detecting a keyDown (key char in parameter) - in contrast to onReceive, this fires for non-character keys like tab, arrows, etc. too! 39 | timeBeforeScanTest:100, // Wait duration (ms) after keypress event to check if scanning is finished 40 | avgTimeByChar:30, // Average time (ms) between 2 chars. Used to do difference between keyboard typing and scanning 41 | minLength:6, // Minimum length for a scanning 42 | endChar:[9,13], // Chars to remove and means end of scanning 43 | startChar:[], // Chars to remove and means start of scanning 44 | ignoreIfFocusOn:false, // do not handle scans if the currently focused element matches this selector 45 | scanButtonKeyCode:false, // Key code of the scanner hardware button (if the scanner button a acts as a key itself) 46 | scanButtonLongPressThreshold:3, // How many times the hardware button should issue a pressed event before a barcode is read to detect a longpress 47 | onScanButtonLongPressed:false, // Callback after detection of a successfull scan while the scan button was pressed and held down 48 | stopPropagation:false, // Stop immediate propagation on keypress event 49 | preventDefault:false // Prevent default action on keypress event 50 | }; 51 | if(typeof options==="function"){ 52 | options={onComplete:options} 53 | } 54 | if(typeof options!=="object"){ 55 | options=$.extend({},defaults); 56 | }else{ 57 | options=$.extend({},defaults,options); 58 | } 59 | 60 | this.each(function(){ 61 | var self=this, $self=$(self), firstCharTime=0, lastCharTime=0, stringWriting='', callIsScanner=false, testTimer=false, scanButtonCounter=0; 62 | var initScannerDetection=function(){ 63 | firstCharTime=0; 64 | stringWriting=''; 65 | scanButtonCounter=0; 66 | }; 67 | self.scannerDetectionOff=function(){ 68 | $self.unbind('keydown.scannerDetection'); 69 | $self.unbind('keypress.scannerDetection'); 70 | } 71 | self.isFocusOnIgnoredElement=function(){ 72 | if(!options.ignoreIfFocusOn) return false; 73 | if(typeof options.ignoreIfFocusOn === 'string') return $(':focus').is(options.ignoreIfFocusOn); 74 | if(typeof options.ignoreIfFocusOn === 'object' && options.ignoreIfFocusOn.length){ 75 | var focused=$(':focus'); 76 | for(var i=0; i=options.minLength && lastCharTime-firstCharTime options.scanButtonLongPressThreshold) options.onScanButtonLongPressed.call(self,stringWriting,scanButtonCounter); 99 | else if(options.onComplete) options.onComplete.call(self,stringWriting,scanButtonCounter); 100 | $self.trigger('scannerDetectionComplete',{string:stringWriting}); 101 | initScannerDetection(); 102 | return true; 103 | }else{ 104 | if(options.onError) options.onError.call(self,stringWriting); 105 | $self.trigger('scannerDetectionError',{string:stringWriting}); 106 | initScannerDetection(); 107 | return false; 108 | } 109 | } 110 | $self.data('scannerDetection',{options:options}).unbind('.scannerDetection').bind('keydown.scannerDetection',function(e){ 111 | // If it's just the button of the scanner, ignore it and wait for the real input 112 | if(options.scanButtonKeyCode !== false && e.which==options.scanButtonKeyCode) { 113 | scanButtonCounter++; 114 | // Cancel default 115 | e.preventDefault(); 116 | e.stopImmediatePropagation(); 117 | } 118 | // Add event on keydown because keypress is not triggered for non character keys (tab, up, down...) 119 | // So need that to check endChar and startChar (that is often tab or enter) and call keypress if necessary 120 | else if((firstCharTime && options.endChar.indexOf(e.which)!==-1) 121 | || (!firstCharTime && options.startChar.indexOf(e.which)!==-1)){ 122 | // Clone event, set type and trigger it 123 | var e2=jQuery.Event('keypress',e); 124 | e2.type='keypress.scannerDetection'; 125 | $self.triggerHandler(e2); 126 | // Cancel default 127 | e.preventDefault(); 128 | e.stopImmediatePropagation(); 129 | } 130 | // Fire keyDetect event in any case! 131 | if(options.onKeyDetect) options.onKeyDetect.call(self,e); 132 | $self.trigger('scannerDetectionKeyDetect',{evt:e}); 133 | 134 | }).bind('keypress.scannerDetection',function(e){ 135 | if (this.isFocusOnIgnoredElement()) return; 136 | if(options.stopPropagation) e.stopImmediatePropagation(); 137 | if(options.preventDefault) e.preventDefault(); 138 | 139 | if(firstCharTime && options.endChar.indexOf(e.which)!==-1){ 140 | e.preventDefault(); 141 | e.stopImmediatePropagation(); 142 | callIsScanner=true; 143 | }else if(!firstCharTime && options.startChar.indexOf(e.which)!==-1){ 144 | e.preventDefault(); 145 | e.stopImmediatePropagation(); 146 | callIsScanner=false; 147 | }else{ 148 | if (typeof(e.which) != 'undefined'){ 149 | stringWriting+=String.fromCharCode(e.which); 150 | } 151 | callIsScanner=false; 152 | } 153 | 154 | if(!firstCharTime){ 155 | firstCharTime=Date.now(); 156 | } 157 | lastCharTime=Date.now(); 158 | 159 | if(testTimer) clearTimeout(testTimer); 160 | if(callIsScanner){ 161 | self.scannerDetectionTest(); 162 | testTimer=false; 163 | }else{ 164 | testTimer=setTimeout(self.scannerDetectionTest,options.timeBeforeScanTest); 165 | } 166 | 167 | if(options.onReceive) options.onReceive.call(self,e); 168 | $self.trigger('scannerDetectionReceive',{evt:e}); 169 | }); 170 | }); 171 | return this; 172 | } 173 | })(jQuery); 174 | -------------------------------------------------------------------------------- /scannerdetection.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scannerdetection", 3 | "version": "1.2.0", 4 | "title": "jQuery Scanner Detection", 5 | "author": { 6 | "name": "Julien Maurel", 7 | "url": "https://github.com/julien-maurel" 8 | }, 9 | "licenses": [ 10 | { 11 | "type": "MIT", 12 | "url": "http://www.opensource.org/licenses/mit-license.php" 13 | } 14 | ], 15 | "dependencies": { 16 | "jquery": ">=1.2" 17 | }, 18 | "description": "jQuery Scanner Detection is a small plugin to detect when user use a scanner (barcode, QR Code...) instead of a keyboard, and call specific callbacks.", 19 | "keywords": [ 20 | "scanner", 21 | "scanning", 22 | "barcode", 23 | "QR", 24 | "QRCode", 25 | "event" 26 | ], 27 | "homepage": "https://github.com/julien-maurel/jQuery-Scanner-Detection", 28 | "bugs": "https://github.com/julien-maurel/jQuery-Scanner-Detection/issues", 29 | "docs": "https://github.com/julien-maurel/jQuery-Scanner-Detection", 30 | "demo": "https://github.com/julien-maurel/jQuery-Scanner-Detection", 31 | "files": [ 32 | "jquery.scannerdetection.js", 33 | "jquery.scannerdetection.compatibility.js" 34 | ] 35 | } 36 | --------------------------------------------------------------------------------