Profile
Back to NewsBack
GitHub Trending 39 min
Reader Mode
muchimi/JoystickGremlinEx: Modified version of Joystick Gremlin to add features I wanted to have but were difficult to do as just a plugin, plus I wanted to run this as 64 bit and on a more current version of Python/QT.

muchimi/JoystickGremlinEx: Modified version of Joystick Gremlin to add features I wanted to have but were difficult to do as just a plugin, plus I wanted to run this as 64 bit and on a more current version of Python/QT.

20 hours ago

GremlinEx

GremlinEx (GEX) is a universal controller integrator: it allows you to take input from multiple hardware devices from different manufacturers connected to a local machine, or a remote machine, such as joysticks and HID controllers, OSC (Open Sound Control), MIDI, Keyboard and mouse inputs and map them to virtual outputs like VJOY, or keyboard or mouse output, convert text to speech and play sounds. It can send output to a game or another process. With OSC support, GremlinEx can receive input from custom designed glass (touch screen) surfaces, and supports two way communication to any device supported by BitFocus Companion such as the Elgato Streamdeck. This communication is two-way so GremlinEx can also send data to a glass surface or an external hardware panel. GremlinEx can be expanded using custom plugins written in Python. !gremlinex !gremlinex viewer

Documentation

The documentation for GremlinEx has recently moved to GitHub Pages: Documentation

Discord

Please visit the Discord server for discussion, tips and development information.

Support and donations

GremlinEx is a passion project dedicated to solving complex controller mapping challenges across a wide range of hardware from different manufacturers. It also introduces powerful features that are unavailable in many other applications, including commercial alternatives. Developing and maintaining GremlinEx requires a significant investment of time, research, and ongoing development. As gaming platforms, hardware, and software continue to evolve, GremlinEx is continually updated, modernized, and improved based on both emerging technologies and the invaluable feedback and ideas shared by its community. If GremlinEx has been helpful to you, please consider supporting its continued development with a donation. Every contribution, regardless of size, is sincerely appreciated. Your support helps sustain the countless hours spent developing, maintaining, and improving the project. There are two ways you can safely and securely contribute to the project:
  • via GitHub's sponsorship program.
  • via a Paypal direct donation
The links are the top of this project page, or on the right side under sponsorships. Again, thank you for your shared passion and for your generosity and support. It means a lot, and sponsors make a huge difference.

Test versions

The most current test releases will contain the latest bug fixes, features and optimizations. Not all test releases are stable which is why they are not in the release channel, and many are. Please make a backup of your profiles and enable the versioning option to keep files separate by version just in case, but there is about a year's worth of key updates since the last official release all in the test channel including several stable versions. The test versions are available here: https://github.com/muchimi/JoystickGremlinEx/releases/tag/test

Change log

(m77T72A)

  • Change: UI: Execute widget relabeled to "Execute on release" instead of "Release on press".

(m77T72)

  • New: UI: Profile visualizer: (experimental) new option to display the profile as a node graph in a window. Additional features may be added later, it's a bit bare bones at the moment but shows an interactive graphical representation of the profile in the UI where you can zoom in and move the canvas around to explore the profile setup in a graphical form.
  • Change: auto-start OSC server if the OSC device is displayed (OSC module enabled).
  • Change: minor rework of log messages.

(m77T71)

  • Fix: State Container : incorrect indexing in module caused a blank entry in XML and exception on load.

(m77T70)

  • Change: Map to State: Added a no-op option for the primary state so the secondary global functions can be used without changing the primary state.
  • Change: Map to State: Added a category filter for the other state mode to filter the action to states in the same category as the primary state, or all other states regardless of category.
  • Fix: Input Viewer: Keyboard will scroll horizontally if it does not fit because the window is too narrow. This will prevent keyboard visual layout issues with some resolutions as keys could overlap.
  • Fix: Map To State: UI element callback change in T69 has a missed parameter swap causing an exception.

(m77T69)

  • New: Map to state: Other state action modes. When triggering a state, the action can also optionally globally touch all other states, such as setting all on, off or use a boolean comparison to determine the new value. Default is do nothing.
  • Change: new dependency library: networkx (included in package)
  • Change: new dependency library: pygraphviz (included in package)
  • Fix: UI: continued hardening to guard against QT behavior and desync.
  • Fix: Map to Keyboard/Ex: some keys could be duplicated on profile read
  • Fix: VJOY: ensure vjoy calls are on the primary process (UI) thread to avoid potential boundary race conditions when interacting with the C++ layer. This is specifically to handle process locking boundaries.

(m77T68)

  • New: Map to State pulse mode: the pulse mode defaults to an option that inverts the value of the state while pulsed, rather than turning it on and off. This was always the intended behavior and should not change behavior provided that the state is set to a known value. This would only require a profile update if you use the pulse feature to turn a state off using pulse. This is usually not the case. This can be turned off via the new option in pulse mode. Defaults to enabled.
  • Change: Allow optional module core plugins to load even if disabled so profiles loaded that use the disabled modules can recognize the fact the profile uses disabled modules. This is an interim solution for now as the long term goal is to not load modules until referenced by a profile (if disabled) and prompt the end-user to load these modules (change options/preferences automatically) if needed.
  • Fix: UI: hardening around life cycle object management of Python references to QT objects causing C++ memory desync that appeared in T64 and refresh changes, some of it is timing related, some of it is behavior related.
  • Fix: UI: revise lambdas to avoid a potential memory leak due to a Python behavior (late binding) in lambda expressions used to hook QT events. The behavior could cause Python to retain or keep on adding references in memory to QT objects that should not be kept. This is due to how QT and Python manage their own objects.
  • Fix: UI: workaround for a QT tab header bug around style and painting that could cause the device tabs to not display or redraw correctly.
  • Fix: UI: device filter user selections can be ignored in some situations.
  • Fix: API (State): added state via map to state action did not refresh list of states on state device.

(m77T67)

  • New (experimental): overlay web browser support (courtesy Lolo350): enables an overlay to be displayed via a web browser on a networked device (such as a tablet or phone). Supports touch input/interactions, HTTP frame fallback, and a GEX Offline screen when the profile is deactivated. This feature aims at enabling touch-screen interaction from any device, not just a Windows device, as an interactive touch surface to send inputs to GEX.
  • Changes: Overlay module (courtesy Lolo350)
- Add a dual-bind 2-position switch (toggle) with latching Off/On behavior, plus multiline label/caption/axis-label fields (Shift+Enter for a new line) - Improve overlay binding UI, profile sidecar persistence, windowed chroma paint, and related inspector/control-panel polish
  • Fix: UI: Voice Device: Clear deletes voices (was deleting incorrect inputs)
  • Fix: UI (Core): resolve an issue with ensuring input changes are synchronized with the mapping when an input is deleted or unselected.
  • Fix: Voice Device: delete entry does not delete command from voice engine until profile reload.

(m77T66)

  • Fix: UI: added more QT desync guardrails when UI needs to refresh.
  • Fix: UI (Options): removed duplicate AFCS entry in the modules tab.

(m77T65)

  • Change: Voice Device: display a message if no states are defined and state latching is selected.
  • Fix: Voice Device: settings: handle blank keyboard or state latching.
  • Fix: Voice Device: settings: load state latching correctly.
  • Fix: Voice Device: settings: exception on some input types when selecting a PTT latch input.
  • Fix: API: do not attempt to persist keyboard entries that are not attached to a key (or keys).
  • Fix: UI: Joystick selector may update the input, not the selected device.
  • Fix: UI: ActionSetView: added two QT memory manager guardrails
  • Fix: API: Keyboard: key name does not update on key objects
  • Fix: API: optional modules enabled by default when they should be disabled if they should be enabled by the user (this is to reduce default overhead/system for vanilla installs).
  • Fix: UI: input widget cache creation and diagnostics code around creation failures.

(m77T64B)

  • Fix: keyboard input - allow to save empty (blank) items.

(m77T64A)

  • Fix: options dialog streamdeck reference invalid.

(m77T64)

  • New: Voice Device: option to play an audio cue on voice match
  • New: Voice Device: AI model download will show a dialog while the download is in progress (models are only downloaded if they don't exist in the local GEX files).
  • Change: Overlay: Overlay editor polish (control panel, keybinds, groups, shadows, inspector/selection performance), Stream Deck designer tweaks, and AFCS enable toggle. (courtesy Lolo350)
  • Change: Voice Device: AI model check occurs on profile start and/or when voice recognition is started to avoid a download if voice is not used/enabled, as well as reducing GEX startup time if a model has to be downloaded.
  • Change: Voice Device: voice verbose mode no longer forced on (was enabled for testing purposes).
  • Fix: Voice Device: fix typo in checkbox widget causing an exception
  • Fix: Voice Device: input description shows verbose mapping details.
  • Fix: API: search file collision detection.
  • Fix: various fixes in Overlay, Streamdeck and AFCS and core API stability.
  • Fix: Input Viewer: exception on UI refresh if a widget has to be deleted.
  • Fix: Input Viewer: QT exception on keyboard visualizer if it's in the process of being deleted.

(m77T63)

  • Fix: UI: Delay widget stores data in seconds or milliseconds as needed.
  • Fix: DoubleTap Container: fix double tap.
  • Fix: DoubleTap Container: enable chain mode options.
  • Fix: DoubleTap Container: do not reset container on mode change (this could prevent container logic such as release events from executing).
  • Fix: TempoEx Container: do not reset container on mode change (this could prevent container logic such as release events from executing).
  • Fix: API: implement extend method for view models for calls using the older API.
  • Fix: UI: fixed an issue with actions not visible in the UI after a refresh.
  • Fix: API: added older extended scan codes encodings to the list of valid keys (right shift, right control) to support older keyboard event data so they are recognized when triggered.

(m77T62B)

  • Fix: AFCS device tab not checking to see if AFCS module is enabled or not.
  • Fix: AFCS missing module option in modules tab (global options)
  • Fix: VJoy Remap: profile start sync input id collision

(m77T62A)

  • New: API (Voice): added a two tone beep to signal voice recognition is enabled/disabled. This can be turned off in the voice settings options.
  • Change: Control Action: added voice management commands to enable/disable/toggle voice recognition from any input (on top of the default input setup in voice settings).

(m77T62)

  • Change: UI: Add mapping header to clarify what is being mapped.
  • Fix: Package (Voice): Packaging utility failed to detect and include library dependencies for the voice engine. This prevented voice transcription from running in the packaged version of GEX.
  • Fix: UI: delete axis curve generated duplicate delete action.
  • Fix: Range Container: incomplete prior refactor caused an exception
  • Fix: UI: device widget: selection API causes parameter exception depending on interaction method
  • Fix: API: widget cache exception
  • Fix: API (Execution Engine): revert inadvertent clear container command for containers that support that option such as TempoEx.

(m77T61B)

  • Change: UI: added additional diagnostics and trace information on retrieving cache data.
  • Fix: UI: Calibration: axis exception.

(m77T61A)

  • Fix: PlaySound Action: typo exception in blocking delay
  • Fix: API: get last input for voice and non-numeric data.

(m77T61)

  • New: API: Containers have an execution priority order like actions. The order priority sets, at run time, the trigger order (the order in which container receives input triggers) with the lowest numbers executing first, and the higher numbers executing last. Containers with the same priority run in an undefined order based on the way the data is stored, which is not necessarily the order in which the container appears on the screen or is listed in the profile. As with actions, if you want a container B to execute before container A, give B a lower number, for example A = 10, B = 0. If you want container C to execute between B and A, in the example here, C = 5. The default priority is 0. The number range is 0 to 999. Any number can be used in that range. If you need precise control over actions, consider using the sequence container which is designed to sequence actions and includes advanced features like delay, randomization, repeat counts, etc...
  • Change: API: generic sidecar support in profile save / save-as
  • Fix: Overlay: sidecar configuration file moved to .obs.json to avoid a contention issue with the main .json sidecar.
  • Fix: Overlay: resolve an issue with overlay not saving due to occasional sidecar contention.

(m77T60)

  • New: Trigger Action: added pulse mode for button triggers.
  • New: UI (Inputs): new icon to identify if the input has at least one mapped container. This is added because some mappings may have empty containers attached to the input with no actions.
  • Change: UI (Options): Modules tab : list applicable environment variable if the module is enabled via an environment variable.
  • Change: Map to VJoy Action: guard against invalid output configurations if the output device, button, hat or axis no longer exists. Instead of throwing an exception, the action will ignore all triggers and place warnings in the log file. This can happen when a profile is saved but the vjoy configuration changed after the fact.
  • Change: UI (Device Filter): filter is now aware of modules that are turned off through configuration options.
  • Fix: API (Events): added lock for certain event processing to avoid potential race conditions.
  • Fix: Trigger Action: exception on press/release checkbox selection due to new API.
  • Fix: Map to VJoy Action: virtual output device button count exception in hat to button mapping.
  • Fix: API (Keyboard): obtaining a list of key names fails with an exception if keys are not yet defined.
  • Fix: UI (Device Filter): exception when clicking the default button due to API change.
  • Fix: StreamDeck device: fix for two potential QT issue.
  • Fix: State device: fix for two potential QT issue.
  • Fix: UI (Input Viewer): toggle combo hat/button display resets other visualizers.
  • Fix: UI (Input Viewer): visualizers could stop updating on profile run on profile change while the window is visible.
  • Fix: UI (input selection): last selected input may not be restored on profile load or app start (still under investigation).

(m77T59)

  • Change: added verbosity option readout to log file on profile start
  • Change: added state status readout to log file on profile start after states are reset for a new profile run
  • Change: added more meaningful diagnostics data to TempoEx container including input and current profile mode.
  • New: Options: ability to enable/disable various GEX modules. Unused features should be disabled to reduce memory and CPU usage at runtime.
  • Fix: UI (icon bug): as it's difficult to determine what is causing the underlying QTA library exception, wrapped these calls to capture the error and traceback to the log file and replace the icon with a generic icon. This should hopefully provide better information as to what's causing this without crashing GEX.
  • Fix: API: exception on JSON output with continued OS file locks. Added logic and timer to allow for the OS to release the file locks on temporary files.

(m77T58B)

  • Fix: resolved one more cause of thread.init() exception

(m77T58A)

  • Fix: Map to Vjoy Action: axis scaling exception.

(m77T58)

  • Change: general optimization pass
- keyboard input queues - mouse input queues - joystick input queues - Octavi IFR - HID polling - major refresh improvement for input viewer
  • Change: configuration overrides for development (allows toggling of components for dev purposes)
  • Fix: further tweaking of axis filtering workflows with EMA filter now able to handle rapid and large changes. Added axis settling algorithm to filter to validate final position. This is aimed at devices that spam (a.k.a. overwhelm inputs with hundred or thousand of updates per second). The devices also tend to instantly stop spamming when the input is in certain positions (such as a center location) causing the filter to terminate on the wrong value due to the low-pass algorithm. This is the best of both worlds, with filtering of spam, while keeping accurate final positions after the spam stops and smoothing values in between.
  • Fix: UI: replaced QT stacked widget custom size/custom layouts as those were determined to cause random QT internal library crashes. These in turn caused an instant Python crash with no errors logged.
  • Change: Platform: reverted to Python 3.14.6 as 3.14.7 does not appear as stable for now especially with older libraries and the very heavy threaded nature of GEX.
  • Fix: UI: added fallback icon if an icon is not found (avoids a font exception) - this may not resolve the issue in all cases.

(m77T57A)

  • Fix: UI: various fixes (courtesy Lolo350)
  • Fix: API: EMA filter updates on drastic input changes (courtesy Lolo350)
  • Fix: UI: plugin UI does not always update correctly.
  • New: AFCS action (courtesy Lolo350)
- AFCS designer polish (canvas/inspector UX) - Config toggles: snap-to-grid and show-selected-segment-only - Robust AFCS device-tab registration in the main window
  • Change: Overlay:
- Overlay visibility conditions/preview, blink, host window, property clipboard, selection pane - Gradient fills (editor + palette storage) with live widget preview and enable/disable checkbox - Widget/font drop shadows with smoother rendering; collapsible inspector sections - Stream Deck page-name preservation in the profile sidecar; overlay persist logging

(m77T57)

  • Change: further optimization of input filtering for axis and button/hat inputs
  • Fix: UI (Voice): missing reference on initial default device query
  • Fix: UI (Voice): clear button looking for a filter that does not exist
  • Fix: UI (Voice): sort button does not visually sort inputs
  • Fix: API (Voice): clear known commands on profile reload

(m77T56)

  • New: anti-spam EMA filter applied to axis inputs aimed directly at devices that spam axis data like Azeron or Wooting and others clogging up the input queues. The filter reduces CPU usage by only processing meaningful data based on prior data, as well as the interval between signals. The filter only applies to axis data, smooths the data in 10ms intervals using a low overhead low-pass EMA algorithm (exponential moving average) and discards signals that too rapid while taking the signal into account.
  • Change: API (Voice): ability to select the AI model (small recommended for now).
  • Change: API (Voice): automatic download for AI model at runtime, local cache in sounds/managed/model folder.
  • Fix: API: eliminate duplicated warnings when remote control is not enabled.
  • Change: API: change from NodeGraphQt to OdenGraphQT (for QT graphics node library).
  • Change: API: add hugging face library (for voice model download).
  • Fix: merged PRR for overlay module (courtesy Lolo350)

(m77T55)

  • Change: PlaySound Action: exposed additional API features for sound playback options in the action. Ability to set decibel threshold for removing detected low volume (silence) in played audio (.wav or generated TTS) - recommended threshold is -55dB, trim options, optional delay if the blocking option is enabled to add a pause between sequential sounds and ability to sync settings globally in the profile to apply to other PlaySound actions without editing them one at at time.
  • Change: API: event processing optimization path on very expensive mode hierarchy lookups that were adding CPU usage to match events to execution nodes.
  • Change: API: execution node functor lookup optimization and caching.
  • Change: Input Viewer: optimization pass on axis repeater updates and eliminate, where possible, unnecessary axis redraws as this window can have hundreds of updates to make.
  • Fix: Macro Action: Vjoy selector - exclude ghost vjoy devices
  • Fix: API: prevent configuration (and sidecar) file corruption on file contention/crash/data errors

(m77T54A)

  • Change: API: sound: added audio sample auto-trim to trim silence at the start and end of a sample stream.
  • Change: API: sound: added caching of processed audio streams for faster playback.
  • Change: API: sound: changed blocking audio playback behavior to avoid audio stream close/reopen latency and to bypass pooled threading
  • Fix: API: mouse buttons not triggering.

(m77T54)

  • Fix: API: configure file watching system after startup to avoid a QT warning message.
  • Fix: UI: exception (missing widget) when deleting certain containers.
  • Fix: State Container: does not refresh on action add/remove
  • Change: Voice: updated command matching tree.
  • Change: API: execution engine: added input node tracking and execution

(m77T53)

  • Fix: API: continued refactor of GEX threading to handle recent internal changes to Python 3.14 threading. The issue caused a slew of recent fatal errors in the Python's engine, namely _lock contention_ on the termination of threads which is a new behavior so they are now handled differently after some research on publicly posted solutions.
  • Change: API (Voice): continued work on the voice recognition module, command matching algorithm and integration of voice commands with the execution graph. Internal testing continues to go well.
  • Fix: UI: Fixed one instance of QT C++ desync.
Notes: this patch does not include code updates for the overlay/streamdek modules and voice is still disabled in the packaged version as the feature is still in development. A further patch will be issued when updates to these modules are ready.

(m77T52)

  • Fix: API (Macro): legacy engine threading event rework due to Python 3.14 changes (could cause an internal Python exception)
  • Fix: API: VJoy keep alive service: threading event rework due to Python 3.14. (could cause an internal Python exception)
  • Fix: API: centralized magic values to ensure consistency across all callback registrations.
  • Change: Added new dependencies for upcoming modules.

(m77T51)

  • Fix: OBS Overlay: (experimental) - enhancements, thread safety and various fixes (courtesy Lolo350)
  • Fix: Streamdeck Device: (experimental) - polish + paste/splitter stability. (courtesy Lolo350)
  • Fix: UI : various fixes.
  • Fix: API: refactor low level mouse wheel release handling to avoid Python 3.14 threading library issues with timers due to the use of internal events in Python that could cause internal lock issues.
  • Change: API: use of high resolution mouse wheel events (support for high resolution devices).

(m77T50)

  • New: OBS Overlay: (experimental) Module courtesy Lolo350. This module allows to design and show an overlay module for OBS with chroma-key support suitable for streaming or showing inputs real-time. Many thanks to Lolo350 for including this feature in GEX.
  • New: API Voice: (experimental) API level support for voice input/speech commands. This module while not yet in production in T50 as UI features are currently disabled in this build while the internal testing continues and includes missing features, the API includes local services for speech recognition. This will follow in the coming days with a voice input device to use natural speech as an input device. Voice commands will trigger mappings as any other input device would in GEX.
  • Fix: Streamdeck Device: added compatibility for T50 (courtesy Lolo350).
  • Fix: Macro API: for the older macro run model, revisited start/stop logic of the macro scheduler and removed daemon status which would cause shutdown/restart logic errors. This does not impact the new faster macro run model.
  • Fix: PlaySound Action: persist suppress duplication options and timings and update UI visuals.

(m77T49)

  • Fix: Map to State Action: exception when in pulse mode on profile mode change.

(m77T48M)

  • Change: Platform: updated packaging tool to 6.22.2 and forced the inclusion of the encodings Python module via the packaging configuration file.
  • Fix:

(m77T48)

  • Change: API (macro): (experimental) Different execution model for macros to increase performance and minimize overhead. A new runtime option enable this mode can be found on the runtime tab in global options under macro execution engine. This is off by default. The performance increase stems from eliminating the use of the scheduler and instead uses a thread pool model and is similar to the approach used in the updated sound module in m77. At this time, exclusive mode is not supported (all macros run concurrently as triggered), one of the ways performance is gained. If exclusive mode is required, use the older model. The execution model is independent of profile mode changes, meaning, a macro that runs in that engine will continue running even if a profile mode change occurs as it's running. This mode is experimental and needs further testing but is functional for standard "fire and forget" macros as triggered.
  • Fix: API: join on keyboard daemon thread from prior logic where keyboard was not a daemon thread
  • Fix: Sound API: missing verbose flag
  • Fix: API: default utf-8 encoding for log system to avoid hard crash on special characters.
  • Fix: UI: Mode selector does not fit all modes and can show modes in incorrect nesting order.

(m77T47A)

  • Fix: API: incorrect parameter name in vjoy enumeration call

(m77T47)

  • Change: Sound API: removed KTTS as an option as this experimental TTS generation method is not practical for GEX due to dependencies and significant complexity installing, and significant footprint for mediocre results compared to EdgeTTS.
  • Fix: remove spurious Torch library breaking packaged mode in T46 (this was an automated "feature" that was not requested and uncaught for T46 - my bad)
  • Fix: Tempo Container: verbose mode exception.
  • Change: API: scanning of disconnected devices is changed to work with new display filters and will distinguish between vjoy devices and physical devices.
  • Fix: UI: incorporate display of disconnected devices as tabs outside of device filter settings.
  • Change: API: refactor device tab filtering data to incorporate disconnected data.
  • Change: API: when loading a VJOY as input from a profile, GEX will attempt to map it to the same VJOY ID based on configuration data in case the VJOY ID changed (this helps with porting profiles from one machine to another if VJOY IDs are different)
  • Fix: API: reset disconnected device references from a prior profile on profile reload.
  • Fix: Gated Axis Action: vjoy as input loopback

(m77T46)

  • Fix: Playsound Action: missing call
  • Change: API: added a profile integrity check feature, for the moment, checking state data integrity due to reported ID changes. This will restore integrity in the profile automatically while the root cause is investigated. More integrity checks will be added especially to check proper XML formatting for profiles to help identify errors, especially when profiles are manually edited.
  • Change: API: added additional diagnostics code to track down a mode issue - this will dump the actual data at the time the error occurs to provide specific context.
  • Fix: API: disconnected devices read on profile read.
  • Fix: Virpil LED plugin fixes (courtesy Lolo350)
  • Fix: gated vjoy as input loopback (courtesy Lolo350)
  • Fix: double-conversion of certain runtime activation conditions (courtesy Lolo350)
  • Fix: VJOY merge latching (courtesy Lolo350)
  • Fix: Guard against unknown device (courtesy RazOrLegend)
  • Fix: TempoEx Container: double tap action could, depending on timing, get triggered by single click after initial trigger (not reset properly)
  • Fix: Tempo Container: adopted changes in T44/T45 to Tempo container for execution node setup.

(m77T45)

  • Change: Platform (Python): Update to Python 3.14.7 maintenance release.
  • Change: Platform (QT): Update to Pyside6 6.11.2, Shiboken6 6.11.2. maintenance releases.
  • Change: Sound API: add detection of audio device changes without constant polling that could break multi-stream playback on device change (change from T44).
  • Change: PlaySound Action: optimize voice reloading in UI if voice set has not changed.
  • Change: UI: reload profile on detected device changes (simplifies logic to re-sync user interface).
  • Fix: PlaySound Action: resolve possible exception when voice refresh button is used.
  • Fix: Sound API: ensure manual audio stream closing and force garbage collection to avoid a potential gotcha with audio library with an internal behavior of that library.
  • Fix: Sound API: guard against underlying library deadlock when swapping audio devices in the middle of playback.
  • Fix: OSC Device: exception on input dialog cancel.
  • Fix: OSC Device: exception on filtering (filtering in OSC needs more work).
  • Fix: Mode Device: internal conversion of legacy profile XML format ignores some entries skipping load of these mappings.
  • Fix: API: ensure profile mode list includes no duplicates.
  • Fix: API: log file issues incorrect warnings for missing joystick devices
  • Fix: API: profile device node missing device GUID data in some situations
  • Fix: API: invisible inputs on disconnected device

(m77T44)

  • New: Play Sound action: a new checkbox for "default audio device" is now available to have GEX output audio to the current OS default audio device, even if it changes at runtime. This is helpful if you want the profile device agnostic for audio output, or if the default device changes at runtime.
  • Fix: Input Viewer: guard against QT C++ when updating viewer after a visualizer was removed while UI events are still updating.
  • Fix: TempoEx Container: resolved an issue where the first defined action would map to the first blank entry, so a long actions would move to short if no short actions defined, and double would move to long, or short if no long actions defined. This is due to the new action model tracking in m77.
  • Fix: Play sound action: playback button is disabled in audio file mode even if a file has been selected.
  • Fix: API: exception in profile execute due to unknown package import.

(m77T43/A)

  • Change: new profile version 17 to support mode device profile changes.
  • Fix: Mode Device: m76 profiles may not load mode device mappings in m77 due to profile data changes.
  • Fix: Vjoy as input device tab names (courtesy Lolo350)
  • Fix: Vjoy Remap: ignore input release in stepped axis encoder mode.
  • Fix: TempoEx Container: actions are unloaded after profile load

(m77T42)

  • Fix: Macro Action: generic icon used for macro steps due to re-arranging of icons.
  • Change: UI: additional diagnostics instrumentation around device selector to track down an exception on device selector drop downs.
  • Fix: Play Sound Action: incorrect playback mode selected on profile reload.
  • Fix: Input viewer VJoy enumeration / axis names (courtesy Lolo350)

(m77T41A)

  • Fix: UI: input name retrieval may fail for keyboard/mouse input
  • Fix: UI: input name retrieval for an axis may fail for unknown devices (will now output an error message to the log file showing which device failed retrieval) and will display (unknown device) for the impacted input.
  • Fix: UI: possible C++ exception on QT when refreshing a device view depending on UI events if QT has already discarded the items but the Python engine is not yet aware.
  • Fix: API: QT C++ serialization of a Python set causing a conversion error in the QT library.
  • Fix: API: added additional instrumentation to validate hardware tracking data structures to get to the bottom of missing devices. Will output missing items in the log file.

(m77T40)

  • Change: TTS conversion: conversion of older TTS engine to Edge AI TTS. This will replace the old legacy TTS action, and also change any PlaySound actions that use the old engine to the new Edge AI system. The conversion saves to a new profile. This will automate changing to the high quality voices. The conversion will retain male/female voicing based on the SAPI names.
  • Change: TTS Action (legacy): add speaker name to XML
  • Fix: TTS API: provide suitable voice defaults for all TTS modes
  • Fix: TTS API: incorrect volume could generate audio with zero volume (causing no sound output).
Note: due to this change you may need to clear your managed audio file cache to force GEX to regen the audio.

(m77T39)

  • Change: UI: do not include full device name for inputs (these appeared recently due to the change in API)
  • Fix: TTS API: for legacy TTS, use a default voice if the selected voice no longer exists.
  • Fix: TTS API: for legacy TTS, check for non-empty phrase if there is no text to convert.
  • Fix: API: pull axis name correctly when device uses non-linear axis indexing or does not start at the first axis.
  • Fix: UI: provide a default icon to IconButton if icon not found.
  • Fix: Double Tap container: behavior updated for m77 API and resolved a few outstanding issues with this container. The new behavior has an automatic release enabled, as with tempoEx, meaning that when it gets triggered, an automatic release is also triggered after the delay has lapsed. The release is based on what was triggered (single/double) based on the first delay. Unlike TempoEx (which also has a double trigger mechanism), the double trigger container monitoring works on presses or releases as the initial trigger.

(m77T38)

  • New: UI: Tool menu option to clear managed sound file folder.
  • Change: TTS API: managed TTS sound files are now arranged internally by speaker.
  • Fix: Play Sound Action: synchronize locale with currently selected speaker on initial load.
  • Fix: TTS API: voice selection for pyttsx3 broken by m77.
  • Fix: TTS API: legacy (pyttsx3) TTS - switch to manual loop handling to avoid an internal library deadlock.

(m77T37A)

  • Fix: Additional guard for QT C++ check in device UI based object.
  • Change: Add traceback on filter default read or write errors so log file is more specific as to what the error is, and what led to that error.

(m77T37)

  • Change: UI: Display order dialog will look for a file in the profile folder called order.json and use that if present as the "load last" button.
  • Change: API: duplicate sound playback suppression is now off by default in global options. This governs the default state of TTS duplication for the play sound and legacy TTS actions.
  • Change: Play Sound Action/Legacy TTS action: duplicate suppression no longer changes the global option when toggled.
  • Fix: Play Sound Action/Legacy TTS action: when duplicate suppression is enabled, it does not evaluate action configuration changes to determine if the sound is a duplicate or not. NOTE: suppression is profile wide and applies to any TTS action in the profile. This is by design.
  • Fix: API: skip ghost VJOY devices when setting profile startup values (ghost devices are VJOY devices that are not configured on the local system).
  • Fix: API: ignore disconnected devices when setting virtual axis/button/hat

(m77T36)

  • Change: hardening for QT behaviors to validate for QT memory model and threading.
  • Change: hardening of sound API for cross-threading and to guard against possible race conditions.
  • Change: hardening of joystick API against out of band device changes
  • Change: API: optionally propagate view model changes for nested models (a model that contains other models)
  • Fix: API: condition parameter propagation for all conditions/actions
  • Fix: API: fixed an issue where loading a device from an older profile that no longer exists or is not connected could prevent a device node from being created causing a downstream exception and logic errors.
  • Fix: UI: input icons may not always update when mappings change

(m77T35)

  • Change: API: keyboard condition supports latched keys
  • Fix: Play Sound Action: selecting TTS legacy mode causes an exception.
  • Fix: UI: condition list not refreshing when a condition is added or removed.
  • Fix: UI: compound actions not refreshing when a new container section is added or removed.
  • Fix: UI: condition count not refreshing when a condition is added or removed.
  • Fix: UI: keyboard/mouse listener displays pressed keys/mouse buttons in multi-key mode
  • Fix: Keyboard condition: listen button functionality (single and multikey)
  • Fix: Map to KeyboardEx action: listen button functionality (single and multikey)

(m77T34)

  • Change: UI: added view model behavior to input visuals to simplify UI update logic where possible.
  • Fix: UI: keyboard/OSC/MIDI input visuals not displaying due to API changes resulting in undetected model changes.
  • Fix: UI: OSC inputs not displaying input information.
  • Fix: API: use zero based internal indexing for models (vs 1 based for DINPUT)
  • Fix: API: handle keyboard/mouse releases broken in T31 due to logic changes.
  • Fix: API: state device trigger - register inputs for new execution logic
  • Fix: UI: state device - state list does not update after add/remove
  • Fix: Press/Release (button container): mappings could reset after loading causing blank displays even if mappings are loaded.

(m77T33)

  • Fix: UI: Mapping visuals not displaying due to API changes resulting in undetected model changes.
  • Fix: API: Latching events could call an incorrect mapping instance. This involved more refactor of the latching API and how it functions, and now adds an override to the functor execution logic.
  • Fix: VJoy Remap action: some stepped visual may be visible when not in stepped mode.
  • Fix: Tempo (legacy) container: exception on missing components. Courtesy RazOrLegend.
  • Fix: Macro (legacy) action: profile restart behavior - reset scheduler. Courtesy RazOrLegend.

(m77T32)

  • Fix: UI: determine current active device tab fails disabling input highlight.
  • Fix: UI: input list excessively redraws or does not redraw when it should.

(m77T31)

  • New: Map to Vjoy action: stepped axis mode (button to axis): gains a new encoder mode. This mode uses an acceleration curve and pulse time to step (modify) the axis output based on pulse frequency and direction. This is used for inputs such as rotary encoders that generate a pulse trigger. The mode supports a latching input to handle the reverse pulse input, enabling a single mapping to handle both rotary directions. The encoder calculation is direction aware to speed up or slow down the rate of change and direction of rotation. The encoder uses acceleration measuring pulses per second and can increase/decrease the rate of change based on how fast you pulse the input (rotate the encoder).
  • New: Map to VJoy action: ability to latch keyboard input for reverse motion (previously only supported joystick buttons).
  • New: Map to VJoy action: cubic distribution for stepped mode
  • Change: Execution engine: reworked multi-key keyboard triggers, and is greatly simplified from the prior API.
  • Fix: Map to VJoy action: corrected output description in visual.
  • Fix: Keyboard Device: corrected input description.
  • Fix: Keyboard Device: display keys in correct order for latched keys (multi keys)
  • Fix: API: model reindex uses incorrect datatype for hash computation
  • Fix: API: Python delete / set methods not supported by new model objects.
  • Fix: API: Python 3.14 threading timer behavior change causing a possible exception when handling mouse wheel low level events - PRR by RazOrLegend (thank you!)
  • Fix: Keyboard Device: Fixed a UI refresh issue when adding a new key.
  • Fix: UI: Listen for input should disable auto-highlight.
  • Fix: API: parent mode lookup for input matching when using nested modes - PRR by RazOrLegend (thank you!)
  • Fix: UI: tray icon updated when profile is active

(m77T30)

  • Change: API: changed device enumeration logic and added additional filter for invalid (ghost) devices
  • Fix: Input Viewer: state visualizer enumeration exception in some situations.
  • Fix: Input Viewer: state and keyboard/mouse visualizers initial checked state does not reflect persisted visualization state
  • Fix: API: state tracker: unhandled new device types can cause exceptions
  • Fix: Keyboard Device: release events may not auto trigger (actions could only get a press, but not a release)
  • Fix: Map to State action: incorrect spacing in the layout of some options.

(m77T29)

  • New: Sequence Container: Continue on trigger change option. This option applies to normal and wiggle modes only (not loop/round-robin modes). When set, it will ignore the input trigger state change (for example, a button release after a button press that triggered the sequence), and continue running the sequence until all steps complete. Has no effect in loop or toggle modes. This can also be called a "fire and forget" mode, so all steps will always execute once triggered. When off, the sequence stops executing even if the sequence is not completed when the input trigger changes states.
  • New: Play/TTS action: Blocking option added. When enabled, only one sound will play at a time and any queued sounds will be blocked until the prior sound fully plays. Default is off, sounds will play simultaneously when triggered.
  • New: Play/TTS action: Stop playback mode. When in this mode, the action, when triggered, will stop all playback going through the sound engine. Note, this only stops sounds currently in the playback queue or actively playing. If another profile action is adding new sounds to the queue, playback will resume until the sounds are played or the next stop playback trigger is received.
Change: network API data packets refactor to support upcoming features Change: UI: tweak mapping user interface with improved section headers
  • Fix: exception when adding a state to the state device in some situations.
  • Fix: condition model API
  • Fix: conditions may not persist to profile
  • Fix: conditions UI may not update counts/distinguish between container conditions and action conditions

(m77T28)

  • New: Play Sound Action: added sync button for cooldown options (synchronizes settings with other play sound actions in the profile instead of changing them one at a time).
  • Fix: Add additional diagnostics wrapper code around file search to better identify issues with OS I/O errors.

(m77T27a)

  • Fix: Map to Vjoy Action: button output uses incorrect button ID
  • Fix: Map to Vjoy Action: merge axis widget can cause exception
vFix: UI: wrap C++ error when cleaning up QT widget (QT may destroy the widget before Python is finished destroying it)
  • Fix: API: joystick devices: exclude vjoy as an input devices if not set as an input (avoids loops)
  • Fix: API: joystick devices: ensure device lists are not duplicated
Known issue: Map to Vjoy Action: merge axis repeater does not update at design time.

(m77T27)

  • New: Actions API: add aliases for supported actions (allows multiple names for a given action to facilitate searching/on boarding).
Change: UI: prompt on action delete.
  • Fix: VJoy Remap Action: "next unused" did not search complete profile
  • Fix: State Device: missing type reference on state conditions
  • Fix: API: update indexing on model delete
  • Fix: TTS (legacy) Action: typo in parameter
  • Fix: TTS (legacy) conversion tool: include profile companion files when converting TTS legacy to new.
  • Fix: API: (backup) include profile companion files in automatic profile backups.
  • Fix: Play Sound: provide suitable default when changing TTS engine modes.

(m77T26)

  • Fix: Additional pass on UI cache.
  • Fix: Keyboard Device: input delete does not delete from profile (API change)
  • Fix: Keyboard Device: input override type did not default to joystick button
  • Fix: Keyboard Device: input did not trigger for mouse related inputs.
  • Fix: OSC Device: input delete does not delete from profile (API change)
  • Fix: OSC Device: OSC message is not visible in input
  • Fix: Vjoy Remap Action: clicking "next unused" button would fail on keyboard input.
  • Fix: UI: deleting an input may not clear associated mapping in the UI.
PRR merge: Virpil LED fixes + Map to Streamdeck action contributed by Lolo_350

(m77T25A)

  • Fix: UI: resolve cache issue (could cause exception when selecting a new input depending on the cache state)
  • Fix: removed spurious import from TTS action

(m77T25)

  • Change: VPC LED action: add non-debug mode execution mode to hide the Virpil LED utility window.
  • Change: Virpil folder: adds the plugin version of the VPC LED action to source code control.
  • Change: UI: Curve Dialog invert button updated to new style
  • Change: UI: Options Dialog: Verbose options layout update
  • Change: TTS (legacy) action: add duplication options for playback (defaults to OFF)
  • Fix: API: delay load of joystick device UI causes invalid curve dialog updates for a call that didn't check for a delay load situation (new API in m77).
  • Fix: VPC LED action: change parameters to hex values as the LED tool expects hex values as parameters
  • Fix: UI: (device display options): device order load missing data type conversion on indexing update
  • Fix: UI: initial size of curve dialog too small.
  • Fix: UI: update for new API for axis input related triggers (curve, calibration) so they apply to the correct input under the m77 model-view system.
  • Fix: TTS: convert CoquiTTS to EdgeTTS on profile load and pick suitable defaults (Coqui is deprecated and was only available briefly as an experiment in 2025).
  • Fix: LOG: verbose mode for axis lookup on compound input types unable to get virtual axis #.
  • Fix: LOG: attach new verbosity elements to verbosity modes in m77.
  • Fix: Chain Container: invalid type referenced due to incomplete automatic name refactor of condition objects.
  • Fix: 1:1 mapping: vjoy remap action set to vjoy 1 regardless of selected vjoy device.

(m77T24A)

  • Fix: XML: (proposed) handling of vjoy (as input) device definitions not recognized in some profiles preventing the profile from loading correctly.

(m77T24)

  • Fix: handle default value for Mode Device for new API.
  • Fix: adjust default message box minimum size to avoid a QT exception

(m77T23)

  • Fix: UI: default dialog parameters for some dialogs may map to incorrect parameters
  • Fix: UI: add mode dialog incorrect parent mode dropdown size.
  • Fix: API: Mode device event handling may not result in a trigger.
  • Fix: UI: remove an action does not always update the action icon list
  • Fix: API: Mode Enter/Mode Exit mappings may not trigger mappings.
  • Fix: API (plugins): boolean plugin variable UI no longer using multi-state checkboxes.
  • Fix: UI: old icon when minimized to tray

(m77T22)

  • Fix: API: Event registration for keyboard condition undefined variable
  • Fix: Reporting: updates for API changes - various devices and containers

(m77T21)

  • Change: Play Sound: Renamed to Play Sound/TTS to reflect new AI capabilities for TTS
  • Fix: Input Viewer: show/hide content not always updating the visualizers.
  • Fix: Input Viewer: One more C++ GC issue with state/keyboard visualizers due to caching.
  • Fix: Input Viewer: clicking on the selector button could result in a QT exception.
  • Fix: Input Viewer: workaround to QT layout visualizer width (due to height workaround)
  • Fix: Input Viewer: clear button does not save visualizer visual states.
  • Fix: Input Viewer: keyboard visualizer key spacing (due to height workaround)
  • Fix: API: Event registration for keyboard condition property called as a method
  • Fix: VJOY: hat output going to incorrect VJOY hat (courtesy of RazOrLegend)
  • Fix: UI: window resize (courtesy of RazOrLegend)
  • Fix: Device Dialog: exception on invalid device (will issue warning in log file as to what it received while ignoring the invalid entry)
Known issue: Input Viewer: when displayed without a joystick device, keyboard and state visualizers may have the incorrect width. This will be resolved at a later time.

(m77T20)

  • Fix: Input Viewer: C++ GC issue if input is refreshed while QT i
... (README truncated for length)
Chat with me