USB Barcode Capture Revisited

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

USB Barcode Capture Revisited

03 Jan 2019, 02:51

This code is perfect in capturing numbers from barcodes based on the speed of entry;
#SingleInstance force

Loop 10
Hotkey, % "$~" A_Index-1, BarCodeHandler, on

BarCodeHandler:
Accu .= SubStr(A_ThisHotkey, 0)
If Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 60
SetTimer, TheBigShebang, -60
If (A_TimeSincePriorHotkey > 100)
Accu := SubStr(A_ThisHotkey, 0)
return
TheBigShebang:
If Accu
msgbox You scanned barcode %Accu%
return
Can someone modify it to capture other characters apart from numbers as well?
There must be a way.
aifritz
Posts: 301
Joined: 29 Jul 2018, 11:30
Location: Germany

Re: USB Barcode Capture Revisited

03 Jan 2019, 12:21

not quite sure what it's supposed to be exactly for and if A_TimeSincePriorHotkey works as expected, but if you only want to make it possible for other chars you could try something like this, there might be a better solution... :)

Code: Select all

#SingleInstance force
Chars = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Loop, Parse, Chars
  Hotkey, % "$~" A_LoopField, BarCodeHandler, on

BarCodeHandler:
Accu .= SubStr(A_ThisHotkey, 0)
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 60)
  SetTimer, TheBigShebang, -60
If (A_TimeSincePriorHotkey > 100)
  Accu := SubStr(A_ThisHotkey, 0)
return

TheBigShebang:
If Accu
  msgbox You scanned barcode %Accu%
return
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

04 Jan 2019, 02:57

Captures lower case letters and numbers but doesn't capture the upper case and spaces for some reason.

Also need it to capture characters like ¬!"£$%^&*()_+=-`\|,./;'#[]{}:@~<>?

You are on the right track for sure.
User avatar
joedf
Posts: 9000
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: USB Barcode Capture Revisited

06 Jan 2019, 23:45

Code: Select all

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
  Hotkey, % "$~" A_LoopField, BarCodeHandler, on
Chars_Upper = 0123456789abcdefghijklmnopqrstuvwxyz
Loop, Parse, Chars_Upper 
  Hotkey, % "$~+" A_LoopField, BarCodeHandler, on
return

BarCodeHandler:
MsgBox % A_ThisHotkey
return

?
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

07 Jan 2019, 05:27

Since it is missing the timer, it returns Chars individually in separate text boxes. It also skips some letters & numbers.
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

07 Jan 2019, 05:30

But yes it distinguishes between Upper and Lower case!
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

07 Jan 2019, 05:57

Eureka Joedf! It works! Now I need to capture Space... whitespace, maybe also perhaps tabs etc.
Also I have an issue that it could NOT capture text unaccompanied by a number.

Code: Select all

#SingleInstance force
Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
  Hotkey, % "$~" A_LoopField, BarCodeHandler, on
  
Chars_Upper = 0123456789abcdefghijklmnopqrstuvwxyz
Loop, Parse, Chars_Upper 
  Hotkey, % "$~+" A_LoopField, BarCodeHandlerUpper, on

BarCodeHandler:
Accu .= SubStr(A_ThisHotkey, 0)
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 60)
  SetTimer, TheBigShebang, -60
If (A_TimeSincePriorHotkey > 100)
  Accu := SubStr(A_ThisHotkey, 0)
return

BarCodeHandlerUpper:
Capture :=
Capture := SubStr(A_ThisHotkey, 0)
StringUpper, Capture, Capture
Accu .= Capture
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 60)
  SetTimer, TheBigShebang, -60
If (A_TimeSincePriorHotkey > 100)
  Accu := SubStr(A_ThisHotkey, 0)
return

TheBigShebang:
If Accu
  msgbox You scanned barcode %Accu%
return
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

07 Jan 2019, 07:24

This bypasses the problem with space, by capturing it without the "$~" which were causing errors with space and then re-entering it into the system via unicode and SendInput so as to not trigger the script.

If there is an elegant solution to the space capture below, please let me know. It would be less prone to error.

Code: Select all

#SingleInstance force

CharSpace :=chr( 32 )

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
  Hotkey, % "$~" A_LoopField, BarCodeHandler, on
  
Chars_Upper = 0123456789abcdefghijklmnopqrstuvwxyz
Loop, Parse, Chars_Upper 
  Hotkey, % "$~+" A_LoopField, BarCodeHandlerUpper, on
  
Hotkey, % "" CharSpace, BarCodeHandlerSpace, on

BarCodeHandler:
Accu .= SubStr(A_ThisHotkey, 0)
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 60)
  SetTimer, TheBigShebang, -60
If (A_TimeSincePriorHotkey > 100)
  Accu := SubStr(A_ThisHotkey, 0)
return

BarCodeHandlerUpper:
Capture :=
Capture := SubStr(A_ThisHotkey, 0)
StringUpper, Capture, Capture
Accu .= Capture
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 60)
  SetTimer, TheBigShebang, -60
If (A_TimeSincePriorHotkey > 100)
  Accu := SubStr(A_ThisHotkey, 0)
return

BarCodeHandlerSpace:
Accu .= " "
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 60)
  SetTimer, TheBigShebang, -60
If (A_TimeSincePriorHotkey > 100)
  Accu := SubStr(A_ThisHotkey, 0)
  
 SendInput, {U+0020}
return

TheBigShebang:
If Accu
  msgbox You scanned barcode %Accu%
return
User avatar
evilC
Posts: 4824
Joined: 27 Feb 2014, 12:30

Re: USB Barcode Capture Revisited

07 Jan 2019, 09:10

The best way to handle Barcode input is to set your scanner to have a pre-amble (Key that scanner sends at beginning of scan) / post-amble (Key that scanner sends at end of scan)
Then you do not need to bother with any of this A_TimeSincePriorHotkey nonsense to be able to tell the difference between you typing on the keyboard normally, or the scanner sending keys

Pre/post amble will be set by scanning a special barcode from the manual.

Just set the pre-amble to say F11 and the post-amble to say F12, then you can turn on or off the capture hotkeys easily:

Code: Select all

Scanning := 0

F11::
   Scanning := 1
   return

F12::
   Scanning := 0
   return

#if Scanning
Loop {
   ; Set up your number / letter hotkeys here
   Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
   Loop, Parse, Chars
      Hotkey, % "$~" A_LoopField, BarCodeHandler, on
}
#if
Also, you can avoid a lot of run-time work with function binding

Instead of:

Code: Select all

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
  Hotkey, % "$~" A_LoopField, BarCodeHandler, on

BarCodeHandler:
  Accu .= SubStr(A_ThisHotkey, 0)
  ; ...
You can do this:

Code: Select all

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
{
  fn := Func("BarCodeHandler").Bind(A_LoopField)
  Hotkey, % "$~" A_LoopField, % fn, on
}

BarCodeHandler(key){
  ; key already holds A_ThisHotkey
}
Also see here for some code which can bind to every key on the keyboard, without having to specify a key list.
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

07 Jan 2019, 09:24

While all you said is true, I do not have this slip of paper (pre-/post-ambles) for my generic barcode which was bought via eBay. Its a pity that there is no other way to set these prefix/suffix.
evilC wrote:
07 Jan 2019, 09:10
The best way to handle Barcode input is to set your scanner to have a pre-amble (Key that scanner sends at beginning of scan) / post-amble (Key that scanner sends at end of scan)
Then you do not need to bother with any of this A_TimeSincePriorHotkey nonsense to be able to tell the difference between you typing on the keyboard normally, or the scanner sending keys

Pre/post amble will be set by scanning a special barcode from the manual.

Just set the pre-amble to say F11 and the post-amble to say F12, then you can turn on or off the capture hotkeys easily:

Code: Select all

Scanning := 0

F11::
   Scanning := 1
   return

F12::
   Scanning := 0
   return

#if Scanning
Loop {
   ; Set up your number / letter hotkeys here
   Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
   Loop, Parse, Chars
      Hotkey, % "$~" A_LoopField, BarCodeHandler, on
}
#if
Also, you can avoid a lot of run-time work with function binding

Instead of:

Code: Select all

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
  Hotkey, % "$~" A_LoopField, BarCodeHandler, on

BarCodeHandler:
  Accu .= SubStr(A_ThisHotkey, 0)
  ; ...
You can do this:

Code: Select all

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
{
  fn := Func("BarCodeHandler").Bind(A_LoopField)
  Hotkey, % "$~" A_LoopField, % fn, on
}

BarCodeHandler(key){
  ; key already holds A_ThisHotkey
}
Also see here for some code which can bind to every key on the keyboard, without having to specify a key list.
User avatar
evilC
Posts: 4824
Joined: 27 Feb 2014, 12:30

Re: USB Barcode Capture Revisited

07 Jan 2019, 09:56

I rarely have an actual piece of paper - you can scan a barcode from a screen just fine.
There should be *some* way to set it, you just need to work out what the actual make/model is, or what the chipset used is.
It may even send a non-printable character by default.
Personally, if I bought a scanner and there was no way to set pre/post-amble, I would return the item, or at the very least give the seller a serious negative review for supplying me with junk.
User avatar
evilC
Posts: 4824
Joined: 27 Feb 2014, 12:30

Re: USB Barcode Capture Revisited

07 Jan 2019, 09:59

Alternatively, another way around it would be to use AutoHotInterception (See link in signature).
That way, you could differentiate keys coming from the scanner to keys coming from your normal keyboard, and you could instruct AHI to block (Not pass through to OS) all hotkeys that come from the scanner

ie AHI can tell the difference between "1" sent by the scanner, and "1" sent by your regular keyboard
User avatar
joedf
Posts: 9000
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: USB Barcode Capture Revisited

07 Jan 2019, 20:08

I've never worked with barcode scanners before... Is there not a way to capture a "scan" event and simply get the decoded data?
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

08 Jan 2019, 05:10

Below is the latest working code. I have reduced the timers to below 20 milliseconds to avoid capturing the keyboard when a key is kept pressed. Reducing the timer to lower than this may affect the barcode capture, giving incomplete captures. One must adjust these timers according to the speed of their barcodes and speed of their keyboard.

Code: Select all

#SingleInstance force

CharSpace :=chr( 32 )

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars
  Hotkey, % "$~" A_LoopField, BarCodeHandler, on
  
Chars_Upper = 0123456789abcdefghijklmnopqrstuvwxyz
Loop, Parse, Chars_Upper 
  Hotkey, % "$~+" A_LoopField, BarCodeHandlerUpper, on
  
Hotkey, % "" CharSpace, BarCodeHandlerSpace, on

BarCodeHandler:
Accu .= SubStr(A_ThisHotkey, 0)
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 20)
  SetTimer, TheBigShebang, -20
If (A_TimeSincePriorHotkey > 25)
  Accu := SubStr(A_ThisHotkey, 0)
return

BarCodeHandlerUpper:
Capture :=
Capture := SubStr(A_ThisHotkey, 0)
StringUpper, Capture, Capture
StringUpper, Capture, Capture
Accu .= Capture
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 20)
  SetTimer, TheBigShebang, -20
If (A_TimeSincePriorHotkey > 25)
  Accu := SubStr(A_ThisHotkey, 0)
return

BarCodeHandlerSpace:
Accu .= " "
If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 20)
  SetTimer, TheBigShebang, -20
If (A_TimeSincePriorHotkey > 25)
  Accu := SubStr(A_ThisHotkey, 0)
  
 SendInput, {U+0020}
return

TheBigShebang:
If Accu
  msgbox You scanned barcode %Accu%
return
User avatar
evilC
Posts: 4824
Joined: 27 Feb 2014, 12:30

Re: USB Barcode Capture Revisited

08 Jan 2019, 05:55

Something like this (Untested) would reduce a LOT of duplicate code and run-time pointless processing:

Code: Select all

#SingleInstance force

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars {
	fn := Func("BarcodeHandler").Bind(A_LoopField)
	Hotkey, % "$~" A_LoopField, % fn, on
}
  
Chars_Upper = ABCDEFGHIJKLMNOPQRSTUVWXYZ
Loop, Parse, Chars_Upper {
	fn := Func("BarcodeHandler").Bind(A_LoopField)
	Hotkey, % "$~+" A_LoopField, % fn, on
}

fn := Func("BarcodeHandler").Bind(" ")
Hotkey, Space, % fn, on

BarCodeHandler(key){
	global Accu
	Accu .= key
	If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 20)
		SetTimer, TheBigShebang, -20
	Else If (A_TimeSincePriorHotkey > 25)
		Accu := SubStr(key, 0)
	If (key == " "){
		SendInput, {U+0020}
	}
}

TheBigShebang:
If Accu
  msgbox You scanned barcode %Accu%
return

^Esc::ExitApp
User avatar
joedf
Posts: 9000
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: USB Barcode Capture Revisited

08 Jan 2019, 19:00

@evilC
interesting.... thanks
@labrint
So uppercase and symbols are being captured by evilC’s latest combined snippet? It works?
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

09 Jan 2019, 04:47

Very eager to try the code, but unfortunately there is an error;

Code: Select all

Error at line 4.

The following variable name contains an illegal character:
"Chars {"

The program will exit.
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

09 Jan 2019, 05:02

Adjusted the curly brace to a line below the parse, and it works like a charm!! Brilliant! Interesting function (bind). Thanks evilC, Joedf, jeeswg. Clearly, I have a lot to learn :)

Correct me if I'm wrong but this is the first barcode capture of this kind (using the speed of data entry method)?

Code: Select all

#SingleInstance force

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars 
{
	fn := Func("BarcodeHandler").Bind(A_LoopField)
	Hotkey, % "$~" A_LoopField, % fn, on
}
  
Chars_Upper = ABCDEFGHIJKLMNOPQRSTUVWXYZ
Loop, Parse, Chars_Upper 
{
	fn := Func("BarcodeHandler").Bind(A_LoopField)
	Hotkey, % "$~+" A_LoopField, % fn, on
}

fn := Func("BarcodeHandler").Bind(" ")
Hotkey, Space, % fn, on

BarCodeHandler(key){
	global Accu
	Accu .= key
	If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 20)
		SetTimer, TheBigShebang, -20
	Else If (A_TimeSincePriorHotkey > 25)
		Accu := SubStr(key, 0)
	If (key == " "){
		SendInput, {U+0020}
	}
}

TheBigShebang:
If Accu
  msgbox You scanned barcode %Accu%
return

^Esc::ExitApp
User avatar
labrint
Posts: 383
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: USB Barcode Capture Revisited

09 Jan 2019, 05:28

I have modified the code, removed the "Unicode Space". The $~ have been added as a prefix to Space, and it works perfectly. This will improve the code significantly as the barcode will not have any substitutions inside the barcode input.

Code: Select all

#SingleInstance force

Chars = 0123456789abcdefghijklmnopqrstuvwxyz!""$`%^&*()_+=-``\|,./;'#[]{}:@~<>?
Loop, Parse, Chars 
{
	fn := Func("BarcodeHandler").Bind(A_LoopField)
	Hotkey, % "$~" A_LoopField, % fn, on
}
  
Chars_Upper = ABCDEFGHIJKLMNOPQRSTUVWXYZ
Loop, Parse, Chars_Upper 
{
	fn := Func("BarcodeHandler").Bind(A_LoopField)
	Hotkey, % "$~+" A_LoopField, % fn, on
}

fn := Func("BarcodeHandler").Bind(" ")
Hotkey, $~Space, % fn, on

BarCodeHandler(key){
	global Accu
	Accu .= key
	If (Strlen(Accu) > 4 && A_TimeSincePriorHotkey < 20)
		SetTimer, TheBigShebang, -20
	Else If (A_TimeSincePriorHotkey > 25)
		Accu := SubStr(key, 0)
}

TheBigShebang:
If Accu
  msgbox You scanned barcode %Accu%
return

^Esc::ExitApp
Great job!

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], peter_ahk and 338 guests