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

83,912

Solution 1

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.

Solution 2

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);
    }
};

Solution 3

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
    });
})($);

Solution 4

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'/>

Solution 5

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

Share:
83,912
WelcomeTo
Author by

WelcomeTo

Updated on January 27, 2022

Comments

  • WelcomeTo
    WelcomeTo about 2 years

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

  • WelcomeTo
    WelcomeTo almost 12 years
    thanks. But how I can detect when barcode were input? onCange event rises only when element lost focus, but I need to know inserted value immediately after inserting. I can to make timer and periodically check value on text field, but I think it's wrong solution.
  • Mitya
    Mitya almost 12 years
    You didn't mention in your question when precisely you wanted to check input, so I assumed onChange. Yes, I think a timer is probably the only way there, unless the barcode application fires some sort of custom event when it manipulates the page.
  • chadiusvt
    chadiusvt over 5 years
    Wanted to point out, this solution also fixes the first character missing bug that the answer from @Vitall had.
  • chadiusvt
    chadiusvt over 5 years
    Also, $(document).trigger(... should be changed to $(e.target).trigger(... so that the event registers with the desired DOM object.
  • chadiusvt
    chadiusvt over 5 years
    Thanks. Also, In my own usage, I noticed that some browsers (IE, Firefox) gave the value of e.key for keyboard keys like backspace to "BACKSPACE" and trigger the event. I fixed this by adding if(e.key.length == 1) _inputString += e.key;
  • Aadam
    Aadam over 5 years
    This is not working if focus is on input field, how can I avoid rfid typing it to input field and should only be detected in above code?
  • Tobia
    Tobia over 5 years
    I changed a bit the code moving the event from keyup to keydown and now you can avoid typing in the input field during barcode reading. Please try the fiddle.
  • sɐunıɔןɐqɐp
    sɐunıɔןɐqɐp over 5 years
    From Review: Welcome to Stack Overflow! Please don't answer just with source code. Try to provide a nice description about how your solution works. See: How do I write a good answer?. Thanks
  • Sharad
    Sharad over 4 years
    I tried in Android mobile bar code scanning, it is taking key press event only instead bar code scan? How this is working for you people.
  • Ahmad Karimi
    Ahmad Karimi over 4 years
    Vitall, I am not a JavaScript guy. I will be extremely grateful to know how this code works and how can I use it in my own code. I want to put an event listener for the $(document) element to catch anytime a barcode is scanned.
  • Vitall
    Vitall over 4 years
    @AhmadKarimi, for add event listener you just need to use jquery on method, something like $(document).on( "onbarcodescaned", function(inputString) { // your code here in inputString should be barcode result });
  • Vitall
    Vitall over 4 years
    @AhmadKarimi also my answer is very old, try to use adapted version of code stackoverflow.com/a/56540835/527925
  • Baxny
    Baxny over 4 years
    If your barcode scanner is slow (our bluetooth scanners) you may need to increase the timeout from 20 to a higher number. We changed our timeout to 200, to give the scanner more time to type the barcode in.
  • Baxny
    Baxny over 4 years
    We also added a check to not type in special characters because when we were manually deleting the barcode out of the field, the script was typing the characters // Stop special keys inserting words e.g. backspace if (e.key.length == 1) { _inputString += e.key; }
  • Arman H
    Arman H about 4 years
    Thanks I was looking for this. My-barcode Reader- inateck(p6 barcode scanner)
  • Jeppe
    Jeppe over 3 years
    This worked for me. To get the barcode-value, I had to subscribe to the trigger like this: $(document).on("altdeviceinput", function (e, barCode) { ...
  • Joel
    Joel over 3 years
    you do not mention how that plugin will help in "Detecting when input box filled by keyboard and when by barcode scanner."
  • Jonathan B.
    Jonathan B. about 3 years
    Just to clarify, this method works when the focus is not on an text input form element. If the focus IS on an input element, then we need to consider other factors as mentioned elsewhere in this Q&A.
  • khashashin
    khashashin about 3 years
    @jeppe thx to pointing on that. @spence7 could you please add some comments on your solution, it works well but I'm a bit confused with that timeoutHandler is that the timeout between keypresses?
  • Spence7
    Spence7 about 3 years
    @khashashin The basic algorithm is: on the keypress event, cancel the setTimeout call if one is waiting to execute, add the pressed key value to an input buffer, then call setTimeout. If another keypress is not captured in 20ms, the function passed to setTimeout will be called. Said function will trigger an event IF the input string is at least 3 characters long (this combined with the short timeout was enough to indicate a scan). Either way the input buffer is flushed.
  • Christian Vermeulen
    Christian Vermeulen over 2 years
    Perhaps this will make things easier? npmjs.com/package/@itexperts/barcode-scanner
  • Ogun Meriçligil
    Ogun Meriçligil over 2 years
    My device Zebra MC2200 this worked for me thank you @Spence7 and Vitall
  • Malus Jan
    Malus Jan over 2 years
    Thanks for the answer. Just one thing to add to the solution: if press enter the e.key will return Enter as a string and considered as scan. I modify the code like: if (e.charCode != 13) {_inputString += e.key;}