def machine(request, capture): machine = Keyboard({'arpeggiate': request.param}) keymap = Keymap(Keyboard.KEYS_LAYOUT.split(), system.KEYS + Keyboard.ACTIONS) keymap.set_mappings(system.KEYMAPS['Keyboard']) machine.set_keymap(keymap) return machine
def get_system_keymap(self, machine_type=None): if machine_type is None: machine_type = self.get_machine_type() try: machine_class = machine_registry.get(machine_type) except: log.error("invalid machine type: %s", machine_type, exc_info=True) return None section = SYSTEM_CONFIG_SECTION % DEFAULT_SYSTEM option = SYSTEM_KEYMAP_OPTION % machine_type mappings = self._get(section, option, None) if mappings is None: mappings = system.KEYMAPS.get(machine_type) else: try: mappings = dict(json.loads(mappings)) except ValueError as e: log.error("invalid machine keymap, resetting to default", exc_info=True) mappings = system.KEYMAPS.get(machine_type) self.set_system_keymap(mappings, machine_type) keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions()) keymap.set_mappings(mappings) return keymap
def test_engine(engine): # Config load. assert engine.load_config() assert engine.events == [] # Startup. engine.start() assert engine.events == [ ('machine_state_changed', ('Fake', 'initializing'), {}), ('machine_state_changed', ('Fake', 'connected'), {}), ('config_changed', (engine.config, ), {}), ] assert FakeMachine.instance is not None assert not FakeMachine.instance.is_suppressed # Output enabled. engine.events.clear() engine.output = True assert engine.events == [ ('output_changed', (True, ), {}), ] assert FakeMachine.instance.is_suppressed # Machine reconnection. engine.events.clear() engine.reset_machine() assert engine.events == [ ('machine_state_changed', ('Fake', 'stopped'), {}), ('machine_state_changed', ('Fake', 'initializing'), {}), ('machine_state_changed', ('Fake', 'connected'), {}), ] assert FakeMachine.instance is not None assert FakeMachine.instance.is_suppressed # No machine reset on keymap change. engine.events.clear() new_keymap = Keymap(system.KEYS, system.KEYS) new_keymap.set_mappings(zip(system.KEYS, reversed(system.KEYS))) config_update = {'system_keymap': new_keymap} assert FakeMachine.instance.keymap != new_keymap engine.config = config_update assert engine.events == [ ('config_changed', (config_update, ), {}), ] assert FakeMachine.instance.keymap == new_keymap # Output disabled engine.events.clear() engine.output = False assert engine.events == [ ('output_changed', (False, ), {}), ] assert not FakeMachine.instance.is_suppressed # Stopped. engine.events.clear() engine.quit(42) assert engine.join() == 42 assert engine.events == [ ('machine_state_changed', ('Fake', 'stopped'), {}), ('quit', (), {}), ] assert FakeMachine.instance is None
def build_keymap(config, key, mappings=None): system = registry.get_plugin('system', key[1]).obj machine_class = registry.get_plugin('machine', key[2]).obj keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions()) if mappings is None: mappings = system.KEYMAPS.get(key[2]) if mappings is None: if machine_class.KEYMAP_MACHINE_TYPE is not None: # Try fallback. return build_keymap(config, (key[0], key[1], machine_class.KEYMAP_MACHINE_TYPE)) # No fallback... mappings = {} keymap.set_mappings(mappings) return keymap
def get_system_keymap(self, machine_type=None, system_name=None): if machine_type is None: machine_type = self.get_machine_type() try: machine_class = registry.get_plugin('machine', machine_type).resolve() except: log.error("invalid machine type: %s", machine_type, exc_info=True) return None if system_name is None: system_name = self.get_system_name() try: system = registry.get_plugin('system', system_name).resolve() except: log.error("invalid system name: %s", system_name, exc_info=True) return None section = SYSTEM_CONFIG_SECTION % system_name option = SYSTEM_KEYMAP_OPTION % machine_type mappings = self._get(section, option, None) if mappings is None: # No user mappings, use system default. mappings = system.KEYMAPS.get(machine_type) else: try: mappings = dict(json.loads(mappings)) except ValueError as e: log.error("invalid machine keymap, resetting to default", exc_info=True) self.set_system_keymap(None, machine_type) mappings = system.KEYMAPS.get(machine_type) if mappings is None: if machine_class.KEYMAP_MACHINE_TYPE is not None: # Try fallback. return self.get_system_keymap( machine_type=machine_class.KEYMAP_MACHINE_TYPE, system_name=system_name) # No fallback... mappings = {} keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions()) keymap.set_mappings(mappings) return keymap
def get_system_keymap(self, machine_type=None, system_name=None): if machine_type is None: machine_type = self.get_machine_type() try: machine_class = registry.get_plugin('machine', machine_type).obj except: log.error("invalid machine type: %s", machine_type, exc_info=True) return None if system_name is None: system_name = self.get_system_name() try: system = registry.get_plugin('system', system_name).obj except: log.error("invalid system name: %s", system_name, exc_info=True) return None section = SYSTEM_CONFIG_SECTION % system_name option = SYSTEM_KEYMAP_OPTION % machine_type mappings = self._get(section, option, None) if mappings is None: # No user mappings, use system default. mappings = system.KEYMAPS.get(machine_type) else: try: mappings = dict(json.loads(mappings)) except ValueError: log.error("invalid machine keymap, resetting to default", exc_info=True) self.set_system_keymap(None, machine_type) mappings = system.KEYMAPS.get(machine_type) if mappings is None: if machine_class.KEYMAP_MACHINE_TYPE is not None: # Try fallback. return self.get_system_keymap( machine_type=machine_class.KEYMAP_MACHINE_TYPE, system_name=system_name ) # No fallback... mappings = {} keymap = Keymap(machine_class.get_keys(), system.KEYS + machine_class.get_actions()) keymap.set_mappings(mappings) return keymap
class TinyMod4Machine(ThreadedStenotypeBase): # Layout of keys on board; used by plover in making of self.keymap KEYS_LAYOUT = ''' S1- T- P- H- *1 -F -P -L -T -D S2- K- W- R- *2 -R -B -G -S -Z A- O- #1 -E -U ''' def __init__(self, _): super(TinyMod4Machine, self).__init__() keys = self.get_keys() self.keymap = Keymap(keys, keys) self.keymap.set_mappings(zip(keys, keys)) self._pressed = False self._stack = ForthStack(8, 7) self._modeSelectPin = 12 # Set up and connect to harware def _connect(self): connected = False # Set plover mode to initializing self._initializing() try: # Init the raw pins io.setup(self._modeSelectPin, io.IN, pull_up_down = io.PUD_UP) io.setup(16, io.IN, pull_up_down = io.PUD_UP) io.setup(20, io.IN, pull_up_down = io.PUD_UP) io.setup(21, io.IN, pull_up_down = io.PUD_UP) io.setup(1, io.IN, pull_up_down = io.PUD_UP) io.setup(26, io.IN, pull_up_down = io.PUD_UP) io.setup(19, io.IN, pull_up_down = io.PUD_UP) io.setup(13, io.IN, pull_up_down = io.PUD_UP) io.setup(6, io.IN, pull_up_down = io.PUD_UP) io.setup(0, io.IN, pull_up_down = io.PUD_UP) # Init the port expander pins self._bus = smbus.SMBus(1) self._bus.write_byte_data(0x20, 0x0c, 0xff) self._bus.write_byte_data(0x20, 0x0d, 0xff) # Check if switch on board is set to NKRO if io.input(self._modeSelectPin): log.warning("NKRO not selected on board. TinyMod4 plugin Disabled.") self._error() return connected self._ready() connected = True return connected except: log.warning("Error setting up TinyMod4") self._error() return connected # Reconnect if disconnected def _reconnect(self): connected = self._connect() while not self.finished.isSet() and not connected: time.sleep(0.5) connected = self._connect() return connected # Stop listening for strokes def stop_capture(self): super(TinyMod4Machine, self).stop_capture() self._stopped() # Covert keys to stroke and send to plover for translation def _on_stroke(self, keys): steno_keys = self.keymap.keys_to_actions(keys) if steno_keys: self._notify(steno_keys) # Read keys from raw pins def _read_raw_keys(self): a = 0 a |= io.input(16) # 1 a |= (io.input(20) << 1) # 2 a |= (io.input(21) << 2) # 4 a |= (io.input(1) << 3) # 8 a |= (io.input(26) << 4) # 10 a |= (io.input(19) << 5) # 20 a |= (io.input(13) << 6) # 40 a |= (io.input(6) << 7) # 80 a |= (io.input(0) << 8) # 100 a ^= 0x01ff self._stack.push(a) # Read keys from port expander pins def _read_ab(self): a = self._bus.read_byte_data(0x20, 0x12) b = self._bus.read_byte_data(0x20, 0x13) a |= b << 8 a ^= 0xffff self._stack.push(a) # Read all keys combined def _read_all(self): self._pressed = True self._read_raw_keys() self._read_ab() self._stack.over() self._stack.over() self._stack.or_() a = self._stack.pop() if a == 0: self._pressed = False # Scan for keys def _scan(self): while not self._pressed: while not self._pressed: self._read_all() time.sleep(0.03) self._read_all() a = 0 b = 0 while self._pressed: self._read_all() b |= self._stack.pop() a |= self._stack.pop() self._stack.push(a) self._stack.push(b) # Convert and send keys def _send(self): b = self._stack.pop() a = self._stack.pop() keys = [] # Steno order: STKPWHRAO*EUFRPBLGTSDZ if a & 0x10: keys.append('S1-') if a & 0x08: keys.append('S2-') if a & 0x20: keys.append('T-') if a & 0x04: keys.append('K-') if a & 0x40: keys.append('P-') if a & 0x02: keys.append('W-') if a & 0x80: keys.append('H-') if a & 0x01: keys.append('R-') if b & 0x08: keys.append('A-') if b & 0x10: keys.append('O-') if a & 0x100: keys.append('*1') if b & 0x200: keys.append('*2') if b & 0x20: keys.append('#1') if b & 0x40: keys.append('-E') if b & 0x80: keys.append('-U') if b & 0x8000: keys.append('-F') if b & 0x01: keys.append('-R') if b & 0x4000: keys.append('-P') if b & 0x02: keys.append('-B') if b & 0x2000: keys.append('-L') if b & 0x04: keys.append('-G') if b & 0x1000: keys.append('-T') if b & 0x800: keys.append('-S') if b & 0x100: keys.append('-D') if b & 0x400: keys.append('-Z') if keys: self._on_stroke(keys) # Start the thread def run(self): self._ready() while not self.finished.isSet(): self._scan() self._send()
class StenotypeBase(object): """The base class for all Stenotype classes.""" # Layout of physical keys. KEYS_LAYOUT = '' # And possible actions to map to. ACTIONS = ( tuple(sorted(system.KEY_ORDER.keys(), key=lambda k: system.KEY_ORDER[k])) + ('no-op',) ) def __init__(self): self.keymap = Keymap(self.KEYS_LAYOUT.split(), self.ACTIONS) self.stroke_subscribers = [] self.state_subscribers = [] self.state = STATE_STOPPED def set_mappings(self, mappings): """Setup machine keymap: mappings of action to keys.""" self.keymap.set_mappings(mappings) def start_capture(self): """Begin listening for output from the stenotype machine.""" pass def stop_capture(self): """Stop listening for output from the stenotype machine.""" pass def add_stroke_callback(self, callback): """Subscribe to output from the stenotype machine. Argument: callback -- The function to call whenever there is output from the stenotype machine and output is being captured. """ self.stroke_subscribers.append(callback) def remove_stroke_callback(self, callback): """Unsubscribe from output from the stenotype machine. Argument: callback -- A function that was previously subscribed. """ self.stroke_subscribers.remove(callback) def add_state_callback(self, callback): self.state_subscribers.append(callback) def remove_state_callback(self, callback): self.state_subscribers.remove(callback) def _notify(self, steno_keys): """Invoke the callback of each subscriber with the given argument.""" for callback in self.stroke_subscribers: callback(steno_keys) def set_suppression(self, enabled): '''Enable keyboard suppression. This is only of use for the keyboard machine, to suppress the keyboard when then engine is running. ''' pass def suppress_last_stroke(self, send_backspaces): '''Suppress the last stroke key events after the fact. This is only of use for the keyboard machine, and the engine is resumed with a command stroke. Argument: send_backspaces -- The function to use to send backspaces. ''' pass def _set_state(self, state): self.state = state for callback in self.state_subscribers: callback(state) def _stopped(self): self._set_state(STATE_STOPPED) def _initializing(self): self._set_state(STATE_INITIALIZING) def _ready(self): self._set_state(STATE_RUNNING) def _error(self): self._set_state(STATE_ERROR) @classmethod def get_option_info(cls): """Get the default options for this machine.""" return {}
assert DictionaryConfig(short_path, False).to_dict() == \ {'path': short_path, 'enabled': False} # Test from_dict creation helper. assert DictionaryConfig.from_dict({'path': short_path}) == \ DictionaryConfig(short_path) assert DictionaryConfig.from_dict({'path': full_path, 'enabled': False}) == \ DictionaryConfig(short_path, False) if sys.platform.startswith('win32'): ABS_PATH = os.path.normcase(r'c:/foo/bar') else: ABS_PATH = '/foo/bar' DEFAULT_KEYMAP = Keymap(Keyboard.get_keys(), english_stenotype.KEYS + Keyboard.get_actions()) DEFAULT_KEYMAP.set_mappings(english_stenotype.KEYMAPS['Keyboard']) DEFAULTS = { 'space_placement': 'Before Output', 'start_attached': False, 'start_capitalized': False, 'undo_levels': config.DEFAULT_UNDO_LEVELS, 'log_file_name': expand_path('strokes.log'), 'enable_stroke_logging': False, 'enable_translation_logging': False, 'start_minimized': False, 'show_stroke_display': False, 'show_suggestions_display': False, 'translation_frame_opacity': 100, 'classic_dictionaries_display_order': False, 'enabled_extensions': set(),
class StenotypeBase(object): """The base class for all Stenotype classes.""" # Layout of physical keys. KEYS_LAYOUT = '' # And possible actions to map to. ACTIONS = system.KEYS + ('no-op', ) def __init__(self): self.keymap = Keymap(self.KEYS_LAYOUT.split(), self.ACTIONS) self.stroke_subscribers = [] self.state_subscribers = [] self.state = STATE_STOPPED def set_mappings(self, mappings): """Setup machine keymap: mappings of action to keys.""" self.keymap.set_mappings(mappings) def start_capture(self): """Begin listening for output from the stenotype machine.""" pass def stop_capture(self): """Stop listening for output from the stenotype machine.""" pass def add_stroke_callback(self, callback): """Subscribe to output from the stenotype machine. Argument: callback -- The function to call whenever there is output from the stenotype machine and output is being captured. """ self.stroke_subscribers.append(callback) def remove_stroke_callback(self, callback): """Unsubscribe from output from the stenotype machine. Argument: callback -- A function that was previously subscribed. """ self.stroke_subscribers.remove(callback) def add_state_callback(self, callback): self.state_subscribers.append(callback) def remove_state_callback(self, callback): self.state_subscribers.remove(callback) def _notify(self, steno_keys): """Invoke the callback of each subscriber with the given argument.""" for callback in self.stroke_subscribers: callback(steno_keys) def set_suppression(self, enabled): '''Enable keyboard suppression. This is only of use for the keyboard machine, to suppress the keyboard when then engine is running. ''' pass def suppress_last_stroke(self, send_backspaces): '''Suppress the last stroke key events after the fact. This is only of use for the keyboard machine, and the engine is resumed with a command stroke. Argument: send_backspaces -- The function to use to send backspaces. ''' pass def _set_state(self, state): self.state = state for callback in self.state_subscribers: callback(state) def _stopped(self): self._set_state(STATE_STOPPED) def _initializing(self): self._set_state(STATE_INITIALIZING) def _ready(self): self._set_state(STATE_RUNNING) def _error(self): self._set_state(STATE_ERROR) @classmethod def get_option_info(cls): """Get the default options for this machine.""" return {}
class KeyboardConfigDialog(wx.Dialog): """Keyboard configuration dialog.""" def __init__(self, options, parent, config): self.config = config self.options = options pos = (config.get_keyboard_config_frame_x(), config.get_keyboard_config_frame_y()) wx.Dialog.__init__(self, parent, title=DIALOG_TITLE, pos=pos) sizer = wx.BoxSizer(wx.VERTICAL) sizer_flags = wx.SizerFlags().Border(wx.ALL, UI_BORDER).Align( wx.ALIGN_CENTER_HORIZONTAL) instructions = wx.StaticText(self, label=ARPEGGIATE_INSTRUCTIONS) sizer.AddF(instructions, sizer_flags.Align(wx.LEFT)) self.arpeggiate_option = wx.CheckBox(self, label=ARPEGGIATE_LABEL) self.arpeggiate_option.SetValue(options.arpeggiate) sizer.AddF(self.arpeggiate_option, sizer_flags) # editable list for keymap bindings self.keymap = Keymap(Keyboard.KEYS_LAYOUT.split(), Keyboard.ACTIONS) mappings = config.get_system_keymap('Keyboard') if mappings is not None: self.keymap.set_mappings(mappings) self.keymap_widget = EditKeymapWidget(self) self.keymap_widget.set_mappings(self.keymap.get_mappings()) sizer.AddF(self.keymap_widget, sizer_flags.Expand()) ok_button = wx.Button(self, id=wx.ID_OK) ok_button.SetDefault() cancel_button = wx.Button(self, id=wx.ID_CANCEL, label='Cancel') reset_button = wx.Button(self, id=wx.ID_RESET, label='Reset to default') button_sizer = wx.BoxSizer(wx.HORIZONTAL) button_sizer.AddF(ok_button, sizer_flags) button_sizer.AddF(cancel_button, sizer_flags) button_sizer.AddF(reset_button, sizer_flags) sizer.AddF(button_sizer, sizer_flags) self.SetSizerAndFit(sizer) self.SetRect(AdjustRectToScreen(self.GetRect())) self.Bind(wx.EVT_MOVE, self.on_move) ok_button.Bind(wx.EVT_BUTTON, lambda e: self.EndModal(wx.ID_OK)) cancel_button.Bind(wx.EVT_BUTTON, lambda e: self.EndModal(wx.ID_CANCEL)) reset_button.Bind(wx.EVT_BUTTON, self.on_reset) def ShowModal(self): code = super(KeyboardConfigDialog, self).ShowModal() if wx.ID_OK == code: self.options.arpeggiate = self.arpeggiate_option.GetValue() # Validate mappings by updating the keymap object. self.keymap.set_mappings(self.keymap_widget.get_mappings()) self.config.set_system_keymap('Keyboard', self.keymap.get_mappings()) return code def on_reset(self, event): mappings = self.keymap_widget.get_mappings() mappings.update(system.KEYMAPS['Keyboard']) self.keymap_widget.set_mappings(mappings) def on_move(self, event): pos = self.GetScreenPositionTuple() self.config.set_keyboard_config_frame_x(pos[0]) self.config.set_keyboard_config_frame_y(pos[1]) event.Skip()
class StenotypeBase: """The base class for all Stenotype classes.""" # Layout of physical keys. KEYS_LAYOUT = '' # And special actions to map to. ACTIONS = () # Fallback to use as machine type for finding a compatible keymap # if one is not already available for this machine type. KEYMAP_MACHINE_TYPE = None def __init__(self): # Setup default keymap with no translation of keys. keys = self.get_keys() self.keymap = Keymap(keys, keys) self.keymap.set_mappings(zip(keys, keys)) self.stroke_subscribers = [] self.state_subscribers = [] self.state = STATE_STOPPED def set_keymap(self, keymap): """Setup machine keymap.""" self.keymap = keymap def start_capture(self): """Begin listening for output from the stenotype machine.""" pass def stop_capture(self): """Stop listening for output from the stenotype machine.""" pass def add_stroke_callback(self, callback): """Subscribe to output from the stenotype machine. Argument: callback -- The function to call whenever there is output from the stenotype machine and output is being captured. """ self.stroke_subscribers.append(callback) def remove_stroke_callback(self, callback): """Unsubscribe from output from the stenotype machine. Argument: callback -- A function that was previously subscribed. """ self.stroke_subscribers.remove(callback) def add_state_callback(self, callback): self.state_subscribers.append(callback) def remove_state_callback(self, callback): self.state_subscribers.remove(callback) def _notify(self, steno_keys): """Invoke the callback of each subscriber with the given argument.""" for callback in self.stroke_subscribers: callback(steno_keys) def set_suppression(self, enabled): '''Enable keyboard suppression. This is only of use for the keyboard machine, to suppress the keyboard when then engine is running. ''' pass def suppress_last_stroke(self, send_backspaces): '''Suppress the last stroke key events after the fact. This is only of use for the keyboard machine, and the engine is resumed with a command stroke. Argument: send_backspaces -- The function to use to send backspaces. ''' pass def _set_state(self, state): self.state = state for callback in self.state_subscribers: callback(state) def _stopped(self): self._set_state(STATE_STOPPED) def _initializing(self): self._set_state(STATE_INITIALIZING) def _ready(self): self._set_state(STATE_RUNNING) def _error(self): self._set_state(STATE_ERROR) @classmethod def get_actions(cls): """List of supported actions to map to.""" return cls.ACTIONS @classmethod def get_keys(cls): return tuple(cls.KEYS_LAYOUT.split()) @classmethod def get_option_info(cls): """Get the default options for this machine.""" return {}
class KeyboardConfigDialog(wx.Dialog): """Keyboard configuration dialog.""" def __init__(self, options, parent, config): self.config = config self.options = options pos = (config.get_keyboard_config_frame_x(), config.get_keyboard_config_frame_y()) wx.Dialog.__init__(self, parent, title=DIALOG_TITLE, pos=pos) sizer = wx.BoxSizer(wx.VERTICAL) sizer_flags = wx.SizerFlags().Border(wx.ALL, UI_BORDER).Align(wx.ALIGN_CENTER_HORIZONTAL) instructions = wx.StaticText(self, label=ARPEGGIATE_INSTRUCTIONS) sizer.AddF(instructions, sizer_flags.Align(wx.LEFT)) self.arpeggiate_option = wx.CheckBox(self, label=ARPEGGIATE_LABEL) self.arpeggiate_option.SetValue(options.arpeggiate) sizer.AddF(self.arpeggiate_option, sizer_flags) # editable list for keymap bindings self.keymap = Keymap(Keyboard.KEYS_LAYOUT.split(), Keyboard.ACTIONS) mappings = config.get_system_keymap('Keyboard') if mappings is not None: self.keymap.set_mappings(mappings) self.keymap_widget = EditKeymapWidget(self) self.keymap_widget.set_mappings(self.keymap.get_mappings()) sizer.AddF(self.keymap_widget, sizer_flags.Expand()) ok_button = wx.Button(self, id=wx.ID_OK) ok_button.SetDefault() cancel_button = wx.Button(self, id=wx.ID_CANCEL, label='Cancel') reset_button = wx.Button(self, id=wx.ID_RESET, label='Reset to default') button_sizer = wx.BoxSizer(wx.HORIZONTAL) button_sizer.AddF(ok_button, sizer_flags) button_sizer.AddF(cancel_button, sizer_flags) button_sizer.AddF(reset_button, sizer_flags) sizer.AddF(button_sizer, sizer_flags) self.SetSizerAndFit(sizer) self.SetRect(AdjustRectToScreen(self.GetRect())) self.Bind(wx.EVT_MOVE, self.on_move) ok_button.Bind(wx.EVT_BUTTON, lambda e: self.EndModal(wx.ID_OK)) cancel_button.Bind(wx.EVT_BUTTON, lambda e: self.EndModal(wx.ID_CANCEL)) reset_button.Bind(wx.EVT_BUTTON, self.on_reset) def ShowModal(self): code = super(KeyboardConfigDialog, self).ShowModal() if wx.ID_OK == code: self.options.arpeggiate = self.arpeggiate_option.GetValue() # Validate mappings by updating the keymap object. self.keymap.set_mappings(self.keymap_widget.get_mappings()) self.config.set_system_keymap('Keyboard', self.keymap.get_mappings()) return code def on_reset(self, event): mappings = self.keymap_widget.get_mappings() mappings.update(system.KEYMAPS['Keyboard']) self.keymap_widget.set_mappings(mappings) def on_move(self, event): pos = self.GetScreenPositionTuple() self.config.set_keyboard_config_frame_x(pos[0]) self.config.set_keyboard_config_frame_y(pos[1]) event.Skip()
{'path': short_path, 'enabled': False} # Test from_dict creation helper. assert DictionaryConfig.from_dict({'path': short_path}) == \ DictionaryConfig(short_path) assert DictionaryConfig.from_dict({'path': full_path, 'enabled': False}) == \ DictionaryConfig(short_path, False) if sys.platform.startswith('win32'): ABS_PATH = os.path.normcase(r'c:/foo/bar') else: ABS_PATH = '/foo/bar' DEFAULT_KEYMAP = Keymap(Keyboard.get_keys(), english_stenotype.KEYS + Keyboard.get_actions()) DEFAULT_KEYMAP.set_mappings(english_stenotype.KEYMAPS['Keyboard']) DEFAULTS = { 'space_placement': 'Before Output', 'start_attached': False, 'start_capitalized': False, 'undo_levels': config.DEFAULT_UNDO_LEVELS, 'log_file_name': expand_path('strokes.log'), 'enable_stroke_logging': False, 'enable_translation_logging':
def test_decoding(self): inputs = [ binascii.unhexlify(packet) for packet in ''' A90020 00 05464000 A904 0400 0D065000 A1008000 05 820400 17 00 8000 05 08 00 00 '''.split() ] # Mi piace mangiare la pizza. expected = 'CHRi/PIAce/CHRAh/PCIAre/HRa/PIsh/SPTa/P*'.split('/') keymap_mappings = { '#': '#', 'S': 'S-', 'P': 'T-', 'C': 'K-', 'T': 'P-', 'H': 'W-', 'V': 'H-', 'R': 'R-', 'I': 'A-', 'A': 'O-', '*': '*', 'E': '-E', 'O': '-U', 'c': '-F', 's': '-R', 't': '-P', 'h': '-B', 'p': '-L', 'r': '-G', 'i': '-T', 'e': '-S', 'a': '-D', 'o': '-Z', } serial_params = { name: value[0] for name, value in ItalianStentura.get_option_info().items() } keymap = Keymap(ItalianStentura.KEYS_LAYOUT.split(), keymap_mappings.keys()) keymap.set_mappings(keymap_mappings) with patch('plover.machine.base.serial.Serial', MockSerial) as mock: machine = ItalianStentura(serial_params) def stroke_callbak(steno_keys): self.assertEqual(''.join(steno_keys), expected.pop(0)) if not expected: machine.stop_capture() machine.add_stroke_callback(stroke_callbak) machine.set_keymap(keymap) mock.inputs = inputs mock.machine = machine machine.start_capture() machine.finished.wait() self.assertFalse(bool(expected))
class StenotypeBase(object): """The base class for all Stenotype classes.""" # Layout of physical keys. KEYS_LAYOUT = '' # And special actions to map to. ACTIONS = () # Fallback to use as machine type for finding a compatible keymap # if one is not already available for this machine type. KEYMAP_MACHINE_TYPE = None def __init__(self): # Setup default keymap with no translation of keys. keys = self.get_keys() self.keymap = Keymap(keys, keys) self.keymap.set_mappings(zip(keys, keys)) self.stroke_subscribers = [] self.state_subscribers = [] self.state = STATE_STOPPED def set_keymap(self, keymap): """Setup machine keymap.""" self.keymap = keymap def start_capture(self): """Begin listening for output from the stenotype machine.""" pass def stop_capture(self): """Stop listening for output from the stenotype machine.""" pass def add_stroke_callback(self, callback): """Subscribe to output from the stenotype machine. Argument: callback -- The function to call whenever there is output from the stenotype machine and output is being captured. """ self.stroke_subscribers.append(callback) def remove_stroke_callback(self, callback): """Unsubscribe from output from the stenotype machine. Argument: callback -- A function that was previously subscribed. """ self.stroke_subscribers.remove(callback) def add_state_callback(self, callback): self.state_subscribers.append(callback) def remove_state_callback(self, callback): self.state_subscribers.remove(callback) def _notify(self, steno_keys): """Invoke the callback of each subscriber with the given argument.""" for callback in self.stroke_subscribers: callback(steno_keys) def set_suppression(self, enabled): '''Enable keyboard suppression. This is only of use for the keyboard machine, to suppress the keyboard when then engine is running. ''' pass def suppress_last_stroke(self, send_backspaces): '''Suppress the last stroke key events after the fact. This is only of use for the keyboard machine, and the engine is resumed with a command stroke. Argument: send_backspaces -- The function to use to send backspaces. ''' pass def _set_state(self, state): self.state = state for callback in self.state_subscribers: callback(state) def _stopped(self): self._set_state(STATE_STOPPED) def _initializing(self): self._set_state(STATE_INITIALIZING) def _ready(self): self._set_state(STATE_RUNNING) def _error(self): self._set_state(STATE_ERROR) @classmethod def get_actions(cls): """List of supported actions to map to.""" return cls.ACTIONS @classmethod def get_keys(cls): return tuple(set(cls.KEYS_LAYOUT.split())) @classmethod def get_option_info(cls): """Get the default options for this machine.""" return {}