<commit_before>import smbus
from time import sleep
import threading

class InputDevice():
    """A driver for Adafruit-developed Raspberry Pi character LCD&button shields based on MCP23017, either Adafruit-made or Chinese-made.
 
       Tested on hardware compatible with Adafruit schematic and working with Adafruit libraries, but not on genuine Adafruit hardware. 
    """
    mapping = [
    "KEY_KPENTER",
    "KEY_RIGHT",
    "KEY_DOWN",
    "KEY_UP",
    "KEY_LEFT"]
    stop_flag = False
    previous_data = 0

    def __init__(self, addr = 0x20, bus = 1):
        """Initialises the ``InputDevice`` object.  
                                                                               
        Kwargs:                                                                  
                                                                                 
            * ``bus``: I2C bus number.
            * ``addr``: I2C address of the expander.

        """
        self.bus_num = bus
        self.bus = smbus.SMBus(self.bus_num)
        if type(addr) in [str, unicode]:
            addr = int(addr, 16)
        self.addr = addr

    def start(self):
        """Starts listening on the input device. Also, initialises the IO expander."""
        self.stop_flag = False
        self.setMCPreg(0x00, 0x1F)
        self.setMCPreg(0x0C, 0x1F)
        self.loop_polling()

    def loop_polling(self):
        """Polling loop. Stops when ``stop_flag`` is set to True."""
        button_states = []
        while not self.stop_flag:
            data = (~self.readMCPreg(0x12)&0x1F)
            if data != self.previous_data:
                self.process_data(data)
                self.previous_data = data
            sleep(0.01)

    def process_data(self, data):
        """Checks data received from IO expander and classifies changes as either "button up" or "button down" events. On "button up", calls send_key with the corresponding button name from ``self.mapping``. """
        data_difference = data ^ self.previous_data
        changed_buttons = []
        for i in range(8):
            if data_difference & 1<<i:
                changed_buttons.append(i)
        for button_number in changed_buttons:
            if not data & 1<<button_number:
                self.send_key(self.mapping[button_number])

    def stop(self):
        """Sets the ``stop_flag`` for loop functions."""
        self.stop_flag = True

    def send_key(self, key):
        """A hook to be overridden by ``InputListener``. Otherwise, prints out key names as soon as they're released so is useful for debugging."""
        print(key)

    def activate(self):
        """Starts a thread with ``start`` function as target."""
        self.thread = threading.Thread(target=self.start)
        self.thread.daemon = False
        self.thread.start()

    def setMCPreg(self, reg, val):
        """Sets the MCP23017 register."""
        self.bus.write_byte_data(self.addr, reg, val)

    def readMCPreg(self, reg):
        """Reads the MCP23017 register."""
        return self.bus.read_byte_data(self.addr, reg)


if __name__ == "__main__":
    id = InputDevice(addr = 0x20)
    id.start()<commit_msg>Fixed a bug where event loops would not exit<commit_after>import smbus
from time import sleep
import threading

class InputDevice():
    """A driver for Adafruit-developed Raspberry Pi character LCD&button shields based on MCP23017, either Adafruit-made or Chinese-made.
 
       Tested on hardware compatible with Adafruit schematic and working with Adafruit libraries, but not on genuine Adafruit hardware. 
    """
    mapping = [
    "KEY_KPENTER",
    "KEY_RIGHT",
    "KEY_DOWN",
    "KEY_UP",
    "KEY_LEFT"]
    stop_flag = False
    running = False
    previous_data = 0

    def __init__(self, addr = 0x20, bus = 1):
        """Initialises the ``InputDevice`` object.  
                                                                               
        Kwargs:                                                                  
                                                                                 
            * ``bus``: I2C bus number.
            * ``addr``: I2C address of the expander.

        """
        self.bus_num = bus
        self.bus = smbus.SMBus(self.bus_num)
        if type(addr) in [str, unicode]:
            addr = int(addr, 16)
        self.addr = addr

    def start(self):
        """Starts listening on the input device. Also, initialises the IO expander."""
        while self.running: #Avoiding starting a new loop while the previous one is active
            sleep(0.01)
        self.stop_flag = False
        self.running = True
        self.setMCPreg(0x00, 0x1F)
        self.setMCPreg(0x0C, 0x1F)
        self.loop_polling()
        self.running = False

    def loop_polling(self):
        """Polling loop. Stops when ``stop_flag`` is set to True."""
        button_states = []
        while not self.stop_flag:
            data = (~self.readMCPreg(0x12)&0x1F)
            if data != self.previous_data:
                self.process_data(data)
                self.previous_data = data
            sleep(0.01)

    def process_data(self, data):
        """Checks data received from IO expander and classifies changes as either "button up" or "button down" events. On "button up", calls send_key with the corresponding button name from ``self.mapping``. """
        data_difference = data ^ self.previous_data
        changed_buttons = []
        for i in range(8):
            if data_difference & 1<<i:
                changed_buttons.append(i)
        for button_number in changed_buttons:
            if not data & 1<<button_number:
                self.send_key(self.mapping[button_number])

    def stop(self):
        """Sets the ``stop_flag`` for loop functions."""
        self.stop_flag = True

    def send_key(self, key):
        """A hook to be overridden by ``InputListener``. Otherwise, prints out key names as soon as they're released so is useful for debugging."""
        print(key)

    def activate(self):
        """Starts a thread with ``start`` function as target."""
        self.thread = threading.Thread(target=self.start)
        self.thread.daemon = False
        self.thread.start()

    def deactivate(self):
        """Starts a thread with ``start`` function as target."""
        self.stop()

    def setMCPreg(self, reg, val):
        """Sets the MCP23017 register."""
        self.bus.write_byte_data(self.addr, reg, val)

    def readMCPreg(self, reg):
        """Reads the MCP23017 register."""
        return self.bus.read_byte_data(self.addr, reg)


if __name__ == "__main__":
    id = InputDevice(addr = 0x20)
    id.start()
{'fraction_non_alphanumeric': 0.0996568700581829, 'fraction_numerical': 0.014471132328807996, 'mean_word_length': 1.889655172413793, 'pattern_counts': {'":': 2, '<': 11, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7565551', 'n_tokens_mistral': 1960, 'n_tokens_neox': 1813, 'n_words': 568}