Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery: Listening for automated scanner input from keyboard?

I'm writing a web app for a library system with a barcode scanner attached. The scanner's input presents as keyboard input, and it's always of the form ~~[\d]+.[\d]+~~, for example ~~470.002~~.

I want to set up a jQuery listener for scanner input, and am a jQuery novice. It should listen to all keyboard input, but only perform an action when it hears input from the scanner, and only when the scanner input has finished.

This is as far as I've got (i.e. not very):

//Global functions: call on all pages.
$(document).ready(function() {
    // Listen for scanner input. 
    $(window).keypress(function(e) {
        var key = e.which;
        if (key==126) {.
            alert('tilde');
            // How to listen for the correct input?
            // check_out_book();
        }
    });
});

What's the best way to keep listening input in the format I need? I'd like it to listen for the final two tildes before calling check_out_book().

I'd also like it to 'stop' listening after the first tilde if there is a pause - to distinguish between a human typist and the automated scanner input. Does jQuery have a way to do this?

Any pointers very much appreciated! Thank you.

like image 583
AP257 Avatar asked Jan 06 '11 23:01

AP257


2 Answers

I think you want to do this by storing what you've received so far and checking to see if it's valid. If it is not, discard what you have received and start again:

$(document).ready(function(){
    var input = '',
        r1 = /^~{1,2}$/,
        r2 = /^~{2}\d+$/,
        r3 = /^~{2}\d+\.$/,
        r4 = /^~{2}\d+\.\d+$/,
        r5 = /^~{2}\d+\.\d+~{1}$/
        r6 = /^~{2}\d+\.\d+~{2}$/;

    $(window).keypress(function(e) {
        input += String.fromCharCode(e.which);

        if (r1.test(input) || r2.test(input) || r3.test(input) || r4.test(input) || r5.test(input)) {
            // input is valid so far, continue
        } else if (r6.test(input) {
            // input is valid and complete
            check_out_book();
        } else {
            // input is invalid, start over
            input = '';
        }
    });
});

You could combine all those regexps into two, but I think it's more legible this way.

like image 109
lonesomeday Avatar answered Nov 14 '22 23:11

lonesomeday


I just finished writing a bit of javascript that detects whether a barcode scanner was used to fill in an input field and moves focus to the next field if it was.

My code answers part of your question, "I want to set up a jQuery listener for scanner input, and am a jQuery novice. It should listen to all keyboard input, but only perform an action when it hears input from the scanner, and only when the scanner input has finished."

Here is the HTML for the input fields:

<input type="text" class="bcode" id="f1" onkeydown="typeSpeed(new Date().getTime());" onblur="typeSpeedReset();" onfocus="typeNextField('f2');" />
<input type="text" class="bcode" id="f2" onkeydown="typeSpeed(new Date().getTime());" onblur="typeSpeedReset();" onfocus="typeNextField('f3');" />
<input type="text" id="f3" />

I have two fields with class 'bcode' that are intended for barcode scanner entry (f1 & f2). The third field is intended for regular input (f3). Fields f1 & f2 send (1) the current timestamp when a key is pressed to the function 'typeSpeed' and (2) the id of the next field to select when the field gains focus. These fields also trigger a call to function 'typeSpeedReset' when the field loses focus.

Here is the javascript/jQuery that makes it work:

$(function(){   
    var typingTimeout;
    $('.bcode').keypress(function(e){
        if (typingTimeout != undefined) clearTimeout(typingTimeout);
        typingTimeout = setTimeout(isBarcode, 500); 
    }); 
});

var ts0 = 0, ts1 = 0, ts2, nf;

function typeSpeed(time) {
    ts0 = (ts0 == 0) ? time : 0;
    var ts3 = ts1;  
    ts1 = time - ts0;   
    ts2 = ts1 - ts3;    
}

function typeSpeedReset() { ts0 = 0; ts1 = 0; }

function typeNextField(nextfield) { nf = nextfield; }

function isBarcode() {
    if(ts2 < 20 && ts1 != 0) { $('#'+nf).focus(); }
}

What happens is the time between keystrokes is quantified by the function 'typeSpeed'. I found out through experimentation (mashing the keyboard or holding down a key) that the fastest human input has approximately ~33ms of delay between keystrokes. The barcode scanner I used to test with generally produced delays of 10ms or less.

A timeout is set on the field with class 'bcode' to detect when input has stopped momentarily. At this point, the delay is evaluated. If it is less than 20ms, a barcode scanner is assumed to have been used and the next field is given focus.

The project this code was written for goes a step further by changing the background color of the field and displaying a small barcode graphic to the right of the field when it has focus so users have a clear indication that it's responsive to and intended for barcode scanner input.

like image 31
humbolight Avatar answered Nov 14 '22 23:11

humbolight