Phase 0: scaffold modern RIOJoy solution + plan

Modernization of the legacy vJoy-based RIO cockpit interface for Win10/11,
removing the vJoy dependency in favor of a custom VHF/UMDF HID driver,
rewritten in C#/.NET 8 as a background tray app with per-game profiles.

- Reorganize: legacy C++ -> legacy/, cockpit art -> docs/reference/
- RioJoy.sln: src/RioJoy.Core (lib) + src/RioJoy.Tray (tray app), net8.0-windows x64
- driver/ placeholder for the RioGamepad WDK driver
- docs/PLAN.md (7-phase plan; profiles + serial-yield model)
- docs/PROTOCOL.md (RIO wire format + iRIO input-map reference)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-06-26 12:43:01 -05:00
co-authored by Claude Opus 4.8
commit 39a3dab1fc
54 changed files with 13616 additions and 0 deletions
@@ -0,0 +1,3 @@
; This is the Data to be used with gimp RIO template, copy the first three lines into a data file, install GIMP run gimp script sg-goobie-MFD.scm
( a-00 b-00 b-01 b-02 b-03 b-04 b-05 b-06 b-07 b-08 b-09 b-0A b-0B b-0C b-0D b-0E b-0F b-10 b-11 b-12 b-13 b-14 b-15 b-16 b-17 b-18 b-19 b-1A b-1B b-1C b-1D b-1E b-1F b-20 b-21 b-22 b-23 b-24 b-25 b-26 b-27 b-28 b-29 b-2A b-2B b-2C b-2D b-2E b-2F b-30 b-31 b-32 b-33 b-34 b-35 b-36 b-37 b-38 b-39 b-3A b-3B b-3C b-3D b-3E b-3F b-40 b-41 b-42 b-43 b-44 b-45 b-46 b-47 b-50 b-51 b-52 b-53 b-54 b-55 b-56 b-57 b-58 b-59 b-5A b-5B b-5C b-5D b-5E b-5F b-60 b-61 b-62 b-63 b-64 b-65 b-66 b-67 b-68 b-69 b-6A b-6B b-6C b-6D b-6E b-6F )
( "defalt" "LSDI" "ZOOM" "UNDOCK" "LDS" "BALANCE" "DRIVE" "DEFENCE" "OFFENCE" "LAST AGGESSOR" "SUB TARGET" "NEXT ENEMY" "NEAR ENEMY" "LAST CONTACT" "DOWN CON" "UP CONTACT" "TOP CONTACT" "M U" "M R" "M D" "M L" "MLC" "TAB" "" "" "ENTER" "ALT" "CTRL" "SHIFT" "VL U" "VL D" "" "" ">" "v" "^" "<" "N" "M" "L" "K" "V" "U" "T" "S" "J" "I" "H" "G" "Z" "Y" "X" "W" "R" "Q" "P" "O" "M ^" "M >" "M v" "M <" "ML" "ESC" "MR" "REVERSE" "FIRE/ACCEPT" "H v" "H ^" "H >" "H <" "NEXT PRIMEARY" "NEXT SECOND" "TARGET/BACK" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F" "RIO_0" "RIO_1" "RIO_2" "RIO_3" "RIO_4" "RIO_5" "RIO_6" "RIO_7" "RIO_8" "RIO_9" "RIO_A" "RIO_B" "RIO_C" "RIO_D" "RIO_E" "RIO_F" )
@@ -0,0 +1 @@
https://docs.google.com/spreadsheets/d/1TkWsk0xXA4rPArQvldmQiWhGd77eB3NUm0Q3XpW5cEU/edit?usp=sharing
Binary file not shown.
@@ -0,0 +1,212 @@
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
; This script reads in a data file containing a list of
; RIO button information.
; The data file uses Lisp/Scheme style lists and commenting (comments
; start with a semi-colon and extend to the end of the line).
; The first non-comment line of the data file should be a list containing
; the field names of the RIO button addresses wrapped in parentheses.
; For example:
;
; ; THIS IS A COMMENT AND IGNORED
; ( 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F )
;
; This "header" list should be followed by the LINE containing the
; actual data to be substituted into the template file. The data should
; be text strings and appear in the same order as the fields specified in
; the header list.
;
; ("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "CTRL" "ALT")
;
;
; The currently open image is used as a template with the upper layers having
; names that match the field names. These field layers are used to determine
; the location and size of the text (this layer is otherwise ignored).
; The name text is centered within the bounds of this field template layer.
;
;
(define (script-fu-sg-goobie image
datafilename
save-xcf
save-jpeg
save-png
save-dir
vert-justification
size-handling)
;; Perform a search for the largest font that will fit within
;; the cell.
;
(define (calc-fontsize text font width height)
(let loop ((fontsize 6) ;; minimum possible fontsize
(last-extents nil)
(last-fontsize 3)
(adjust 2)
)
(let ((extents (gimp-text-get-extents-fontname text fontsize PIXELS font)))
(if (or (= last-fontsize fontsize) (equal? extents last-extents))
(max fontsize 6)
(if (or (> (car extents) width) (> (cadr extents) height))
(loop (truncate (* last-fontsize (+ (* (- adjust 1) 0.5) 1)))
last-extents
last-fontsize
(+ (* (- adjust 1) 0.5) 1) )
(loop (truncate (* fontsize adjust))
extents
fontsize
adjust ))))))
(define (create-data-layer image field-name field-data)
(let ((frame-layer
(let loop ((layers (vector->list (cadr (gimp-image-get-layers image)))))
(if (null? layers)
#f
(if (string=? field-name (car (gimp-drawable-get-name (car layers))))
(car layers)
(loop (cdr layers)) )))))
(if frame-layer
(if (= (car (gimp-drawable-is-text-layer frame-layer)) 1)
(let ((x (car (gimp-drawable-offsets frame-layer)))
(y (cadr (gimp-drawable-offsets frame-layer)))
(w (car (gimp-drawable-width frame-layer)))
(h (car (gimp-drawable-height frame-layer)))
(font (car (gimp-text-layer-get-font frame-layer)))
(size (car (gimp-text-layer-get-font-size frame-layer)))
)
(gimp-image-set-active-layer image frame-layer)
(gimp-text-layer-set-text frame-layer field-data)
(let ((extents (gimp-text-get-extents-fontname field-data
size
PIXELS
font )))
(when (and (zero? size-handling)
(or (> (car extents) w)
(> (cadr extents) h) ))
(gimp-text-layer-set-font-size frame-layer (calc-fontsize field-data font w h) PIXELS) )
(case vert-justification
((0) ; center
(gimp-layer-set-offsets frame-layer
x
(+ y (/ (- h (cadr extents)) 2)) ))
((1) ; top
(gimp-layer-set-offsets frame-layer
x
y ))
((2) ; bottom
(gimp-layer-set-offsets frame-layer
x
(- (+ y h) (cadr extents)) )))))
(gimp-message "Field layer is not a text layer")
)
(begin
(gimp-message (string-append "Field layer not found: " field-name)) ))
frame-layer ))
;; ----------------------------------------------------------------------
;; Main processing start here
;
(let* ((inport (open-input-file datafilename))
(field-names (map symbol->string (read inport)))
(filetag (car field-names)) )
(gimp-image-undo-freeze image)
(gimp-context-push)
(let entry-loop ((fields (read inport)))
(unless (eof-object? fields)
(let ((temp-image (car (gimp-image-duplicate image)))
(filename #f) )
(let field-loop ((field-names field-names)
(field-values fields) )
(unless (null? field-values)
(when (string=? (car field-names) filetag)
(set! filename (car field-values)) )
(create-data-layer temp-image (car field-names) (car field-values))
(field-loop (cdr field-names) (cdr field-values)) ))
(if filename
(let ((fullname (string-append save-dir
DIR-SEPARATOR
filename )))
(unless (zero? save-xcf)
(let ((filename (string-append fullname ".xcf")))
(gimp-xcf-save TRUE
temp-image
(car (gimp-image-get-active-layer image))
filename
filename )))
(unless (zero? save-png)
(let ((layer (car (gimp-image-merge-visible-layers temp-image
CLIP-TO-IMAGE )))
(filename (string-append fullname ".png")) )
(file-png-save2 RUN-NONINTERACTIVE
temp-image
layer
filename
filename
FALSE ; interlace
9
FALSE ; bkgd
(car (gimp-drawable-has-alpha layer))
FALSE ; offs
FALSE ; phys
FALSE ; time
TRUE ; comment
FALSE ; svtrans
)))
(unless (zero? save-jpeg)
(let ((layer (car (gimp-image-flatten temp-image)))
(filename (string-append fullname ".jpg")) )
(file-jpeg-save RUN-NONINTERACTIVE
temp-image
layer
filename
filename
0.93
0 ; smoothing
1 ; optimize
1 ; progressive
"" ; comment
0 ; subsmp (0-4)
1 ; baseline
0 ; restart
0 ;dct
))))
(gimp-message "Error encountered") )
; (gimp-image-delete temp-image)
)
(entry-loop (read inport)) ))
(close-input-port inport)
(gimp-context-pop)
(gimp-image-undo-thaw image)
)
)
(script-fu-register "script-fu-sg-goobie"
"Goobie (MFD)..."
"Create MFD image based on template image"
"Frank Galatis"
"Saul Goode"
"June 2012"
"*"
SF-IMAGE "Image" 0
SF-FILENAME "Data file" "example.data"
SF-TOGGLE "Save as XCF" FALSE
SF-TOGGLE "Save as JPEG" TRUE
SF-TOGGLE "Save as PNG" FALSE
SF-DIRNAME "Save directory" ""
SF-OPTION "Vertical justification" '("Center" "Top" "Bottom")
SF-OPTION "Font sizing (if too large)" '("Fit" "Crop" "Overflow")
)
(script-fu-menu-register "script-fu-sg-goobie"
"<Image>/File"
)