中断阻止evdev读取

时间:2016-04-06 14:13:08

标签: python multithreading signals evdev

我有一个模块可以捕获条形码扫描仪的所有读数。 我的问题是我无法正确关闭它。 发送KeyboardInterrupt或SystemExit信号后,它仅在我扫描条形码时停止。

我尝试将此方法添加到BarcodeScanner类中,但它仍然无效:

def interrupt(self):
    """Envoi la demande d'arrêt."""

    super(BarcodeScanner, self).interrupt()
    self.device.write(ecodes.EV_KEY, ecodes.KEY_ESC, 0)
    self.device.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)

我该怎么做?

interruptable.py

#!/usr/bin/env python3
# -*-coding:Utf-8 -*


class Interruptable:
    """Classe intégrant une boucle sans fin pouvant être stoppée proprement."""

    interruptables = []

    def __init__(self):
        """Crée un objet interruptible."""

        self._interrupted = False
        Interruptable.interruptables.append(self)

    def interrupt(self):
        """Envoi la demande d'arrêt."""

        self._interrupted = True

    def reset(self):
        """Permet le redémarrage d'un service."""

        self._interrupted = False

    def interrupted(self):
        """Verifie si la demande d'arrêt à déjà été envoyée."""

        return self._interrupted

barcode_scanner.py

#!/usr/bin/env python3
# -*-coding:Utf-8 -*

from evdev import InputDevice, ecodes, list_devices, categorize
import signal, sys
import threading
from time import sleep

from tymsoft.interruptable import Interruptable

class BarcodeScanner(Interruptable):
    """TODO"""

    def __init__(self, device_name='Bar Code', layout='AZERTY_FR'):
        self.modifiers = {
            # 0: None, 29: u'LCTRL', 42: u'LSHFT', 54: u'RSHFT', 56: u'LALT', 97:u'RCTRL', 100: u'RALT'
            0: 0, 29: 1, 42: 2, 54: 3, 56: 4, 97: 5, 100: 6
        }
        self.layouts = {
            'AZERTY_FR': {
                # [NORMAL, LCTRL, LSHFT, RSHFT, LALT, RCTRL, RALT]
                2: [u'&', u'', u'1', u'1', u'', u'', u''],
                3: [u'é', u'', u'2', u'2', u'', u'', u'~'],
                4: [u'"', u'', u'3', u'3', u'', u'', u'#'],
                5: [u'\'', u'', u'4', u'4', u'', u'', u'{'],
                6: [u'(', u'', u'5', u'5', u'', u'', u'['],
                7: [u'-', u'', u'6', u'6', u'', u'', u'|'],
                8: [u'è', u'', u'7', u'7', u'', u'', u'`'],
                9: [u'_', u'', u'8', u'8', u'', u'', u'\\'],
                10: [u'ç', u'', u'9', u'9', u'', u'', u'^'],
                11: [u'à', u'', u'0', u'0', u'', u'', u'@'],
                12: [u')', u'', u'°', u'°', u'', u'', u']'],
                13: [u'=', u'', u'+', u'+', u'', u'', u'}'],
                15: [u'\t', u'', u'', u'', u'', u'', u''],
                16: [u'a', u'', u'A', u'A', u'', u'', u''],
                17: [u'z', u'', u'Z', u'Z', u'', u'', u''],
                18: [u'e', u'', u'E', u'E', u'', u'', u'€'],
                19: [u'r', u'', u'R', u'R', u'', u'', u''],
                20: [u't', u'', u'T', u'T', u'', u'', u''],
                21: [u'y', u'', u'Y', u'Y', u'', u'', u''],
                22: [u'u', u'', u'U', u'U', u'', u'', u''],
                23: [u'i', u'', u'I', u'I', u'', u'', u''],
                24: [u'o', u'', u'O', u'O', u'', u'', u''],
                25: [u'p', u'', u'P', u'P', u'', u'', u''],
                26: [u'^', u'', u'¨', u'¨', u'', u'', u''],
                27: [u'$', u'', u'£', u'£', u'', u'', u'¤'],
                28: [u'\n', u'', u'', u'', u'', u'', u''],
                30: [u'q', u'', u'Q', u'Q', u'', u'', u''],
                31: [u's', u'', u'S', u'S', u'', u'', u''],
                32: [u'd', u'', u'D', u'D', u'', u'', u''],
                33: [u'f', u'', u'F', u'F', u'', u'', u''],
                34: [u'g', u'', u'G', u'G', u'', u'', u''],
                35: [u'h', u'', u'H', u'H', u'', u'', u''],
                36: [u'j', u'', u'J', u'J', u'', u'', u''],
                37: [u'k', u'', u'K', u'K', u'', u'', u''],
                38: [u'l', u'', u'L', u'L', u'', u'', u''],
                39: [u'm', u'\n', u'M', u'M', u'', u'', u''],
                40: [u'ù', u'', u'%', u'%', u'', u'', u''],
                41: [u'²', u'', u'', u'', u'', u'', u''],
                43: [u'*', u'', u'µ', u'µ', u'', u'', u''],
                44: [u'w', u'', u'W', u'W', u'', u'', u''],
                45: [u'x', u'', u'X', u'X', u'', u'', u''],
                46: [u'c', u'', u'C', u'C', u'', u'', u''],
                47: [u'v', u'', u'V', u'V', u'', u'', u''],
                48: [u'b', u'', u'B', u'B', u'', u'', u''],
                49: [u'n', u'', u'N', u'N', u'', u'', u''],
                50: [u',', u'', u'?', u'?', u'', u'', u''],
                51: [u';', u'', u'.', u'.', u'', u'', u''],
                52: [u':', u'', u'/', u'/', u'', u'', u''],
                53: [u'!', u'', u'§', u'§', u'', u'', u''],
                57: [u' ', u'', u' ', u' ', u'', u'', u''],
                86: [u'<', u'', u'>', u'>', u'', u'', u''],
                96: [u'\n', u'', u'', u'', u'', u'', u'']
            },
            'QWERTY_US': {
                # [NORMAL, LCTRL, LSHFT, RSHFT, LALT, RCTRL, RALT]
                2: [u'1', u'', u'!', u'!', u'', u'', u''],
                3: [u'2', u'', u'@', u'@', u'', u'', u''],
                4: [u'3', u'', u'#', u'#', u'', u'', u''],
                5: [u'4', u'', u'$', u'$', u'', u'', u''],
                6: [u'5', u'', u'%', u'%', u'', u'', u''],
                7: [u'6', u'', u'^', u'^', u'', u'', u''],
                8: [u'7', u'', u'&', u'&', u'', u'', u''],
                9: [u'8', u'', u'*', u'*', u'', u'', u''],
                10: [u'9', u'', u'(', u'(', u'', u'', u''],
                11: [u'0', u'', u')', u')', u'', u'', u''],
                12: [u'-', u'', u'_', u'_', u'', u'', u''],
                13: [u'=', u'', u'+', u'+', u'', u'', u''],
                15: [u'\t', u'', u'', u'', u'', u'', u''],
                16: [u'q', u'', u'Q', u'Q', u'', u'', u''],
                17: [u'w', u'', u'W', u'W', u'', u'', u''],
                18: [u'e', u'', u'E', u'E', u'', u'', u''],
                19: [u'r', u'', u'R', u'R', u'', u'', u''],
                20: [u't', u'', u'T', u'T', u'', u'', u''],
                21: [u'y', u'', u'Y', u'Y', u'', u'', u''],
                22: [u'u', u'', u'U', u'U', u'', u'', u''],
                23: [u'i', u'', u'I', u'I', u'', u'', u''],
                24: [u'o', u'', u'O', u'O', u'', u'', u''],
                25: [u'p', u'', u'P', u'P', u'', u'', u''],
                26: [u'[', u'', u'{', u'{', u'', u'', u''],
                27: [u']', u'', u'}', u'}', u'', u'', u''],
                28: [u'\n', u'', u'', u'', u'', u'', u''],
                30: [u'a', u'', u'A', u'A', u'', u'', u''],
                31: [u's', u'', u'S', u'S', u'', u'', u''],
                32: [u'd', u'', u'D', u'D', u'', u'', u''],
                33: [u'f', u'', u'F', u'F', u'', u'', u''],
                34: [u'g', u'', u'G', u'G', u'', u'', u''],
                35: [u'h', u'', u'H', u'H', u'', u'', u''],
                36: [u'j', u'', u'J', u'J', u'', u'', u''],
                37: [u'k', u'', u'K', u'K', u'', u'', u''],
                38: [u'l', u'', u'L', u'L', u'', u'', u''],
                39: [u';', u'', u':', u':', u'', u'', u''],
                40: [u'\'', u'', u'"', u'"', u'', u'', u''],
                41: [u'`', u'', u'~', u'~', u'', u'', u''],
                43: [u'\\', u'', u'|', u'|', u'', u'', u''],
                44: [u'z', u'', u'Z', u'Z', u'', u'', u''],
                45: [u'x', u'', u'X', u'X', u'', u'', u''],
                46: [u'c', u'', u'C', u'C', u'', u'', u''],
                47: [u'v', u'', u'V', u'V', u'', u'', u''],
                48: [u'b', u'', u'B', u'B', u'', u'', u''],
                49: [u'n', u'', u'N', u'N', u'', u'', u''],
                50: [u'm', u'\n', u'M', u'M', u'', u'', u''],
                51: [u',', u'', u'<', u'<', u'', u'', u''],
                52: [u'.', u'', u'>', u'>', u'', u'', u''],
                53: [u'/', u'', u'?', u'?', u'', u'', u''],
                57: [u' ', u'', u' ', u' ', u'', u'', u''],
                96: [u'\n', u'', u'', u'', u'', u'', u'']
            }
        }
        self.eol = [(0, 28), (0, 96), (29, 39)]

        self.layout = layout

        self.device = None
        devices = map(InputDevice, list_devices())
        for device in devices:
            if device_name in device.name:
                self.device = InputDevice(device.fn)
                print('Lecteur de codes-barres : ' + device.name)
                break

        self._listeners = []
        Interruptable.__init__(self)
        self.device.grab()

    def start_capture(self):
        """TODO"""

        def run():
            barcode = ''
            modifier = 0
            keycode = 0
            for event in self.device.read_loop():
                if not self.interrupted():
                    if event.type == ecodes.EV_KEY:
                        data = categorize(event)
                        if data.keystate == 1:
                            if data.scancode in self.modifiers:
                                modifier = data.scancode
                            elif data.scancode in self.layouts[self.layout]:
                                keycode = data.scancode
                    elif event.type == ecodes.EV_SYN:
                        if (modifier, keycode) in self.eol:
                            if len(barcode) > 0:
                                for listener in self._listeners:
                                    listener(barcode)
                                barcode = ''
                        elif keycode != 0:
                            barcode += self.layouts[self.layout][keycode][self.modifiers[modifier]]
                        modifier = 0
                        keycode = 0
                else:
                    self.device.ungrab()
                    break


        thread = threading.Thread(target=run, name='barcode_scanner')
        thread.start()

    def register_listener(self, callback):
        self._listeners.append(callback)

1 个答案:

答案 0 :(得分:1)

我通过select()+ read()循环替换read_loop()方法解决了这个问题。通过这种方式,我可以对select进行超时。

#!/usr/bin/env python3
# -*-coding:Utf-8 -*

from evdev import InputDevice, ecodes, list_devices, categorize
from select import select
import signal, sys
import threading
from time import sleep

from tymsoft.interruptable import Interruptable

class BarcodeScanner(Interruptable):
    """TODO"""

    def __init__(self, device_name='Bar Code', layout='AZERTY_FR'):
        self.modifiers = {
            # 0: None, 29: u'LCTRL', 42: u'LSHFT', 54: u'RSHFT', 56: u'LALT', 97:u'RCTRL', 100: u'RALT'
            0: 0, 29: 1, 42: 2, 54: 3, 56: 4, 97: 5, 100: 6
        }
        self.layouts = {
            'AZERTY_FR': {
                # [NORMAL, LCTRL, LSHFT, RSHFT, LALT, RCTRL, RALT]
                2: [u'&', u'', u'1', u'1', u'', u'', u''],
                3: [u'é', u'', u'2', u'2', u'', u'', u'~'],
                4: [u'"', u'', u'3', u'3', u'', u'', u'#'],
                5: [u'\'', u'', u'4', u'4', u'', u'', u'{'],
                6: [u'(', u'', u'5', u'5', u'', u'', u'['],
                7: [u'-', u'', u'6', u'6', u'', u'', u'|'],
                8: [u'è', u'', u'7', u'7', u'', u'', u'`'],
                9: [u'_', u'', u'8', u'8', u'', u'', u'\\'],
                10: [u'ç', u'', u'9', u'9', u'', u'', u'^'],
                11: [u'à', u'', u'0', u'0', u'', u'', u'@'],
                12: [u')', u'', u'°', u'°', u'', u'', u']'],
                13: [u'=', u'', u'+', u'+', u'', u'', u'}'],
                15: [u'\t', u'', u'', u'', u'', u'', u''],
                16: [u'a', u'', u'A', u'A', u'', u'', u''],
                17: [u'z', u'', u'Z', u'Z', u'', u'', u''],
                18: [u'e', u'', u'E', u'E', u'', u'', u'€'],
                19: [u'r', u'', u'R', u'R', u'', u'', u''],
                20: [u't', u'', u'T', u'T', u'', u'', u''],
                21: [u'y', u'', u'Y', u'Y', u'', u'', u''],
                22: [u'u', u'', u'U', u'U', u'', u'', u''],
                23: [u'i', u'', u'I', u'I', u'', u'', u''],
                24: [u'o', u'', u'O', u'O', u'', u'', u''],
                25: [u'p', u'', u'P', u'P', u'', u'', u''],
                26: [u'^', u'', u'¨', u'¨', u'', u'', u''],
                27: [u'$', u'', u'£', u'£', u'', u'', u'¤'],
                28: [u'\n', u'', u'', u'', u'', u'', u''],
                30: [u'q', u'', u'Q', u'Q', u'', u'', u''],
                31: [u's', u'', u'S', u'S', u'', u'', u''],
                32: [u'd', u'', u'D', u'D', u'', u'', u''],
                33: [u'f', u'', u'F', u'F', u'', u'', u''],
                34: [u'g', u'', u'G', u'G', u'', u'', u''],
                35: [u'h', u'', u'H', u'H', u'', u'', u''],
                36: [u'j', u'', u'J', u'J', u'', u'', u''],
                37: [u'k', u'', u'K', u'K', u'', u'', u''],
                38: [u'l', u'', u'L', u'L', u'', u'', u''],
                39: [u'm', u'\n', u'M', u'M', u'', u'', u''],
                40: [u'ù', u'', u'%', u'%', u'', u'', u''],
                41: [u'²', u'', u'', u'', u'', u'', u''],
                43: [u'*', u'', u'µ', u'µ', u'', u'', u''],
                44: [u'w', u'', u'W', u'W', u'', u'', u''],
                45: [u'x', u'', u'X', u'X', u'', u'', u''],
                46: [u'c', u'', u'C', u'C', u'', u'', u''],
                47: [u'v', u'', u'V', u'V', u'', u'', u''],
                48: [u'b', u'', u'B', u'B', u'', u'', u''],
                49: [u'n', u'', u'N', u'N', u'', u'', u''],
                50: [u',', u'', u'?', u'?', u'', u'', u''],
                51: [u';', u'', u'.', u'.', u'', u'', u''],
                52: [u':', u'', u'/', u'/', u'', u'', u''],
                53: [u'!', u'', u'§', u'§', u'', u'', u''],
                57: [u' ', u'', u' ', u' ', u'', u'', u''],
                86: [u'<', u'', u'>', u'>', u'', u'', u''],
                96: [u'\n', u'', u'', u'', u'', u'', u'']
            },
            'QWERTY_US': {
                # [NORMAL, LCTRL, LSHFT, RSHFT, LALT, RCTRL, RALT]
                2: [u'1', u'', u'!', u'!', u'', u'', u''],
                3: [u'2', u'', u'@', u'@', u'', u'', u''],
                4: [u'3', u'', u'#', u'#', u'', u'', u''],
                5: [u'4', u'', u'$', u'$', u'', u'', u''],
                6: [u'5', u'', u'%', u'%', u'', u'', u''],
                7: [u'6', u'', u'^', u'^', u'', u'', u''],
                8: [u'7', u'', u'&', u'&', u'', u'', u''],
                9: [u'8', u'', u'*', u'*', u'', u'', u''],
                10: [u'9', u'', u'(', u'(', u'', u'', u''],
                11: [u'0', u'', u')', u')', u'', u'', u''],
                12: [u'-', u'', u'_', u'_', u'', u'', u''],
                13: [u'=', u'', u'+', u'+', u'', u'', u''],
                15: [u'\t', u'', u'', u'', u'', u'', u''],
                16: [u'q', u'', u'Q', u'Q', u'', u'', u''],
                17: [u'w', u'', u'W', u'W', u'', u'', u''],
                18: [u'e', u'', u'E', u'E', u'', u'', u''],
                19: [u'r', u'', u'R', u'R', u'', u'', u''],
                20: [u't', u'', u'T', u'T', u'', u'', u''],
                21: [u'y', u'', u'Y', u'Y', u'', u'', u''],
                22: [u'u', u'', u'U', u'U', u'', u'', u''],
                23: [u'i', u'', u'I', u'I', u'', u'', u''],
                24: [u'o', u'', u'O', u'O', u'', u'', u''],
                25: [u'p', u'', u'P', u'P', u'', u'', u''],
                26: [u'[', u'', u'{', u'{', u'', u'', u''],
                27: [u']', u'', u'}', u'}', u'', u'', u''],
                28: [u'\n', u'', u'', u'', u'', u'', u''],
                30: [u'a', u'', u'A', u'A', u'', u'', u''],
                31: [u's', u'', u'S', u'S', u'', u'', u''],
                32: [u'd', u'', u'D', u'D', u'', u'', u''],
                33: [u'f', u'', u'F', u'F', u'', u'', u''],
                34: [u'g', u'', u'G', u'G', u'', u'', u''],
                35: [u'h', u'', u'H', u'H', u'', u'', u''],
                36: [u'j', u'', u'J', u'J', u'', u'', u''],
                37: [u'k', u'', u'K', u'K', u'', u'', u''],
                38: [u'l', u'', u'L', u'L', u'', u'', u''],
                39: [u';', u'', u':', u':', u'', u'', u''],
                40: [u'\'', u'', u'"', u'"', u'', u'', u''],
                41: [u'`', u'', u'~', u'~', u'', u'', u''],
                43: [u'\\', u'', u'|', u'|', u'', u'', u''],
                44: [u'z', u'', u'Z', u'Z', u'', u'', u''],
                45: [u'x', u'', u'X', u'X', u'', u'', u''],
                46: [u'c', u'', u'C', u'C', u'', u'', u''],
                47: [u'v', u'', u'V', u'V', u'', u'', u''],
                48: [u'b', u'', u'B', u'B', u'', u'', u''],
                49: [u'n', u'', u'N', u'N', u'', u'', u''],
                50: [u'm', u'\n', u'M', u'M', u'', u'', u''],
                51: [u',', u'', u'<', u'<', u'', u'', u''],
                52: [u'.', u'', u'>', u'>', u'', u'', u''],
                53: [u'/', u'', u'?', u'?', u'', u'', u''],
                57: [u' ', u'', u' ', u' ', u'', u'', u''],
                96: [u'\n', u'', u'', u'', u'', u'', u'']
            }
        }
        self.eol = [(0, 28), (0, 96), (29, 39)]

        self.layout = layout

        self.device = None
        devices = map(InputDevice, list_devices())
        for device in devices:
            if device_name in device.name:
                self.device = InputDevice(device.fn)
                print('Lecteur de codes-barres : ' + device.name)
                break

        self._listeners = []
        Interruptable.__init__(self)
        self.device.grab()

    def start_capture(self):
        """TODO"""

        def run():
            barcode = ''
            modifier = 0
            keycode = 0
            while not self.interrupted():
                select([self.device], [], [], 0.25)
                try:
                    for event in self.device.read():
                            if event.type == ecodes.EV_KEY:
                                data = categorize(event)
                                if data.keystate == 1:
                                    if data.scancode in self.modifiers:
                                        modifier = data.scancode
                                    elif data.scancode in self.layouts[self.layout]:
                                        keycode = data.scancode
                            elif event.type == ecodes.EV_SYN:
                                if (modifier, keycode) in self.eol:
                                    if len(barcode) > 0:
                                        for listener in self._listeners:
                                            listener(barcode)
                                        barcode = ''
                                elif keycode != 0:
                                    barcode += self.layouts[self.layout][keycode][self.modifiers[modifier]]
                                modifier = 0
                                keycode = 0
                except BlockingIOError:
                    pass
            self.device.ungrab()

        thread = threading.Thread(target=run, name='barcode_scanner')
        thread.start()

    def register_listener(self, callback):
        self._listeners.append(callback)