Revision: 45614
http://sourceforge.net/p/vice-emu/code/45614
Author: compyx
Date: 2025-03-31 16:34:58 +0000 (Mon, 31 Mar 2025)
Log Message:
-----------
Merge branch compyx/joymap-001 into trunk
This is the first step towards proper joystick mapping and calibration in the
Gtk3 UI (and future UIs):
* Reorganize data structures: mappings now are members of axis, button and hat
objects, and a joystick device is a collection of axes, buttons and hats.
Also add calibration data as members of the axis and button objects.
* Move responsibilities from the drivers to common code: the drivers pass raw
axis and button values to the common code and the common code decides what
those values mean (applying calibration). Hats are a different beast: so
currently the drivers need to decide which joystick directions their hat
values translate to.
* Managing resources is done (mostly) in common code: joystick devices take
ownership of axis, button and hat objects and the common code takes ownership
of joystick devices. The drivers are responsible for allocating and freeing
any arch-specific data, the rest is taken care of by the common code.
* Add additional information about host inputs in the data structures: for the
UI we need names of the axes, buttons and hats, and to be able to identify
the devices we need vendor and product IDs (so at a later point we can have
per-device loading of mappings/calibration).
* Identify inputs by ID, rather than index: SDL may refer to inputs by index,
but Linux evdev, Free/NetBSD HID and DirectInput do not. DirectInput and BSD
drivers are new implementations and Linux evdev was already a recent addition.
Modified Paths:
--------------
trunk/vice/doc/Makefile.am
trunk/vice/doc/mkdoxy.sh
trunk/vice/src/arch/gtk3/joystickdrv/joystick_bsd.c
trunk/vice/src/arch/gtk3/joystickdrv/joystick_linux_evdev.c
trunk/vice/src/arch/gtk3/joystickdrv/joystick_win32_directinput.c
trunk/vice/src/arch/sdl/joy.c
trunk/vice/src/arch/sdl/joy.h
trunk/vice/src/arch/sdl/menu_joystick.c
trunk/vice/src/arch/sdl/ui.c
trunk/vice/src/arch/sdl/uimenu.c
trunk/vice/src/joyport/joystick.c
trunk/vice/src/joyport/joystick.h
trunk/vice/src/machine.c
Added Paths:
-----------
trunk/vice/data/CBM-II/sdl_sym_de.vkm
trunk/vice/doc/joystick.md
Removed Paths:
-------------
trunk/vice/data/CBM-II/sdl_sym_de.vkm
Deleted: trunk/vice/data/CBM-II/sdl_sym_de.vkm
===================================================================
--- trunk/vice/data/CBM-II/sdl_sym_de.vkm 2025-03-31 07:56:10 UTC (rev 45613)
+++ trunk/vice/data/CBM-II/sdl_sym_de.vkm 2025-03-31 16:34:58 UTC (rev 45614)
@@ -1,288 +0,0 @@
-# VICE keyboard mapping file
-#
-# A Keyboard map is read in as patch to the current map.
-#
-# File format:
-# - comment lines start with '#'
-# - keyword lines start with '!keyword'
-# - normal lines have 'keysym/scancode row column shiftflag'
-#
-# Keywords and their lines are:
-# '!CLEAR' clear whole table
-# '!INCLUDE filename' read file as mapping file
-# '!LSHIFT row col' left shift keyboard row/column
-# '!RSHIFT row col' right shift keyboard row/column
-# '!VSHIFT shiftkey' virtual shift key (RSHIFT or LSHIFT)
-# '!SHIFTL shiftkey' shift lock key (RSHIFT or LSHIFT)
-# for emulated keyboards that have only one shift key, set both LSHIFT
-# and RSHIFT to the same row/col and use RSHIFT for VSHIFT and SHIFTL.
-# '!LCTRL row col' left control keyboard row/column
-# '!VCTRL ctrlkey' virtual control key (LCTRL)
-# '!LCBM row col' left CBM keyboard row/column
-# '!VCBM cbmkey' virtual CBM key (LCBM)
-# '!UNDEF keysym' remove keysym from table
-#
-# Shiftflag can have these values, flags can be ORed to combine them:
-# 0x0000 0 key is not shifted for this keysym/scancode
-# 0x0001 1 key is combined with shift for this keysym/scancode
-# 0x0002 2 key is left shift on emulated machine
-# 0x0004 4 key is right shift on emulated machine (use only this one
-# for emulated keyboards that have only one shift key)
-# 0x0008 8 key can be shifted or not with this keysym/scancode
-# 0x0010 16 deshift key for this keysym/scancode
-# 0x0020 32 another definition for this keysym/scancode follows
-# 0x0040 64 key is shift-lock on emulated machine
-# 0x0080 128 shift modifier required on host
-# 0x0100 256 key is used for an alternative keyboard mapping, e.g. C64 mode in x128
-# 0x0200 512 alt-r (alt-gr) modifier required on host
-# 0x0400 1024 ctrl modifier required on host
-# 0x0800 2048 key is combined with cbm for this keysym/scancode
-# 0x1000 4096 key is combined with ctrl for this keysym/scancode
-# 0x2000 8192 key is (left) cbm on emulated machine
-# 0x4000 16384 key is (left) ctrl on emulated machine
-#
-# Negative row values:
-# 'keysym -1 n' joystick keymap A, direction n
-# 'keysym -2 n' joystick keymap B, direction n
-# 'keysym -3 0' first RESTORE key
-# 'keysym -3 1' second RESTORE key
-# 'keysym -4 0' 40/80 column key (x128)
-# 'keysym -4 1' CAPS (ASCII/DIN) key (x128)
-# 'keysym -5 n' joyport keypad, key n (not supported in x128)
-#
-# Joystick direction values:
-# 0 Fire
-# 1 South/West
-# 2 South
-# 3 South/East
-# 4 West
-# 5 East
-# 6 North/West
-# 7 North
-# 8 North/East
-#
-# Joyport keypad key layout:
-# --------------------------
-# | 0 | 1 | 2 | 3 | 4 |
-# --------------------------
-# | 5 | 6 | 7 | 8 | 9 |
-# --------------------------
-# | 10 | 11 | 12 | 13 | 14 |
-# --------------------------
-# | 15 | 16 | 17 | 18 | 19 |
-# --------------------------
-#
-# When a bigger spaced key is used,
-# it uses the upper left most key value.
-
-# Symbolic Mapping, DE Layout, CBM2, SDL
-
-# note: For some reason SDL does not get keyboard events for "dead keys" at all,
-# so a "nodeadkeys" layout must be used. CAUTION: apparently SDL generates
-# some tables internally at startup - switching the host layout while
-# the emulator is running produces unpredictable results (broken keycodes)
-
-# Commodore cbm2 keyboard matrix:
-#
-# references:
-# http://www.zimmers.net/anonftp/pub/cbm/b/documents/de/keyboard-matrix.gif
-# http://www.zimmers.net/anonftp/pub/cbm/b/documents/keymap-us.gif
-# http://www.zimmers.net/anonftp/pub/cbm/schematics/computers/b/p500-keyboard.txt
-# http://www.floodgap.com/retrobits/ckb/secret/cbm-610-keyboard.jpg
-#
-# Keys starting with 'KP' are on the number pad. Both shifts and shift lock
-# are in parallel at one point in matrix.
-#
-# 0 1 2 3 4 5
-# +--------+--------+--------+--------+--------+--------+
-# 0 | F9 | 9 ( | O | L | ; : | / ? |
-# +--------+--------+--------+--------+--------+--------+
-# 1 | F10 | 0 ) | - | P | [ | ' " |
-# +--------+--------+--------+--------+--------+--------+
-# 2 | c.down | = + |<- pound| ] | return | pi |
-# +--------+--------+--------+--------+--------+--------+
-# 3 | c.up | c.left | c.right|del ins | CBM |########|
-# +--------+--------+--------+--------+--------+--------+
-# 4 |home/clr|KP ? |KP 7 |KP 4 |KP 1 |KP 0 |
-# +--------+--------+--------+--------+--------+--------+
-# 5 |rvs/off |KP CE |KP 8 |KP 5 |KP 2 |KP . |
-# +--------+--------+--------+--------+--------+--------+
-# 6 | graph |KP * |KP 9 |KP 6 |KP 3 |KP 00 |
-# +--------+--------+--------+--------+--------+--------+
-# 7 |run/stop|KP / |KP - |KP + |KP enter|########|
-# +--------+--------+--------+--------+--------+--------+
-# 8 | F1 | escape | TAB |########| Shift | CTRL |
-# +--------+--------+--------+--------+--------+--------+
-# 9 | F2 | 1 ! | Q | A | Z |########|
-# +--------+--------+--------+--------+--------+--------+
-#10 | F3 | 2 @ | W | S | X | C |
-# +--------+--------+--------+--------+--------+--------+
-#11 | F4 | 3 # | E | D | F | V |
-# +--------+--------+--------+--------+--------+--------+
-#12 | F5 | 4 $ | R | T | G | B |
-# +--------+--------+--------+--------+--------+--------+
-#13 | F6 | 5 % | 6 ^ | Y | H | N |
-# +--------+--------+--------+--------+--------+--------+
-#14 | F7 | 7 & | U | J | M | space |
-# +--------+--------+--------+--------+--------+--------+
-#15 | F8 | 8 * | I | K | , < | . > |
-# +--------+--------+--------+--------+--------+--------+
-
-# CBM2 Keyboard layout:
-#
-# F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 down up left right clr rvs graph r/s
-#
-# ESC 1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) - =+ arrow/pound del ? CE * /
-# TAB q w e r t y u i o p [ ] return 7 8 9 -
-# SL a s d f g h j k l ;: '" pi 4 5 6 +
-# LS z x c v b n m ,< .> /? RS CBM 1 2 3
-# CTRL SPACE 0 . 00 enter
-
-!CLEAR
-!LSHIFT 8 4
-!RSHIFT 8 4
-!VSHIFT RSHIFT
-!SHIFTL RSHIFT
-!LCBM 3 4
-!VCBM LCBM
-!LCTRL 8 5
-!VCTRL LCTRL
-
-27 8 1 8 /* ESC -> ESC */
-
-49 9 1 8 /* 1 -> 1 */
-50 10 1 0x20 /* 2 -> 2 */
-50 1 5 0x80 /* shift 2 -> " */
-51 11 1 8 /* 3 -> 3 */
-52 12 1 8 /* 4 -> 4 */
-53 13 1 8 /* 5 -> 5 */
-54 13 2 0x20 /* 6 -> 6 */
-54 14 1 0x81 /* shift 6 -> & shift+7 */
-55 14 1 0x20 /* 7 -> 7 */
-55 0 5 0x90 /* shift 7 -> / */
-56 15 1 0x20 /* 8 -> 8 */
-56 0 1 0x80 /* shift 8 -> ( shift+9 */
-57 0 1 0x20 /* 9 -> 9 */
-57 1 1 0x80 /* shift 9 -> ) shift+0 */
-48 1 1 0x20 /* 0 -> 0 */
-48 2 1 0x90 /* shift 0 -> = */
-
-223 4 1 0x00b0 /* shift ? -> ? */
-223 4 1 0x0201 /* ctrl ? -> ctrl+ */
-
-180 2 2 8 /* ´ ` -> pound */
-
-45 1 2 0x20 /* Minus -> Minus */
-45 2 2 0x90 /* shift+Minus -> left arrow */
-
-306 8 5 0x4008 /* Left Ctrl -> CTRL */
-305 3 4 0x2008 /* Right Ctrl -> CBM */
-
-304 8 4 4 /* Left Shift -> Shift */
-301 8 4 64 /* Caps Lock -> Shift Lock */
-303 8 4 4 /* Right Shift -> Shift */
-
-32 14 5 8 /* Space -> Space */
-8 3 3 8 /* Backspace -> Del */
-9 8 2 8 /* TAB -> TAB */
-13 2 4 8 /* Return -> Return */
-
-44 15 4 0x20 /* , -> , */
-44 0 4 0x90 /* shift , -> ; */
-
-46 15 5 0x20 /* . -> . */
-46 0 4 0x420 /* ctrl . -> . */
-46 0 4 0x80 /* shift . -> : */
-
-#47 0 5 8 /* / -> / */
-
-60 15 4 0x021 /* < -> ,+shift */
-60 15 5 0x080 /* shift > -> .+shift */
-
-43 2 1 0x21 /* + -> Plus */
-43 15 1 0x80 /* shift++ -> * */
-
-252 10 1 1 /* ue -> @ */
-246 1 4 8 /* oe -> [ */
-228 2 3 8 /* ae -> ] */
-
-35 11 1 33 /* # -> 3+shift */
-35 1 5 0x420 /* ctrl # -> '+ctrl */
-35 1 5 0x90 /* ' -> 7+shift */
-
-94 13 2 0x021 /* ^ -> shift+6 (arrow up) */
-94 2 5 0x420 /* ctrl ^ -> pi */
-94 2 5 0x8b0 /* shift ^ -> pi */
-
-113 9 2 0x28 /* Q -> Q */
-113 10 1 0x201 /* altgr Q -> @ */
-
-119 10 2 8 /* W -> W */
-101 11 2 8 /* E -> E */
-114 12 2 8 /* R -> R */
-116 12 3 8 /* T -> T */
-121 13 3 8 /* Y -> Y */
-117 14 2 8 /* U -> U */
-105 15 2 8 /* I -> I */
-111 0 2 8 /* O -> O */
-112 1 3 8 /* P -> P */
-97 9 3 8 /* A -> A */
-115 10 3 8 /* S -> S */
-100 11 3 8 /* D -> D */
-102 11 4 8 /* F -> F */
-103 12 4 8 /* G -> G */
-104 13 4 8 /* H -> H */
-106 14 3 8 /* J -> J */
-107 15 3 8 /* K -> K */
-108 0 3 8 /* L -> L */
-122 9 4 8 /* Z -> Z */
-120 10 4 8 /* X -> X */
-99 10 5 8 /* C -> C */
-118 11 5 8 /* V -> V */
-98 12 5 8 /* B -> B */
-110 13 5 8 /* N -> N */
-109 14 4 8 /* M -> M */
-
-
-282 8 0 8 /* F1 -> F1 */
-283 9 0 8 /* F2 -> F2 */
-284 10 0 8 /* F3 -> F3 */
-285 11 0 8 /* F4 -> F4 */
-286 12 0 8 /* F5 -> F5 */
-287 13 0 8 /* F6 -> F6 */
-288 14 0 8 /* F7 -> F7 */
-289 15 0 8 /* F8 -> F8 */
-290 0 0 8 /* F9 -> F9 */
-291 1 0 8 /* F10 -> F10 */
-
-#292 1 0 8 /* F11 -> (unused) */
-#293 1 0 8 /* F12 -> run/stop */
-
-273 3 0 8 /* Up -> CRSR UP */
-276 3 1 8 /* Left -> CRSR LEFT */
-275 3 2 8 /* Right -> CRSR RIGHT */
-274 2 0 8 /* Down -> CRSR DOWN */
-
-277 6 5 8 /* Ins -> KP 00 */
-127 5 1 8 /* Del -> KP CE */
-278 4 0 8 /* Home -> CLR/HOME */
-279 5 0 8 /* End -> Rev/Off */
-280 7 0 8 /* PgUp -> Run/Stop */
-281 6 0 8 /* PgDown -> Norm/Graph */
-
-271 7 4 8 /* Numpad Enter -> Numpad Enter */
-267 7 1 8 /* Numpad / -> Numpad / */
-268 6 1 8 /* Numpad * -> Numpad * */
-263 4 2 8 /* Numpad 7 -> Numpad 7 */
-264 5 2 8 /* Numpad 8 -> Numpad 8 */
-265 6 2 8 /* Numpad 9 -> Numpad 9 */
-269 7 2 8 /* Numpad - -> Numpad - */
-260 4 3 8 /* Numpad 4 -> Numpad 4 */
-261 5 3 8 /* Numpad 5 -> Numpad 5 */
-262 6 3 8 /* Numpad 6 -> Numpad 6 */
-270 7 3 8 /* Numpad + -> Numpad + */
-257 4 4 8 /* Numpad 1 -> Numpad 1 */
-258 5 4 8 /* Numpad 2 -> Numpad 2 */
-259 6 4 8 /* Numpad 3 -> Numpad 3 */
-256 4 5 8 /* Numpad 0 -> Numpad 0 */
-266 5 5 8 /* Numpad . -> Numpad . */
Copied: trunk/vice/data/CBM-II/sdl_sym_de.vkm (from rev 45613, branches/compyx/joymap-001/vice/data/CBM-II/sdl_sym_de.vkm)
===================================================================
--- trunk/vice/data/CBM-II/sdl_sym_de.vkm (rev 0)
+++ trunk/vice/data/CBM-II/sdl_sym_de.vkm 2025-03-31 16:34:58 UTC (rev 45614)
@@ -0,0 +1,288 @@
+# VICE keyboard mapping file
+#
+# A Keyboard map is read in as patch to the current map.
+#
+# File format:
+# - comment lines start with '#'
+# - keyword lines start with '!keyword'
+# - normal lines have 'keysym/scancode row column shiftflag'
+#
+# Keywords and their lines are:
+# '!CLEAR' clear whole table
+# '!INCLUDE filename' read file as mapping file
+# '!LSHIFT row col' left shift keyboard row/column
+# '!RSHIFT row col' right shift keyboard row/column
+# '!VSHIFT shiftkey' virtual shift key (RSHIFT or LSHIFT)
+# '!SHIFTL shiftkey' shift lock key (RSHIFT or LSHIFT)
+# for emulated keyboards that have only one shift key, set both LSHIFT
+# and RSHIFT to the same row/col and use RSHIFT for VSHIFT and SHIFTL.
+# '!LCTRL row col' left control keyboard row/column
+# '!VCTRL ctrlkey' virtual control key (LCTRL)
+# '!LCBM row col' left CBM keyboard row/column
+# '!VCBM cbmkey' virtual CBM key (LCBM)
+# '!UNDEF keysym' remove keysym from table
+#
+# Shiftflag can have these values, flags can be ORed to combine them:
+# 0x0000 0 key is not shifted for this keysym/scancode
+# 0x0001 1 key is combined with shift for this keysym/scancode
+# 0x0002 2 key is left shift on emulated machine
+# 0x0004 4 key is right shift on emulated machine (use only this one
+# for emulated keyboards that have only one shift key)
+# 0x0008 8 key can be shifted or not with this keysym/scancode
+# 0x0010 16 deshift key for this keysym/scancode
+# 0x0020 32 another definition for this keysym/scancode follows
+# 0x0040 64 key is shift-lock on emulated machine
+# 0x0080 128 shift modifier required on host
+# 0x0100 256 key is used for an alternative keyboard mapping, e.g. C64 mode in x128
+# 0x0200 512 alt-r (alt-gr) modifier required on host
+# 0x0400 1024 ctrl modifier required on host
+# 0x0800 2048 key is combined with cbm for this keysym/scancode
+# 0x1000 4096 key is combined with ctrl for this keysym/scancode
+# 0x2000 8192 key is (left) cbm on emulated machine
+# 0x4000 16384 key is (left) ctrl on emulated machine
+#
+# Negative row values:
+# 'keysym -1 n' joystick keymap A, direction n
+# 'keysym -2 n' joystick keymap B, direction n
+# 'keysym -3 0' first RESTORE key
+# 'keysym -3 1' second RESTORE key
+# 'keysym -4 0' 40/80 column key (x128)
+# 'keysym -4 1' CAPS (ASCII/DIN) key (x128)
+# 'keysym -5 n' joyport keypad, key n (not supported in x128)
+#
+# Joystick direction values:
+# 0 Fire
+# 1 South/West
+# 2 South
+# 3 South/East
+# 4 West
+# 5 East
+# 6 North/West
+# 7 North
+# 8 North/East
+#
+# Joyport keypad key layout:
+# --------------------------
+# | 0 | 1 | 2 | 3 | 4 |
+# --------------------------
+# | 5 | 6 | 7 | 8 | 9 |
+# --------------------------
+# | 10 | 11 | 12 | 13 | 14 |
+# --------------------------
+# | 15 | 16 | 17 | 18 | 19 |
+# --------------------------
+#
+# When a bigger spaced key is used,
+# it uses the upper left most key value.
+
+# Symbolic Mapping, DE Layout, CBM2, SDL
+
+# note: For some reason SDL does not get keyboard events for "dead keys" at all,
+# so a "nodeadkeys" layout must be used. CAUTION: apparently SDL generates
+# some tables internally at startup - switching the host layout while
+# the emulator is running produces unpredictable results (broken keycodes)
+
+# Commodore cbm2 keyboard matrix:
+#
+# references:
+# http://www.zimmers.net/anonftp/pub/cbm/b/documents/de/keyboard-matrix.gif
+# http://www.zimmers.net/anonftp/pub/cbm/b/documents/keymap-us.gif
+# http://www.zimmers.net/anonftp/pub/cbm/schematics/computers/b/p500-keyboard.txt
+# http://www.floodgap.com/retrobits/ckb/secret/cbm-610-keyboard.jpg
+#
+# Keys starting with 'KP' are on the number pad. Both shifts and shift lock
+# are in parallel at one point in matrix.
+#
+# 0 1 2 3 4 5
+# +--------+--------+--------+--------+--------+--------+
+# 0 | F9 | 9 ( | O | L | ; : | / ? |
+# +--------+--------+--------+--------+--------+--------+
+# 1 | F10 | 0 ) | - | P | [ | ' " |
+# +--------+--------+--------+--------+--------+--------+
+# 2 | c.down | = + |<- pound| ] | return | pi |
+# +--------+--------+--------+--------+--------+--------+
+# 3 | c.up | c.left | c.right|del ins | CBM |########|
+# +--------+--------+--------+--------+--------+--------+
+# 4 |home/clr|KP ? |KP 7 |KP 4 |KP 1 |KP 0 |
+# +--------+--------+--------+--------+--------+--------+
+# 5 |rvs/off |KP CE |KP 8 |KP 5 |KP 2 |KP . |
+# +--------+--------+--------+--------+--------+--------+
+# 6 | graph |KP * |KP 9 |KP 6 |KP 3 |KP 00 |
+# +--------+--------+--------+--------+--------+--------+
+# 7 |run/stop|KP / |KP - |KP + |KP enter|########|
+# +--------+--------+--------+--------+--------+--------+
+# 8 | F1 | escape | TAB |########| Shift | CTRL |
+# +--------+--------+--------+--------+--------+--------+
+# 9 | F2 | 1 ! | Q | A | Z |########|
+# +--------+--------+--------+--------+--------+--------+
+#10 | F3 | 2 @ | W | S | X | C |
+# +--------+--------+--------+--------+--------+--------+
+#11 | F4 | 3 # | E | D | F | V |
+# +--------+--------+--------+--------+--------+--------+
+#12 | F5 | 4 $ | R | T | G | B |
+# +--------+--------+--------+--------+--------+--------+
+#13 | F6 | 5 % | 6 ^ | Y | H | N |
+# +--------+--------+--------+--------+--------+--------+
+#14 | F7 | 7 & | U | J | M | space |
+# +--------+--------+--------+--------+--------+--------+
+#15 | F8 | 8 * | I | K | , < | . > |
+# +--------+--------+--------+--------+--------+--------+
+
+# CBM2 Keyboard layout:
+#
+# F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 down up left right clr rvs graph r/s
+#
+# ESC 1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) - =+ arrow/pound del ? CE * /
+# TAB q w e r t y u i o p [ ] return 7 8 9 -
+# SL a s d f g h j k l ;: '" pi 4 5 6 +
+# LS z x c v b n m ,< .> /? RS CBM 1 2 3
+# CTRL SPACE 0 . 00 enter
+
+!CLEAR
+!LSHIFT 8 4
+!RSHIFT 8 4
+!VSHIFT RSHIFT
+!SHIFTL RSHIFT
+!LCBM 3 4
+!VCBM LCBM
+!LCTRL 8 5
+!VCTRL LCTRL
+
+27 8 1 8 /* ESC -> ESC */
+
+49 9 1 8 /* 1 -> 1 */
+50 10 1 0x20 /* 2 -> 2 */
+50 1 5 0x80 /* shift 2 -> " */
+51 11 1 8 /* 3 -> 3 */
+52 12 1 8 /* 4 -> 4 */
+53 13 1 8 /* 5 -> 5 */
+54 13 2 0x20 /* 6 -> 6 */
+54 14 1 0x81 /* shift 6 -> & shift+7 */
+55 14 1 0x20 /* 7 -> 7 */
+55 0 5 0x90 /* shift 7 -> / */
+56 15 1 0x20 /* 8 -> 8 */
+56 0 1 0x80 /* shift 8 -> ( shift+9 */
+57 0 1 0x20 /* 9 -> 9 */
+57 1 1 0x80 /* shift 9 -> ) shift+0 */
+48 1 1 0x20 /* 0 -> 0 */
+48 2 1 0x90 /* shift 0 -> = */
+
+223 4 1 0x00b0 /* shift ? -> ? */
+223 4 1 0x0201 /* ctrl ? -> ctrl+ */
+
+180 2 2 8 /* ´ ` -> pound */
+
+45 1 2 0x20 /* Minus -> Minus */
+45 2 2 0x90 /* shift+Minus -> left arrow */
+
+306 8 5 0x4008 /* Left Ctrl -> CTRL */
+305 3 4 0x2008 /* Right Ctrl -> CBM */
+
+304 8 4 4 /* Left Shift -> Shift */
+301 8 4 64 /* Caps Lock -> Shift Lock */
+303 8 4 4 /* Right Shift -> Shift */
+
+32 14 5 8 /* Space -> Space */
+8 3 3 8 /* Backspace -> Del */
+9 8 2 8 /* TAB -> TAB */
+13 2 4 8 /* Return -> Return */
+
+44 15 4 0x20 /* , -> , */
+44 0 4 0x90 /* shift , -> ; */
+
+46 15 5 0x20 /* . -> . */
+46 0 4 0x420 /* ctrl . -> . */
+46 0 4 0x80 /* shift . -> : */
+
+#47 0 5 8 /* / -> / */
+
+60 15 4 0x021 /* < -> ,+shift */
+60 15 5 0x080 /* shift > -> .+shift */
+
+43 2 1 0x21 /* + -> Plus */
+43 15 1 0x80 /* shift++ -> * */
+
+252 10 1 1 /* ue -> @ */
+246 1 4 8 /* oe -> [ */
+228 2 3 8 /* ae -> ] */
+
+35 11 1 33 /* # -> 3+shift */
+35 1 5 0x420 /* ctrl # -> '+ctrl */
+35 1 5 0x90 /* ' -> 7+shift */
+
+94 13 2 0x021 /* ^ -> shift+6 (arrow up) */
+94 2 5 0x420 /* ctrl ^ -> pi */
+94 2 5 0x8b0 /* shift ^ -> pi */
+
+113 9 2 0x28 /* Q -> Q */
+113 10 1 0x201 /* altgr Q -> @ */
+
+119 10 2 8 /* W -> W */
+101 11 2 8 /* E -> E */
+114 12 2 8 /* R -> R */
+116 12 3 8 /* T -> T */
+121 13 3 8 /* Y -> Y */
+117 14 2 8 /* U -> U */
+105 15 2 8 /* I -> I */
+111 0 2 8 /* O -> O */
+112 1 3 8 /* P -> P */
+97 9 3 8 /* A -> A */
+115 10 3 8 /* S -> S */
+100 11 3 8 /* D -> D */
+102 11 4 8 /* F -> F */
+103 12 4 8 /* G -> G */
+104 13 4 8 /* H -> H */
+106 14 3 8 /* J -> J */
+107 15 3 8 /* K -> K */
+108 0 3 8 /* L -> L */
+122 9 4 8 /* Z -> Z */
+120 10 4 8 /* X -> X */
+99 10 5 8 /* C -> C */
+118 11 5 8 /* V -> V */
+98 12 5 8 /* B -> B */
+110 13 5 8 /* N -> N */
+109 14 4 8 /* M -> M */
+
+
+282 8 0 8 /* F1 -> F1 */
+283 9 0 8 /* F2 -> F2 */
+284 10 0 8 /* F3 -> F3 */
+285 11 0 8 /* F4 -> F4 */
+286 12 0 8 /* F5 -> F5 */
+287 13 0 8 /* F6 -> F6 */
+288 14 0 8 /* F7 -> F7 */
+289 15 0 8 /* F8 -> F8 */
+290 0 0 8 /* F9 -> F9 */
+291 1 0 8 /* F10 -> F10 */
+
+#292 1 0 8 /* F11 -> (unused) */
+#293 1 0 8 /* F12 -> run/stop */
+
+273 3 0 8 /* Up -> CRSR UP */
+276 3 1 8 /* Left -> CRSR LEFT */
+275 3 2 8 /* Right -> CRSR RIGHT */
+274 2 0 8 /* Down -> CRSR DOWN */
+
+277 6 5 8 /* Ins -> KP 00 */
+127 5 1 8 /* Del -> KP CE */
+278 4 0 8 /* Home -> CLR/HOME */
+279 5 0 8 /* End -> Rev/Off */
+280 7 0 8 /* PgUp -> Run/Stop */
+281 6 0 8 /* PgDown -> Norm/Graph */
+
+271 7 4 8 /* Numpad Enter -> Numpad Enter */
+267 7 1 8 /* Numpad / -> Numpad / */
+268 6 1 8 /* Numpad * -> Numpad * */
+263 4 2 8 /* Numpad 7 -> Numpad 7 */
+264 5 2 8 /* Numpad 8 -> Numpad 8 */
+265 6 2 8 /* Numpad 9 -> Numpad 9 */
+269 7 2 8 /* Numpad - -> Numpad - */
+260 4 3 8 /* Numpad 4 -> Numpad 4 */
+261 5 3 8 /* Numpad 5 -> Numpad 5 */
+262 6 3 8 /* Numpad 6 -> Numpad 6 */
+270 7 3 8 /* Numpad + -> Numpad + */
+257 4 4 8 /* Numpad 1 -> Numpad 1 */
+258 5 4 8 /* Numpad 2 -> Numpad 2 */
+259 6 4 8 /* Numpad 3 -> Numpad 3 */
+256 4 5 8 /* Numpad 0 -> Numpad 0 */
+266 5 5 8 /* Numpad . -> Numpad . */
Modified: trunk/vice/doc/Makefile.am
===================================================================
--- trunk/vice/doc/Makefile.am 2025-03-31 07:56:10 UTC (rev 45613)
+++ trunk/vice/doc/Makefile.am 2025-03-31 16:34:58 UTC (rev 45614)
@@ -6,6 +6,7 @@
Documentation-Howto.txt \
Doxygen-Howto.txt \
iec-bus.txt \
+ joystick.md \
Release-Howto.txt \
vice.texi \
gpl.texi
Copied: trunk/vice/doc/joystick.md (from rev 45613, branches/compyx/joymap-001/vice/doc/joystick.md)
===================================================================
--- trunk/vice/doc/joystick.md (rev 0)
+++ trunk/vice/doc/joystick.md 2025-03-31 16:34:58 UTC (rev 45614)
@@ -0,0 +1,269 @@
+# VICE Joystick API
+
+> To get a nicely formatted HTML version of this document, including syntax
+> highlighting, use:
+>
+> `pandoc -s -t html -f gfm joystick.md > joystick.html`
+
+
+## Preface
+
+This document describes the updated joystick API, which currently is a **work in
+progress**. All information herein is subject to change while the joystick code
+is being worked on. The inner workings of the actual emulation of the I/O system
+will not be described, just the translation of host device input to emulated
+joystick device, so no actual CIA/VIA emulation.
+
+
+## Overview of the joystick system in VICE
+
+The joystick system in VICE is split into two parts: **common code** and
+**driver code**. The driver code is specific to an OS/UI, while the common code,
+as the name implies, is used for every OS/UI.
+
+### Common code
+
+The common code (in `src/joyport/`) is responsible for interpreting data from
+the drivers and passing that to the emulation, as well as handling mapping and
+calibration of host inputs to emulated inputs. It is also responsible for
+providing the UI with information on host and emulated devices, and at a later
+point, passing host input to the UI for mapping and calibration dialogs.
+
+### Driver code
+
+The driver code is responsible for reading data from a host device and passing
+that back to the common code, as well as providing the common code with a list
+of available host devices and their properties.
+
+
+## Changes in the separation of driver and common code
+
+I've tried to keep the code required to implement a driver as small as possible,
+moving a number of responsibilities from the drivers to the common code.
+
+* The old code would let the driver interpret raw axis and button values and
+ send that back to the emulation (during the `poll()` callback). The drivers
+ now simply pass the raw values to the common code, and the common code
+ interprets those values with the help of the information on the host devices
+ provided by the driver (while also doing calibration).
+
+* A driver no longer needs to concern itself with ordering inputs, the common
+ code handles that.
+
+* Every input now has a unique *code*, which can be an event code (like with
+ Linux' evdev), a simple index of the input (as in SDL) or a HID usage code
+ (as on FreeBSD/NetBSD). The API provides drivers with methods of looking up
+ axis, button and hat objects through their respective code.
+
+* Event handlers in the common code now refer to inputs by instance, not index.
+ So for an axis event a driver would call `joy_axis_event()` with a host device
+ instance, axis instance and raw axis value.
+
+
+**TODO**: Proper (simple) description of `joystick_device_t` and its members
+ `joystick_axis_t`, `joystick_button_t` and `joystick_hat_t`.
+
+**TODO**: Explain ownership of objects (container assumes ownership of its
+ elements and is responsible for freeing them after use, etc).
+
+
+## Implementing a driver
+
+Implementing a driver should be fairly straightforward. A driver registers
+itself with the joystick system and adds host devices it has detected.
+
+During joystick system initialization an arch-specific initialization function
+is called (and expected to be implemented by the driver), where the driver
+registers itself and adds host devices:
+
+```C
+void joystick_arch_init(void)
+```
+
+The function to register the driver is:
+
+```C
+void joystick_driver_register(const joystick_driver_t *driver)
+```
+
+Where `joystick_driver_t` is defined as:
+```C
+typedef struct joystick_driver_s {
+ /** \brief Open host device for use */
+ bool (*open) (joystick_device_t *);
+
+ /** \brief Poll host device */
+ void (*poll) (joystick_device_t *);
+
+ /** \brief Close host device */
+ void (*close) (joystick_device_t *);
+
+ /** \brief Optional method to free arch-specific device data */
+ void (*priv_free)(void *);
+
+ /** \brief Function to call after registering a device
+ *
+ * This function is called after #joystick_device_register has processed
+ * its argument. It can be used to customize mappings or calibration if so
+ * required.
+ */
+ void (*customize)(joystick_device_t *);
+
+} joystick_driver_t;
+```
+
+> Currently (re)opening a device hasn't been implemented yet, so the `open()`
+> method can be ignored, for now.
+
+### Driver methods
+
+The `poll()` method is called by the emulation at the end of *every emulated
+scanline*, and is expected to process any pending event data and pass that
+along to `joy_axis_event()`, `joy_button_event()` or `joy_hat_event()`.
+
+The `close()` method should close the host device (e.g. close file descriptor)
+and put the device in a proper state for opening again. It should **not** free
+its private data in the `priv` member of the `joystick_device_t`, that is done
+in the `priv_free()` method, called by the joystick system on shutdown.
+It should also **not** free the joystick device instance, that again is done by
+the joystick system.
+
+The `priv_free()` method (if used) is, as mentioned above, called on emulator
+shutdown (or once we implement plug-n-pray, on device unplugging), and can be
+used to free any arch-specific resources that cannot be contained in the
+`joystick_device_t` instance or its members.
+> For example: the DirectInput driver for Windows stores a `GUID` and an
+> `LPDIRECTINPUTDEVICE8` instance in `priv`.
+
+The `customize()` method can be used to customize the default mapping and
+calibration applied by the joystick system when `joystick_device_register()` is
+called.
+
+
+### Example of driver implementation
+
+The basic structure of a driver is the following:
+
+```C
+
+/* Some arch-specific data of a device (obvious pseudo code) */
+typedef struct foo_priv_s {
+ FOO_DEVICE *foodev;
+} foo_priv_t;
+
+
+/* Declaration of driver methods */
+static joystick_driver_t foo_driver = {
+ .poll = foo_poll,
+ .close = foo_close
+ .priv_free = foo_priv_free
+};
+
+
+/*
+ * Called after the joystick system has initialized during emulator boot
+ */
+void joystick_arch_init(void)
+{
+ /* Arch-specific initialization, if required */
+ FOO_JOYSTICK_SYSTEM_INIT();
+
+ /* Register driver */
+ joystick_driver_register(&foo_driver);
+
+ /* Iterate devices and register them with the joystick system */
+ for (int i = 0; i < NUM_HOST_DEVICES; i++) {
+
+ joystick_device_t *joydev = joystick_device_new();
+
+ FOO_DEVICE *foodev = OPEN_FOO_DEVICE(i);
+
+ joystick_device_set_name(joydev, foodev->name);
+ joystick_device_set_node(joydev, foodev->...); /* filesystem node of
+ device, GUID string,
+ whatever */
+ joydev->vendor = foodev->vendor_id; /* USB HID vendor ID */
+ joydev->product = foodev->product_id; /* USB HID product ID */
+
+ /* Iterate axes, buttons and perhaps hats of a device and add them */
+ for (int a = 0; a < NUM_AXES(foodev); a++) {
+
+ joystick_axis_t *axis = joystick_axis_new(foodev->AXES[a].name);
+ axis->code = foodev->AXES[a].code; /* some unique event code, can
+ be HID usage, or just index
+ of axis */
+ /* set limits if available */
+ axis->minimum = foodev->AXES[a].min; /* default is INT16_MIN */
+ axis->maximum = foodev->AXES[a].max; /* default is INT16_MAX */
+
+ /* store arch-specific data in `priv` member */
+ foo_priv_t *priv = lib_malloc(sizeof *priv);
+ priv->foodev = foodev;
+ joydev->priv = priv;
+
+ /* add axis to device: device takes ownership */
+ joystick_device_add_axis(joydev, axis);
+ }
+
+ /*
+ * ... Do the same for buttons and hats, if available ...
+ */
+
+ /* Now register the device with the joystick system: the joystick
+ * system takes ownership of the device and its members
+ */
+ joystick_device_register(joydev);
+ }
+}
+
+
+/*
+ * Clean up any arch-specific resources here on emulator shutdown
+ */
+void joystick_arch_shutdown(void)
+{
+ FOO_JOYSTICK_SYSTEM_CLOSE();
+}
+
+
+static void foo_poll(joystick_device_t *joydev)
+{
+ foo_priv_t *priv = joydev->priv;
+
+ while (HAS_EVENT_PENDING(priv->foodev) {
+ FOO_EVENT event = GET_EVENT(priv->foodev);
+
+ switch (event.type) {
+ case FOO_AXIS:
+ joystick_axis_t *axis = joystick_axis_from_code(joydev, event.code);
+ joy_axis_event(axis, event.value);
+ break;
+ case FOO_BUTTON:
+ joystick_button_t *button = joystick_button_from_code(joydev, event.code);
+ joy_button_event(button, event.value);
+ break;
+ }
+ }
+}
+
+
+static void foo_close(joystick_device_t *joydev)
+{
+ foo_priv_t *priv = joydev->priv;
+
+ if (priv->foodev != NULL) {
+ FOO_DEVICE_CLOSE(priv->foodev);
+ priv->foodev = NULL;
+ }
+}
+
+
+static void foo_priv_free(void *priv)
+{
+ foo_priv_t *p = priv;
+
+ FOO_DEVICE_FREE(p->foodev);
+ lib_free(p);
+}
+```
+
Modified: trunk/vice/doc/mkdoxy.sh
===================================================================
--- trunk/vice/doc/mkdoxy.sh 2025-03-31 07:56:10 UTC (rev 45613)
+++ trunk/vice/doc/mkdoxy.sh 2025-03-31 16:34:58 UTC (rev 45614)
@@ -73,6 +73,7 @@
ARCH_GTK3_INPUT=" ../src/arch/gtk3"
ARCH_GTK3_INPUT+=" ../src/arch/gtk3/widgets"
ARCH_GTK3_INPUT+=" ../src/arch/gtk3/widgets/base"
+ARCH_GTK3_INPUT+=" ../src/arch/gtk3/joystickdrv"
ARCH_SDL_INPUT=" ../src/arch/sdl"
@@ -87,6 +88,7 @@
INPUT+=" ../src/hwsiddrv"
INPUT+=" ../src/iecbus"
INPUT+=" ../src/imagecontents"
+INPUT+=" ../src/joyport"
INPUT+=" ../src/monitor"
INPUT+=" ../src/parallel"
INPUT+=" ../src/printerdrv"
Modified: trunk/vice/src/arch/gtk3/joystickdrv/joystick_bsd.c
===================================================================
--- trunk/vice/src/arch/gtk3/joystickdrv/joystick_bsd.c 2025-03-31 07:56:10 UTC (rev 45613)
+++ trunk/vice/src/arch/gtk3/joystickdrv/joystick_bsd.c 2025-03-31 16:34:58 UTC (rev 45614)
@@ -1,8 +1,7 @@
/** \file joystick_bsd.c
- * \brief NetBSD/FreeBSD/DragonFly USB joystick support
+ * \brief NetBSD/FreeBSD USB joystick support
*
- * \author Dieter Baron <di...@ni...>
- * \author Marco van den Heuvel <bla...@ya...>
+ * \author Bas Wassink <b.w...@zi...>
*
* \todo Check if this code also works on OpenBSD.
*/
@@ -30,11 +29,46 @@
#include "vice.h"
-
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <errno.h>
+#include <dirent.h>
#include <fcntl.h>
-#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <unistd.h>
+#include <usbhid.h>
+#ifdef FREEBSD_COMPILE
+/* for hid_* and HUG_* */
+#include <dev/hid/hid.h>
+/* for struct usb_device_info */
+#include <dev/usb/usb_ioctl.h>
+#endif
+
+#ifdef NETBSD_COMPILE
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+#include <dev/hid/hid.h>
+
+/* FreeBSD (9.3) doesn't have the D-Pad defines */
+#ifndef HUG_D_PAD_UP
+#define HUG_D_PAD_UP 0x0090
+#endif
+#ifndef HUG_D_PAD_DOWN
+#define HUG_D_PAD_DOWN 0x0091
+#endif
+#ifndef HUG_D_PAD_RIGHT
+#define HUG_D_PAD_RIGHT 0x0092
+#endif
+#ifndef HUG_D_PAD_LEFT
+#define HUG_D_PAD_LEFT 0x0093
+#endif
+
+#endif /* NETBSD_COMPILE */
+
#include "cmdline.h"
#include "joystick.h"
#include "keyboard.h"
@@ -42,346 +76,588 @@
#include "log.h"
#include "resources.h"
#include "types.h"
+#include "util.h"
+/* Constants used when calling scandir(3) and (re)constructing nodes in the
+ * file system of HID devices
+ */
-#define ITEM_AXIS 0
-#define ITEM_BUTTON 1
-#define ITEM_HAT 2
+/** \brief Root directory of \c uhid* files */
+#define ROOT_NODE "/dev"
-static log_t bsd_joystick_log;
+/** \brief Length of the #ROOT_NODE */
+#define ROOT_NODE_LEN 4
-#ifdef HAVE_USB_H
-#include <usb.h>
-#endif
+/** \brief Prefix of HID files in the \c /dev virtual file system */
+#define NODE_PREFIX "uhid"
-#ifdef DRAGONFLYBSD_COMPILE
-/* sys/param.h contains the __DragonFly_version macro */
-# include <sys/param.h>
-# if __DragonFly_version >= 300200
-/* DragonFly >= 3.2 (USB4BSD stack) */
-# include <bus/u4b/usb.h>
-# include <bus/u4b/usbhid.h>
-# else
-/* DragonFly < 3.2: old USB stack */
-# include <bus/usb/usb.h>
-# include <bus/usb/usbhid.h>
-# endif
-#else
-# ifdef FREEBSD_COMPILE
-# include <sys/ioccom.h>
-# endif
-# include <dev/usb/usb.h>
-# include <dev/usb/usbhid.h>
-#endif
+/** \brief Length of the #NODE_PREIFX */
+#define NODE_PREFIX_LEN 4
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(HAVE_USBHID_H)
-#include <usbhid.h>
-#elif defined(HAVE_LIBUSB_H)
-#include <libusb.h>
-#elif defined(HAVE_LIBUSBHID_H)
-#include <libusbhid.h>
-#endif
+/** \brief Driver-specific data
+ */
+typedef struct joy_priv_s {
+ void *buffer; /**< buffer for reading HID data */
+ report_desc_t rep_desc; /**< HID report descriptor */
+ int rep_size; /**< size of \c rep_desc */
+ int rep_id; /**< report ID */
+ int fd; /**< file descriptor of HID device */
+ int *prev_axes; /**< previous raw value of axes */
+ int *prev_buttons; /**< previous raw value of buttons */
+ int *prev_hats; /**< previous raw value of hats */
+} joy_priv_t;
-#define MAX_DEV 16 /* number of uhid devices to try (NetBSD 9.3 has 16
- /dev/uhid* nodes) */
+/* Forward declarations */
+static bool bsd_joy_open (joystick_device_t *joydev);
+static void bsd_joy_poll (joystick_device_t *joydev);
+static void bsd_joy_close(joystick_device_t *joydev);
+static void joy_priv_free(void *priv);
-/*
- * This hat map was created from values observed on NetBSD 9.2
- * with an analog joystick "ADDISON TECHNOLOGY" that also has a hat switch.
- * uhidev1 at uhub1 port 6 configuration 1 interface 0
- * uhidev1: vendor 0907 (0x907) product 0523 (0x523), rev 1.00/1.00, addr 40, iclass 3/0
- * uhid0 at uhidev1: input=3, output=0, feature=0
+
+/** \brief Log for BSD joystick driver */
+static log_t bsd_joy_log;
+
+/** \brief BSD joystick driver declaration */
+static joystick_driver_t driver = {
+ .open = bsd_joy_open,
+ .poll = bsd_joy_poll,
+ .close = bsd_joy_close,
+ .priv_free = joy_priv_free
+};
+
+
+/** \brief Allocate new private data object
*
- * Only 0 and the odd values (horizontal and vertical) were observed
- * but let's leave the diagonals in too, just in case.
+ * Allocate and initialize private data object instance.
*
- * There are apparently hats with 0 for neutral and 1 for up, and some
- * with 8 for neutral and 0 for up. The other values are off by 1.
- * We try to autodetect, by seeing which of 0 or 8 occurs first.
- * We report no direction until one of those is seen.
+ * \return new data object
*/
-#define MAX_HAT_MAP_INDEX 8
-static const uint8_t hat_map[MAX_HAT_MAP_INDEX + 2] = {
- 0, /* 0 */
- JOYSTICK_DIRECTION_UP, /* 1 */
- JOYSTICK_DIRECTION_UP | JOYSTICK_DIRECTION_RIGHT, /* 2 */
- JOYSTICK_DIRECTION_RIGHT, /* 3 */
- JOYSTICK_DIRECTION_RIGHT | JOYSTICK_DIRECTION_DOWN, /* 4 */
- JOYSTICK_DIRECTION_DOWN, /* 5 */
- JOYSTICK_DIRECTION_DOWN | JOYSTICK_DIRECTION_LEFT, /* 6 */
- JOYSTICK_DIRECTION_LEFT, /* 7 */
- JOYSTICK_DIRECTION_LEFT | JOYSTICK_DIRECTION_UP, /* 8 */
- 0, /* 9 */
-};
+static joy_priv_t *joy_priv_new(void)
+{
+ joy_priv_t *priv = lib_malloc(sizeof *priv);
-struct usb_joy_item {
- struct hid_item item;
- struct usb_joy_item *next;
+ priv->buffer = NULL;
+ priv->rep_desc = NULL;
+ priv->rep_size = 0;
+ priv->fd = -1;
+ priv->rep_id = 0;
+ priv->prev_axes = NULL;
+ priv->prev_buttons = NULL;
+ priv->prev_hats = NULL;
+ return priv;
+}
- int type;
- int min_val;
- int max_val;
- int ordinal_number;
-};
+/** \brief Free private data instance
+ *
+ * Free private data object and its resources.
+ * Closes file descriptor, cleans up HID report descriptor and free HID buffer.
+ *
+ * \param[in] priv private data object
+ */
+static void joy_priv_free(void *priv)
+{
+ joy_priv_t *p = priv;
-typedef struct bsd_joystick_priv_s {
- struct usb_joy_item *usb_joy_item;
- char *usb_joy_buf;
- int usb_joy_fd;
- int usb_joy_size;
-} bsd_joystick_priv_t;
+ if (p != NULL) {
+ if (p->fd >= 0) {
+ close(p->fd);
+ }
+ lib_free(p->buffer);
+ if (p->rep_desc != NULL) {
+ hid_dispose_report_desc(p->rep_desc);
+ }
+ lib_free(p->prev_axes);
+ lib_free(p->prev_buttons);
+ lib_free(p->prev_hats);
+ lib_free(p);
+ }
+}
-static void usb_joy_add_item(struct usb_joy_item **item, struct hid_item *hi, int orval, int type)
+/** \brief Open joystick device for polling
+ *
+ * \param[in] joydev joystick device
+ */
+static bool bsd_joy_open (joystick_device_t *joydev)
{
- struct usb_joy_item *it;
- int w;
+ return true; /* NOP */
+}
- it = lib_malloc(sizeof *it);
- it->next = *item;
- *item = it;
+/** \brief Poll joystick device
+ *
+ * \param[in] joydev joystick device
+ */
+static void bsd_joy_poll(joystick_device_t *joydev)
+{
+ joy_priv_t *priv = joydev->priv;
- memcpy(&it->item, hi, sizeof(*hi));
- it->type = type;
- it->ordinal_number = orval;
+ if (priv != NULL && priv->fd >= 0) {
+ ssize_t rsize;
- switch (type) {
- case ITEM_AXIS:
- w = (hi->logical_maximum - hi->logical_minimum) / 3;
- it->min_val = hi->logical_minimum + w;
- it->max_val = hi->logical_maximum - w;
- break;
- case ITEM_BUTTON:
- it->min_val = hi->logical_minimum;
- it->max_val = hi->logical_maximum - 1;
- break;
- case ITEM_HAT:
- it->min_val = -1; /* mapping not autodetected yet */
- break;
+ while ((rsize = read(priv->fd, priv->buffer, (size_t)priv->rep_size)) == priv->rep_size) {
+ struct hid_data *data;
+ struct hid_item item;
+
+ data = hid_start_parse(priv->rep_desc, 1 << hid_input, priv->rep_id);
+ if (data == NULL) {
+ return;
+ }
+
+ while (hid_get_item(data, &item) > 0) {
+ joystick_axis_t *axis;
+ joystick_button_t *button;
+ joystick_hat_t *hat;
+ int value = hid_get_data(priv->buffer, &item);
+ int usage = HID_USAGE(item.usage);
+ unsigned int page = HID_PAGE(item.usage);
+ int prev;
+
+ switch (page) {
+ case HUP_GENERIC_DESKTOP:
+ switch (usage) {
+ case HUG_X: /* fall through */
+ case HUG_Y: /* fall through */
+ case HUG_Z: /* fall through */
+ case HUG_RX: /* fall through */
+ case HUG_RY: /* fall through */
+ case HUG_RZ: /* fall through */
+ case HUG_SLIDER:
+ /* axis */
+ axis = joystick_axis_from_code(joydev, (uint32_t)usage);
+ if (axis != NULL) {
+ /* XXX: On my Logitech F710 the Y axis is inverted by
+ * FreeBSD, NetBSD just reports insane values.
+ * So for FreeBSD we'd need calibration to be
+ * implemented for the F710 to work.
+ */
+ prev = priv->prev_axes[axis->index];
+ if (value != prev) {
+ priv->prev_axes[axis->index] = value;
+ joy_axis_event(axis, (int32_t)value);
+ }
+ }
+ break;
+
+ case HUG_HAT_SWITCH:
+ /* hat */
+ hat = joystick_hat_from_code(joydev, (uint32_t)usage);
+ if (hat != NULL) {
+ prev = priv->prev_hats[hat->index];
+ if (prev != value) {
+ priv->prev_hats[hat->index] = value;
+ joy_hat_event(hat, (int32_t)value);
+ }
+ }
+ break;
+
+ case HUG_D_PAD_UP: /* fall through */
+ case HUG_D_PAD_DOWN: /* fall through */
+ case HUG_D_PAD_LEFT: /* fall through */
+ case HUG_D_PAD_RIGHT:
+ /* D-Pad is mapped as buttons */
+ button = joystick_button_from_code(joydev, (uint32_t)usage);
+ if (button != NULL) {
+ prev = priv->prev_buttons[button->index];
+ if (prev != value) {
+ priv->prev_buttons[button->index] = value;
+ joy_button_event(button, (int32_t)value);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case HUP_BUTTON:
+ /* button event */
+ button = joystick_button_from_code(joydev, (uint32_t)usage);
+ if (button != NULL) {
+ prev = priv->prev_buttons[button->index];
+ if (prev != value) {
+ priv->prev_buttons[button->index] = value;
+ joy_button_event(button, (int32_t)value);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ hid_end_parse(data);
+ }
+
+ if (rsize != -1 && errno != EAGAIN) {
+ log_warning(bsd_joy_log,
+ "weird report size: %zd: %s",
+ rsize, strerror(errno));
+ }
}
}
-static void usb_free_item(struct usb_joy_item **item)
+/** \brief Close joystick device
+ *
+ * \param[in] joydev joystick device
+ */
+static void bsd_joy_close(joystick_device_t *joydev)
{
- struct usb_joy_item *it, *it2;
-
- it=*item;
- while (it) {
- it2 = it;
- it = it->next;
- lib_free(it2);
+ if (joydev != NULL && joydev->priv != NULL) {
+ joy_priv_free(joydev->priv);
+ joydev->priv = NULL;
}
- *item = NULL;
}
-static void usb_joystick_close(void* priv)
+
+/** \brief scandir select callback
+ *
+ * Check if name matches "uhid?*".
+ *
+ * \param[in] de directory entry
+ *
+ * \return non-0 when matching "uhid?*"
+ */
+static int sd_select(const struct dirent *de)
{
- bsd_joystick_priv_t *joypriv = priv;
- close(joypriv->usb_joy_fd);
- usb_free_item(&joypriv->usb_joy_item);
- lib_free(priv);
+ const char *name = de->d_name;
+
+ return ((strlen(name) >= NODE_PREFIX_LEN + 1u) &&
+ (strncmp(NODE_PREFIX, name, NODE_PREFIX_LEN) == 0));
}
-static void usb_joystick(int jp, void* priv)
+/** \brief Get full path of UHID device node
+ *
+ * \param[in] node node in /dev/
+ *
+ * \return full path to \a node
+ * \note free with \c lib_free() after use
+ */
+static char *full_node_path(const char *node)
{
- int val;
- ssize_t ret;
- struct usb_joy_item *it;
- bsd_joystick_priv_t *joypriv = priv;
+ size_t nlen = strlen(node);
+ size_t plen = ROOT_NODE_LEN + 1u + nlen + 1u;
+ char *path = lib_malloc(plen);
- val = 0;
- while ((ret = read(joypriv->usb_joy_fd, joypriv->usb_joy_buf, joypriv->usb_joy_size)) == joypriv->usb_joy_size) {
- val = 1;
+ memcpy(path, ROOT_NODE, ROOT_NODE_LEN);
+ path[ROOT_NODE_LEN] = '/';
+ memcpy(path + ROOT_NODE_LEN + 1, node, nlen + 1u);
+ return path;
+}
+
+/** \brief Open device for HID usage
+ *
+ * Open \c node and get associated HID data from it for scanning/polling.
+ * This function opens the device and allocates a buffer for HID reports, gets
+ * the report ID and size and allocates a \c joy_priv_t instance with all that
+ * data.
+ *
+ * \param[in] node path in <tt>/dev/</tt> to the device
+ *
+ * \return new initialized \c joy_priv_t instance or <tt>NULL</tt> on error
+ */
+static joy_priv_t *joy_hid_open(const char *node)
+{
+ joy_priv_t *priv;
+ report_desc_t rep_desc;
+ int rep_id;
+ int rep_size;
+ int fd;
+
+ fd = open(node, O_RDONLY|O_NONBLOCK);
+ if (fd < 0) {
+ /* don't log, (Net)BSD allocates a lot of nodes in /dev that aren't
+ * actually valid */
+ return NULL;
}
- if (ret != -1 && errno != EAGAIN) {
- /* XXX */
- log_warning(bsd_joystick_log, "strange read return: %zd/%d", ret, errno);
- return;
+
+ /* get report ID if possible, else asume 0 */
+#ifdef USB_GET_REPORT_ID
+ if (ioctl(fd, USB_GET_REPORT_ID, &rep_id) < 0) {
+ log_warning(bsd_joy_log, "USB_GET_REPORT_ID failed.");
+ close(fd);
+ return NULL;
}
- if (!val) {
- return;
+#else
+ rep_id = 0;
+#endif
+
+ /* get report description */
+ rep_desc = hid_get_report_desc(fd);
+ if (rep_desc == NULL) {
+ log_error(bsd_joy_log,
+ "failed to get HID report for %s: %s",
+ node, strerror(errno));
+ close(fd);
+ return NULL;
}
- for (it = joypriv->usb_joy_item; it; it = it->next) {
- val = hid_get_data(joypriv->usb_joy_buf, &it->item);
- if (it->type == ITEM_HAT) {
- if (val >= 0 && val <= MAX_HAT_MAP_INDEX) {
- /* Autodect if 0 is neutral, or 8 */
- if (it->min_val < 0) {
- if (val == 0) {
- it->min_val = 0;
- } else if (val == 8) {
- it->min_val = 1;
- } else {
- /* Not yet autodetected */
- }
- /* Report neutral position for now */
- joy_hat_event(jp, it->ordinal_number, 0);
- } else {
- val += it->min_val;
- joy_hat_event(jp, it->ordinal_number, hat_map[val]);
+ /* get report size */
+ rep_size = hid_report_size(rep_desc, hid_input, rep_id);
+ if (rep_size <= 0) {
+ log_error(bsd_joy_log, "invalid report size of %d", rep_size);
+ hid_dispose_report_desc(rep_desc);
+ close(fd);
+ return NULL;
+ }
+
+ /* success: allocate private data object and store what we need for polling
+ * and further querying */
+ priv = joy_priv_new();
+ priv->buffer = lib_malloc((size_t)rep_size);
+ priv->rep_desc = rep_desc;
+ priv->rep_size = rep_size;
+ priv->rep_id = rep_id;
+ priv->fd = fd;
+
+ return priv;
+}
+
+/** \brief Add axis to joystick device
+ *
+ * \param[in] joydev joystick device
+ * \param[in] item HID item with axis information
+ *
+ */
+static void add_joy_axis(joystick_device_t *joydev,
+ const struct hid_item *item)
+{
+ joystick_axis_t *axis;
+
+ axis = joystick_axis_new(hid_usage_in_page(item->usage));
+ axis->code = (uint32_t)HID_USAGE(item->usage);
+ axis->minimum = item->logical_minimum;
+ axis->maximum = item->logical_maximum;
+
+ log_message(bsd_joy_log, "axis %u: %s", axis->code, axis->name);
+ joystick_device_add_axis(joydev, axis);
+}
+
+/** \brief Add button to joystick device
+ *
+ * \param[in] joydev joystick device
+ * \param[in] item HID item with button information
+ */
+static void add_joy_button(joystick_device_t *joydev,
+ const struct hid_item *item)
+{
+ joystick_button_t *button;
+
+ button = joystick_button_new(hid_usage_in_page(item->usage));
+ button->code = (uint32_t)HID_USAGE(item->usage);
+
+ log_message(bsd_joy_log, "button %u: %s", button->code, button->name);
+ joystick_device_add_button(joydev, button);
+}
+
+/** \brief Add hat to joystick device
+ *
+ * \param[in] joydev joystick device
+ * \param[in] item HID item with hat information
+ */
+static void add_joy_hat(joystick_device_t *joydev,
+ const struct hid_item *item)
+{
+ joystick_hat_t *hat;
+
+ hat = joystick_hat_new(hid_usage_in_page(item->usage));
+ hat->code = (uint32_t)HID_USAGE(item->usage);
+
+ log_message(bsd_joy_log, "hat %u: %s", hat->code, hat->name);
+ joystick_device_add_hat(joydev, hat);
+}
+
+/** \brief Scan device for inputs
+ *
+ * Scan \a joydev for axes, buttons and hats and register them with \a joydev.
+ *
+ * \param[in] joydev joystick device
+ *
+ * \return \c true on succes
+ */
+static bool scan_inputs(joystick_device_t *joydev)
+{
+ joy_priv_t *priv;
+ struct hid_data *hdata;
+ struct hid_item hitem;
+
+ priv = joydev->priv;
+ hdata = hid_start_parse(priv->rep_desc, 1 << hid_input, priv->rep_id);
+ if (hdata == NULL) {
+ log_error(bsd_joy_log, "hid_start_parse() failed: %s,", strerror(errno));
+ return false;
+ }
+
+ while (hid_get_item(hdata, &hitem) > 0) {
+ unsigned int page = HID_PAGE (hitem.usage);
+ int usage = HID_USAGE(hitem.usage);
+
+ switch (page) {
+ case HUP_GENERIC_DESKTOP:
+ switch (usage) {
+ case HUG_X: /* fall through */
+ case HUG_Y: /* fall through */
+ case HUG_Z: /* fall through */
+ case HUG_RX: /* fall through */
+ case HUG_RY: /* fall through */
+ case HUG_RZ: /* fall through */
+ case...
[truncated message content] |