Hardware Communication#

This page covers the details of communication protocols Plover uses to capture keyboard or steno writer input.

Keyboard Capture & Output#

Three implementations of keyboard capture and output are currently available:

  • The Windows implementation installs low-level event hooks to listen for key presses, and the Win32 API’s SendInput to generate keystrokes.

  • The macOS implementation uses Quartz’s Event Services API: event taps to listen for key presses, and keyboard events to generate keystrokes.

  • Linux and BSD both use an implementation based on Xlib’s xinput to listen for key presses, and xtest.fake_input to generate keystrokes, both of which require an X display server.

    Wayland is not currently supported.

Before implementing new keyboard capture and output mechanisms for a new platform, make sure to set up the platform layer for your platform.


New keyboard capture methods can be implemented as a subclass of Capture; your implementation should translate platform-specific events into calls to key_down and key_up.

class MyKeyboardCapture(Capture):
  def start(self):
    self._thread = threading.Thread(target=self._run)

  def _run(self):
    while True:
      key, pressed = ... # wait for key event

      if pressed:

Plover’s engine handles translating these calls into steno strokes, as well as handling keymaps and arpeggiation.


New keyboard emulation methods can be implemented as a subclass of Output. It must implement all of the methods specified, by translating them to platform-specific input calls.

class MyKeyboardEmulation(Output):
  def send_backspaces(self, num):

  def send_string(self, s):

  def send_key_combination(self, combo):

Serial Protocols#

Plover supports communicating with hobbyist, student, and professional steno writers through a serial interface. The most common protocols are Gemini PR for hobbyist writers and Stentura for Stenograph writers, but custom protocols may be implemented.

The SerialStenotypeBase class handles all of the connection establishment and configuration; when implementing a new serial interface, you only need to define your key layout and implement a way to parse each packet.

class MySerialMachine(SerialStenotypeBase):

  def run(self):

USB-based Protocols#


Complete this section.

Other Protocols#


Complete this section.