
.. include:: ver.rst
.. |date| date::

=======
marsond
=======

-----------------------------------------------------------------------
Fix Enter/Shift key timings on Marson/USBLink/MT606-1 PS/2-USB adaptors
-----------------------------------------------------------------------

:Manual section: 8
:Manual group: Urchlay's Stuff
:Date: |date|
:Version: |version|

SYNOPSIS
========

marsond [**-d** *delay-ms*] [**-f**] [**-k** *keyboard-device*] [**-p** *pause-ms* [**-s** *shift-ms*] [**-v**] | [**--help**] | [**--version**] | [**-V**]

DESCRIPTION
===========

**marsond** fixes two issues with a particular model of PS/2 => USB
keyboard adaptor. The symptoms:

- In games and emulators, the Enter key only works sometimes. This is
  caused by the firmware in the adaptor sending the keypress and release
  events only 8 milliseconds apart.

- In normal use, pressing either Shift key and Enter
  key simultaneously causes the shift key to get "stuck" and act like
  it's still being held down. You have to press and release Shift again
  to get it to "unstick".

See the **NOTES** section for full details.

For normal use, **marsond** will be started by a **udev**\(7) rule
when the adaptor is plugged in (including booting with the adaptor
connected). The udev rule is found in:

  /etc/udev/rules.d/99-marsond.rules

...which can be edited to change the options it's run with, if
needed. The defaults work well on the author's system.

Note that **marsond** doesn't affect the PS/2 mouse port on the
adaptor at all.

OPTIONS
=======

Options can be "bundled": **-vf** is the same as **-v** **-f**.

-d delay-ms
  Amount of time in milliseconds to delay the Enter key release
  events. Also, the Shift key threshold is this times 4, unless set
  with the **-s** option. Minimum 1, default 30 (unless changed at
  compile time; see **--help**).

.. delay time for Enter key release.

-f
  Run in the foreground; do not detach from the terminal or become a
  daemon. In this mode, **marsond** can be killed with *^C*.

.. run in foreground, not as a daemon.

-k keyboard-device
  Input device for the keyboard adaptor. Default::

    /dev/input/by-id/usb-Marson_Marson_Keyboard_and_Mouse_Link_Ver:ps2120L-event-kbd

  \.\.\.unless changed at compile time; see **--help**.

.. keyboard device (usually under /dev/input/by-id/).

-p pause-ms
  Amount of time in milliseconds to pause at startup, before opening the
  keyboard and uinput devices. May be useful on slow systems, if
  **marsond** won't consistently start from udev, but works fine
  if started manually. Minimum 0, default 0.

.. pause before opening keyboard/uinput devs (default 0).

-s thresh-ms
  Threshold for Shift key. If Enter is pressed within **thresh-ms** of
  either Shift key, a Shift key release will be sent before the Enter
  keypress. This avoids the "stuck shift key" problem. Default is
  120, or 4 times the **-d** delay if set.

.. threshold in ms for shift key followed by enter (default 30 or -d * 3).

-v
  Verbose debugging mode. Prints copious trace information to **stderr**.
  Debugging mode is turned off when **marsond** forks itself into the
  background as a daemon. If you want to debug the event loop, combine
  **-v** and **-f**.

.. verbose debugging.

-h, --help
  Shows built-in usage message and exits. This includes the
  compiled-in defaults for the **-d** and **-k** options.

.. this help text.

-V, --version
  Shows version number and exits.

.. show version number.

ENVIRONMENT
===========

MARSOND_USER
  After initialization, **marsond** will drop privileges by
  setting its user ID to this user's. Default: *nobody*

MARSOND_GROUP
  Group to run as, after dropping privileges. Default:
  the primary group of the user it's running as. Normally
  you won't have to set this.

NOTES
=====

Hardware
--------

The Enter key dropped keystroke problem happens with any SDL
application (SDL1 or SDL2), as well as other graphics libraries. It
happens regardless of what PS/2 keyboard you have plugged in, what
computer you have the adaptor plugged into, or what OS that computer
is running. The firmware in the adaptor sends an Enter keypress, then
8 microseconds later sends an Enter key release. There is no way to
change this.

The problem where Shift/Enter causes the Shift key to act "stuck"
happens in any application. It's particularly annoying because I'm an
inaccurate typist, and I hit right Shift+Enter about 5% of the time when I'm
just trying to press Enter.

The specific hardware that has the problems for me is USB
vendor ID 04b4, product ID 0101, "Marson Keyboard and Mouse Link
Ver:ps2120L". It has a label on the front that says "USBLink", and on
the back, the model number is "MT606-1". It looks like:

  https://slackware.uk/~urchlay/sdl-usblink-hack/marson-front.jpg

  https://slackware.uk/~urchlay/sdl-usblink-hack/marson-back.jpg

Confusingly enough, in **lsusb**\(8) output, it shows up as::

  $ lsusb | grep 04b4:0101
  Bus 003 Device 006: ID 04b4:0101 Cypress Semiconductor Corp. Keyboard/Hub

The Bus and Device numbers may be different for you, it's the ID and
name that are important.

I'm not sure if any other USB keyboard adaptors are affected. If
you have the problem on some other adaptor, try it with **marsond**.
Use the **-k** option to set the */dev/input/by-id* name of the device,
and run the daemon manually. If this fixes it, please contact me so I
can add support for your adaptor in the future. In the meantime,
you can compile **marsond** with your device's info on the make
command line::

  make DEFAULT_KBD=/dev/input/by-id/<whatever> VENDOR_ID=<xxxx> PRODUCT_ID=<xxxx>

Implementation
--------------

**marsond** uses the Linux kernel's **uinput** layer to "grab" the
keyboard, create a new virtual keyboard device, and pass events from
the real keyboard to the virtual one. When it sees the key release
event for the Enter key, it simply pauses for a few milliseconds
before delivering it.

It also keeps track of the last timestamp of the left and right Shift
keys, and if Enter is pressed too soon after Shift, it sends a key
release for the Shift key(s). It's still possible to type Shift+Enter
on purpose, but there must be a delay (default 120ms) between the two
keypresses. Most people, even fast typists, won't press them that
close together.

This should work with everything that uses the keyboard. It definitely
does, with SDL 1 and 2 running under X (and SDL 1 on the console,
too). It should also work with Wayland, though I don't use Wayland,
so I haven't tested it there. If you do, please contact me and let me
know whether or not it works for you.

Startup
-------

**marsond** must be run as root. At startup, it does these
things as root:

- Grab the physical keyboard.

- Create the virtual keyboard device.

- Lock its pages into physical memory, to avoid being swapped out.

- Set its priority (nice value) to -20 (highest priority), to
  avoid slow response on a loaded system.

After doing the above, root access is no longer needed, so it will
drop privileges and run as the *nobody* user by default (but see
**ENVIRONMENT** if you need a different user).

Misc
----

While **marsond** is running, "xinput --list" will show an input
device called "marson virtual keyboard", listed as a keyboard.

LIMITATIONS
===========

Only one MT-606-1 device is supported, out of the box. This shouldn't
really be a problem (do you really need 2 keyboards?) but it's worth
mentioning. If you really do own two of these adaptors and want to use
them on the same PC, you could add a second udev rule (with **-k** option
for the daemon).

This isn't really a **marsond** problem per se, but when Xorg detects
a new keyboard, it resets your keyboard repeat rate (**xset r**)
and custom keymap (**xmodmap**\(1)). If you use a 'desktop' such
as KDE, GNOME, or XFCE, it should re-apply your settings. For a
traditional window manager (WindowMaker, FVWM2, etc), this can be very
annoying.

.. EXIT STATUS
.. ===========

.. BUGS
.. ====

.. EXAMPLES
.. ========

COPYRIGHT
=========

WTFPL. Short version: do WTF you want. Full version:

  http://www.wtfpl.net/txt/copying/

AUTHORS
=======

B. Watson <urchlay@slackware.uk>

SEE ALSO
========

The homepage: https://slackware.uk/~urchlay/repos/marsond

Another solution to the problem, less complete, but should be portable
to non-Linux OSes: https://slackware.uk/~urchlay/sdl-usblink-hack/
