Skip to content

Commit b542391

Browse files
Added BarcodeScanner class which uses evdev to read input from /dev/input for
barcode scanner. The poll function is regularly called and when a ENTER key is detected, the barcodeReceived signal is emitted with the ASCII string. Implemented a primary and secondary barcode scanner in MainWindow. The barcodeReceived signal is connected to a slot.
1 parent 69f522e commit b542391

File tree

3 files changed

+71
-29
lines changed

3 files changed

+71
-29
lines changed

mainWindow.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
11
import mainWindow_ui
2+
from scanner import BarcodeScanner
23
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow
34
from PyQt5.QtCore import *
45

5-
66
class MainWindow(QMainWindow, mainWindow_ui.Ui_MainWindow):
77
def __init__(self, parent=None):
88
super(MainWindow, self).__init__(parent)
99
self.setupUi(self)
1010

11+
# TODO Load settings here. This will load the previously saved settings
12+
1113
# Remove title bar to
1214
self.setWindowFlags(Qt.FramelessWindowHint)
1315

1416
# Sets position to 0,0 on screen and sets window to fixed size
1517
self.setGeometry(0, 0, 800, 480)
1618

19+
# TODO The primary and secondary scanner should be defined based on prev
20+
# settings
21+
self.primaryScanner = BarcodeScanner(4);
22+
self.primaryScanner.barcodeReceived.connect(self.primaryScanner_barcodeReceived)
23+
self.secondaryScanner = BarcodeScanner(5);
24+
self.secondaryScanner.barcodeReceived.connect(self.secondaryScanner_barcodeReceived)
25+
26+
# Setup timer to regularly poll for new barcodes from scanners
27+
# TODO Consider having a constants file where I can set the interval for
28+
# the scannerPoll timer. This doesnt need to be a setting however
29+
self.scannerPoll = QTimer()
30+
self.scannerPoll.timeout.connect(self.scannerPoll_ticked)
31+
self.scannerPoll.start(2)
32+
1733
@pyqtSlot()
1834
def keyPressEvent(self, event):
1935
# Pressing escape will kill the application since the title bar is absent
@@ -23,3 +39,16 @@ def keyPressEvent(self, event):
2339
@pyqtSlot()
2440
def on_pushButton_clicked(self):
2541
self.close()
42+
43+
@pyqtSlot()
44+
def scannerPoll_ticked(self):
45+
self.primaryScanner.poll()
46+
self.secondaryScanner.poll()
47+
48+
@pyqtSlot(str)
49+
def primaryScanner_barcodeReceived(self, barcode):
50+
print("Primary barcode scanner got: %s" % barcode)
51+
52+
@pyqtSlot(str)
53+
def secondaryScanner_barcodeReceived(self, barcode):
54+
print("Secondary barcode scanner got: %s" % barcode)

run.sh

100644100755
File mode changed.

scanner.py

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from exception import *
22
from evdev import *
3-
from ecodes import *
3+
from evdev.ecodes import *
4+
from PyQt5.QtCore import QObject, pyqtSignal
45
import re
56

67
keycodeToASCII = {
7-
# Scancode: ASCIICode
88
KEY_1: ['1', '!'], KEY_2: ['2', '@'], KEY_3: ['3', '#'], KEY_4: ['4', '$'], KEY_5: ['5', '%'], KEY_6: ['6', '^'],
99
KEY_7: ['7', '*'], KEY_8: ['8', '('], KEY_9: ['9', '('], KEY_0: ['0', ')'], KEY_MINUS: ['-', '_'], KEY_EQUAL: ['=', '+'],
1010
KEY_TAB: ['\t', '\t'], KEY_Q: ['q', 'Q'], KEY_W: ['w', 'W'], KEY_E: ['e', 'E'], KEY_R: ['r', 'R'], KEY_T: ['t', 'T'],
@@ -21,8 +21,12 @@
2121
KEY_KPPLUS: '+', KEY_KP1: '1', KEY_KP2: '2', KEY_KP3: '3', KEY_KP0: '0', KEY_KPDOT: '.', KEY_KPSLASH: '/'
2222
}
2323

24-
class BarcodeScanner:
24+
class BarcodeScanner(QObject):
25+
# Signal is emitted once a barcode has been scanned and received
26+
barcodeReceived = pyqtSignal(str)
27+
2528
def __init__(self, usbPortNumber):
29+
QObject.__init__(self)
2630
self.modifiers = {
2731
KEY_RIGHTMETA: 0, # Right GUI - (usually the Windows key)
2832
KEY_RIGHTALT: 0, # Right ALT
@@ -34,13 +38,18 @@ def __init__(self, usbPortNumber):
3438
KEY_LEFTCTRL: 0 # Left Control
3539
}
3640
self.state = {
37-
LED_CAPSL: 0, # Caps Lock
38-
LED_NUML: 0, # Num Lock
39-
LED_SCROLLL: 0 # Scroll Lock
41+
KEY_CAPSLOCK: 0, # Caps Lock
42+
KEY_NUMLOCK: 0, # Num Lock
43+
KEY_SCROLLLOCK: 0, # Scroll Lock
4044
}
4145

46+
# This regex expression identifies a device on a specified USB port number
47+
# I am not entirely sure if this is Raspbian specific, Linux specific or what,
48+
# but it works in this case
4249
rePhysicalLoc = re.compile("usb\-.*\..*\-1\.%i.*" % usbPortNumber)
4350

51+
# Loop through all available devices and search for a regex match
52+
# First match found is the device we will use
4453
devices = [InputDevice(fn) for fn in list_devices()]
4554
self.device = None
4655
for device in devices:
@@ -54,36 +63,40 @@ def __init__(self, usbPortNumber):
5463

5564
# Get the current state of the LED buttons; update self.state with the values that are on
5665
ledStates = self.device.leds()
57-
for led in ledStates:
58-
self.state[led] = 1
66+
if LED_CAPSL in ledStates: self.state[KEY_CAPSLOCK] = 1
67+
if LED_NUML in ledStates: self.state[KEY_NUMLOCK] = 1
68+
if LED_SCROLLL in ledStates: self.state[KEY_SCROLLLOCK] = 1
69+
70+
# Set the current string buffer to none
71+
self.curStr = ""
5972

6073
def poll(self):
6174
try:
6275
# Read all of the events from the loop
63-
events = self.device.read()
76+
deviceEvents = self.device.read()
6477

65-
for event in events:
78+
for event in deviceEvents:
79+
# Only accept keyboard events
6680
if event.type is EV_KEY:
6781
keyEvent = util.categorize(event)
68-
69-
if keyEvent.keycode in self.modifiers:
70-
if keyEvent.keystate is events.KeyEvent.key_down:
71-
self.modifiers[keyEvent.keycode] = 1
72-
elif keyEvent.keystate is events.KeyEvent.key_up:
73-
self.modifiers[keyEvent.keycode] = 0
74-
elif keyEvent.keycode in self.state:
75-
if keyEvent.keystate is events.KeyEvent.key_down:
76-
self.state[keyEvent.keycode] = 1
77-
elif keyEvent.keystate is events.KeyEvent.key_up:
78-
self.state[keyEvent.keycode] = 0
79-
elif keyEvent.keystate is events.KeyEvent.key_down or \
80-
keyEvent.keystate is events.KeyEvent.key_hold:
81-
if keyEvent.keycode in keycodeToASCII:
82+
83+
if keyEvent.scancode in self.modifiers:
84+
if keyEvent.keystate is events.KeyEvent.key_down: self.modifiers[keyEvent.scancode] = 1
85+
elif keyEvent.keystate is events.KeyEvent.key_up: self.modifiers[keyEvent.scancode] = 0
86+
elif keyEvent.scancode in self.state:
87+
if keyEvent.keystate is events.KeyEvent.key_down: self.state[keyEvent.scancode] = 1
88+
elif keyEvent.keystate is events.KeyEvent.key_up: self.state[keyEvent.scancode] = 0
89+
elif keyEvent.keystate is events.KeyEvent.key_down or keyEvent.keystate is events.KeyEvent.key_hold:
90+
if keyEvent.scancode is KEY_ENTER:
91+
#print("Current str: %s" % self.curStr)
92+
self.barcodeReceived.emit(self.curStr)
93+
self.curStr = ""
94+
elif keyEvent.scancode in keycodeToASCII:
8295
shift = (self.modifiers[KEY_LEFTSHIFT] or self.modifiers[KEY_RIGHTSHIFT])
83-
str = keycodeToASCII[keyEvent.keycode][shift]
84-
elif keyEvent.keycode in numpadcodeToASCII:
85-
str = numpadcodeToASCII[keyEvent.keycode]
96+
self.curStr += keycodeToASCII[keyEvent.scancode][shift]
97+
elif keyEvent.scancode in numpadcodeToASCII and self.state[KEY_NUMLOCK]:
98+
str = numpadcodeToASCII[keyEvent.scancode]
8699
except BlockingIOError:
87100
# If no events are available, this is thrown
88101
# No actual error, move on
89-
pass
102+
pass

0 commit comments

Comments
 (0)