Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect when input box filled by keyboard and when by barcode scanner.

How I can programmatically detect when text input filled by typing on keyboard and when it filled automatically by bar-code scanner?

like image 382
WelcomeTo Avatar asked Jul 02 '12 09:07

WelcomeTo


People also ask

How do I tell if keyboard input is coming from a barcode scanner?

Meaning that you can tell them to prefix (and/or suffix) their input with some sentinel characters that indicate the input is coming from the barcode scanner, rather than a standard keyboard. (Check your barcode scanner's user manual for more information.)

How do I use a barcode scanner as a keyboard?

In order to use the Barcodescanner Keyboard you need to enable it. Do this by opening Android Settings , Language & keyboard and enable the input method named Barcode Keyboard by checking the box. Confirm the security warning (see privacy). After the input method was enabled it must be activated.

How barcode reader reads input or read information?

Barcode scanners can be connected to a computer through a serial port , keyboard port , or an interface device called a wedge . A barcode reader works by directing a beam of light across the bar code and measuring the amount of light that is reflected back.


8 Answers

I wrote this answer, because my Barcode Scanner Motorola LS1203 generated keypress event, so I can't use Utkanos's solution.

My solution is:

var BarcodeScanerEvents = function() {
     this.initialize.apply(this, arguments);
};

BarcodeScanerEvents.prototype = {
    initialize: function() {
       $(document).on({
          keyup: $.proxy(this._keyup, this)
       });
    },
    _timeoutHandler: 0,
    _inputString: '',
    _keyup: function (e) {
        if (this._timeoutHandler) {
            clearTimeout(this._timeoutHandler);
            this._inputString += String.fromCharCode(e.which);
        } 

        this._timeoutHandler = setTimeout($.proxy(function () {
            if (this._inputString.length <= 3) {
                this._inputString = '';
                return;
            }

            $(document).trigger('onbarcodescaned', this._inputString);

            this._inputString = '';

        }, this), 20);
    }
};
like image 172
Vitall Avatar answered Oct 01 '22 15:10

Vitall


Adapted the super useful Vitall answer above to utilize an IIFE instead of prototyping, in case anyone just seeing this now is into that.

This also uses the 'keypress' event instead of keyup, which allowed me to reliably use KeyboardEvent.key, since KeyboardEvent.which is deprecated now. I found this to work for barcode scanning as well as magnetic-strip card swipes.

In my experience, handling card swipes with keyup caused me to do extra work handling 'Shift' keycodes e.g. a Shift code would be followed by the code representing '/', with the intended character being '?'. Using 'keypress' solved this as well.

(function($) {
    var _timeoutHandler = 0,
        _inputString = '',
        _onKeypress = function(e) {
            if (_timeoutHandler) {
                clearTimeout(_timeoutHandler);
            }
            _inputString += e.key;

            _timeoutHandler = setTimeout(function () {
                if (_inputString.length <= 3) {
                    _inputString = '';
                    return;
                }
                $(e.target).trigger('altdeviceinput', _inputString);
                _inputString = '';

            }, 20);
        };
    $(document).on({
        keypress: _onKeypress
    });
})($);
like image 41
Spence7 Avatar answered Oct 01 '22 15:10

Spence7


Well a barcode won't fire any key events so you could do something like:

$('#my_field').on({
    keypress: function() { typed_into = true; },
    change: function() {
        if (typed_into) {
            alert('type');
            typed_into = false; //reset type listener
        } else {
            alert('not type');
        }
    }
});

Depending on when you want to evaluate this, you may want to do this check not on change but on submit, or whatever.

like image 39
Mitya Avatar answered Oct 01 '22 17:10

Mitya


you can try following example, using jQuery plugin https://plugins.jquery.com/scannerdetection/

Its highly configurable, time based scanner detector. It can be used as solution for prefix/postfix based, time based barcode scanner.

Tutorial for usage and best practices, as well discussed about various Barcode Scanner Models and how to deal with it. http://a.kabachnik.info/jquery-scannerdetection-tutorial.html

$(window).ready(function(){

	//$("#bCode").scannerDetection();

	console.log('all is well');
	
	$(window).scannerDetection();
	$(window).bind('scannerDetectionComplete',function(e,data){
            console.log('complete '+data.string);
            $("#bCode").val(data.string);
        })
        .bind('scannerDetectionError',function(e,data){
            console.log('detection error '+data.string);
        })
        .bind('scannerDetectionReceive',function(e,data){
            console.log('Recieve');
            console.log(data.evt.which);
        })

        //$(window).scannerDetection('success');
<input id='bCode'type='text' value='barcode appears here'/>
like image 24
dextermini Avatar answered Oct 01 '22 16:10

dextermini


For ES6 2019 version of Vitall answer.

const events = mitt()

class BarcodeScaner {
  initialize = () => {
    document.addEventListener('keypress', this.keyup)
    if (this.timeoutHandler) {
      clearTimeout(this.timeoutHandler)
    }
    this.timeoutHandler = setTimeout(() => {
      this.inputString = ''
    }, 10)
  }

  close = () => {
    document.removeEventListener('keypress', this.keyup)
  }

  timeoutHandler = 0

  inputString = ''

  keyup = (e) => {
    if (this.timeoutHandler) {
      clearTimeout(this.timeoutHandler)
      this.inputString += String.fromCharCode(e.keyCode)
    }

    this.timeoutHandler = setTimeout(() => {
      if (this.inputString.length <= 3) {
        this.inputString = ''
        return
      }
      events.emit('onbarcodescaned', this.inputString)

      this.inputString = ''
    }, 10)
  }
}

Can be used with react hooks like so:

const ScanComponent = (props) => {
  const [scanned, setScanned] = useState('')
  useEffect(() => {
    const barcode = new BarcodeScaner()
    barcode.initialize()
    return () => {
      barcode.close()
    }
  }, [])

  useEffect(() => {
    const scanHandler = code => {
      console.log(code)
      setScanned(code)
    }

    events.on('onbarcodescaned', scanHandler)
    return () => {
      events.off('onbarcodescaned', scanHandler)
    }
  }, [/* here put dependencies for your scanHandler ;) */])
  return <div>{scanned}</div>
}

I use mitt from npm for events, but you can use whatever you prefer ;)

Tested on Zebra DS4208

like image 41
MisieQQQ Avatar answered Oct 01 '22 15:10

MisieQQQ


The solution from Vitall only works fine if you already hit at least one key. If you don't the first character will be ignored (if(this._timeoutHandler) returns false and the char will not be appended).

If you want to begin scanning immediately you can use the following code:

var BarcodeScanerEvents = function() {
	this.initialize.apply(this, arguments);
};

BarcodeScanerEvents.prototype = {
	initialize : function() {
		$(document).on({
			keyup : $.proxy(this._keyup, this)
		});
	},
	_timeoutHandler : 0,
	_inputString : '',
	_keyup : function(e) {
		if (this._timeoutHandler) {
			clearTimeout(this._timeoutHandler);
		}
		this._inputString += String.fromCharCode(e.which);

		this._timeoutHandler = setTimeout($.proxy(function() {
			if (this._inputString.length <= 3) {
				this._inputString = '';
				return;
			}

			$(document).trigger('onbarcodescaned', this._inputString);

			this._inputString = '';

		}, this), 20);
	}
};
like image 21
Mhastrich Avatar answered Oct 01 '22 15:10

Mhastrich


If you can set a prefix to your barcode scanner I suggests this (I changed a bit the Vitall code):

var BarcodeScanner = function(options) {
     this.initialize.call(this, options);
};
BarcodeScanner.prototype = {
    initialize: function(options) {
       $.extend(this._options,options);
       if(this._options.debug) console.log("BarcodeScanner: Initializing");
       $(this._options.eventObj).on({
          keydown: $.proxy(this._keydown, this),
       });
    },
    destroy: function() {
        $(this._options.eventObj).off("keyup",null,this._keyup);
        $(this._options.eventObj).off("keydown",null,this._keydown);
    },
    fire: function(str){
        if(this._options.debug) console.log("BarcodeScanner: Firing barcode event with string: "+str);
        $(this._options.fireObj).trigger('barcode',[str]);
    },
    isReading: function(){
        return this._isReading;
    },
    checkEvent: function(e){
        return this._isReading || (this._options.isShiftPrefix?e.shiftKey:!e.shiftKey) && e.which==this._options.prefixCode;
    },
    _options: {timeout: 600, prefixCode: 36, suffixCode: 13, minCode: 32, maxCode: 126, isShiftPrefix: false, debug: false, eventObj: document, fireObj: document},
    _isReading: false,
    _timeoutHandler: false,
    _inputString: '',
    _keydown: function (e) {
        if(this._input.call(this,e))
            return false;
    },
    _input: function (e) {
        if(this._isReading){
            if(e.which==this._options.suffixCode){
                //read end
                if(this._options.debug) console.log("BarcodeScanner: Read END");
                if (this._timeoutHandler) 
                    clearTimeout(this._timeoutHandler);
                this._isReading=false;
                this.fire.call(this,this._inputString);
                this._inputString='';
            }else{
                //char reading
                if(this._options.debug) console.log("BarcodeScanner: Char reading "+(e.which));
                if(e.which>=this._options.minCode && e.which<=this._options.maxCode)
                    this._inputString += String.fromCharCode(e.which);
            }
            return true;
        }else{
            if((this._options.isShiftPrefix?e.shiftKey:!e.shiftKey) && e.which==this._options.prefixCode){
                //start reading
                if(this._options.debug) console.log("BarcodeScanner: Start reading");
                this._isReading=true;
                this._timeoutHandler = setTimeout($.proxy(function () {
                    //read timeout
                    if(this._options.debug) console.log("BarcodeScanner: Read timeout");
                    this._inputString='';
                    this._isReading=false;
                    this._timeoutHandler=false;
                }, this), this._options.timeout);
                return true;
            }
        }
        return false;
    }
};

If you need you customize timeout, suffix, prefix, min/max ascii code readed:

new BarcodeScanner({timeout: 600, prefixKeyCode: 36, suffixKeyCode: 13, minKeyCode: 32, maxKeyCode: 126});

I also added the isShiftPrefix option to use for example the $ char as prefix with these options: new BarcodeScanner({prefixKeyCode: 52, isShiftPrefix: true});

This is a fiddle: https://jsfiddle.net/xmt76ca5/

like image 30
Tobia Avatar answered Oct 01 '22 16:10

Tobia


You can use a "onkeyup" event on that input box. If the event has triggered then you can called it "Input from Keyboard".

like image 34
Sudip Pal Avatar answered Oct 01 '22 15:10

Sudip Pal