I went with a hacked up solution in the end. I got hold of the Python 'inputs' module, had a look at what the example gameport script was printing, then tried to marry this up with the kernel documentation (/usr/src/linux/Documentation/input/event-codes.txt), because that seemed to be the only place that explained about the events.
With a bit of trial-and-error I could map left and right to the z and x keys. The up and down are presumably ABS_HAT0Y.
I played around with this code, and bad things happen if you do too many release events for a key in pynput, but there seems to be no problem pushing a release event from pynput in combination with release events from the real keyboard (pressing both DPAD left + keyboard 'z' and other combinations).
Code:
#!/usr/bin/env python
#
# Remap hat L-R keys to keyboard 'z' and 'x'
# pip install inputs
# pip install pynput
from inputs import get_gamepad
from pynput.keyboard import Key, Controller
keyboard = Controller()
while 1:
events = get_gamepad()
for event in events:
if event.ev_type == "Absolute" and event.code == "ABS_HAT0X":
if event.state == -1:
keyboard.press('z')
elif event.state == 1:
keyboard.press('x')
else: # state == 0, centre position
if keyboard.pressed('z'):
keyboard.release('z')
if keyboard.pressed('x'):
keyboard.release('x')
And Frozen Bubble is happy :-)