WhiteMagic / JoystickGremlin

A tool for configuring and managing joystick devices.
http://whitemagic.github.io/JoystickGremlin/
GNU General Public License v3.0
324 stars 46 forks source link

3 state button emulation and startup sync #112

Open Francky63 opened 6 years ago

Francky63 commented 6 years ago

I need to emulate a 3 state switch(as in Cougar TQS DOg fight switch). As you probally know this is fixed in Falcon or in Tusba but the only solution for other programs is your application. Thia state are often used (especially in flight simulator application to determine the MODE) On the HOTAS usually you have a ON OFF ON switch where the software need a On ON ON switch. What i would like to do is to use the pressed button state for to remap the two ON buttons on vJoy and release button to remap OFF state on a vJoy button, i mean: you have UP MIDDLE DOWN position on the HOTAS usually you have only UP & DOWN state mapped on a Joy Buttons. My target is to have (e.g) UP vJoy button 1, MIDDLE on vJoy Button 2 and Down on VJoy button 3. Of course only one of them at time is on. I'm not able to do it with Joystick Gremlin UI i try with remap and condition, action pressed and release (that it look not working) but nothing. What i suppose to do is put On btn 1 when UP is pressed and Off btn 2, Put Off btn 1 and on btn 2 when UP is released (MIDDLE position emulation), Put On btn 3 and off btn 2 when DOWN is pressed and at last ... put off btn 3 and on btn 2 when DWON is release.

I solved it with the attached script where i insert also a problem for IDLE detent and engine start for Warthog ( when button is released the engine should be started and i need to rise up a button ...

This it solve all my needed except button initialization i need to put MIDDLE vJoy related buttons to ON when Joystick Gremlin is enabled i think i need something like this: vjoy[1].button(g_3_STATI1_MID_OUT_btn).is_pressed = True that should be executed at startup, but i don't know the right syntax and where to put it

I Think an synchronization option between input devices and vJoy output devices could be a useful feature in Joystick Gremlin Now if i start with joy button X pressed mapped on vJoy button Z, Z it stay OFF until a new source button state change

`

Program name: throttle.py

Program name: Modifiche per 3 state button

import gremlin throttle = gremlin.input_devices.JoystickDecorator( "Throttle - HOTAS Warthog", 72287236, "Default" )

Id of the button to press or pulse

g_3_STATI1_UP_IN_btn = 13 g_3_STATI1_DWN_IN_btn = 14 g_3_STATI1_UP_OUT_btn = 5 g_3_STATI1_MID_OUT_btn = 6 g_3_STATI1_DWN_OUT_btn = 7

g_3_STATI2_UP_IN_btn = 9 g_3_STATI2_DWN_IN_btn = 10 g_3_STATI2_UP_OUT_btn = 8 g_3_STATI2_MID_OUT_btn = 9 g_3_STATI2_DWN_OUT_btn = 10

g_3_STATI3_UP_IN_btn = 27 g_3_STATI3_DWN_IN_btn = 28 g_3_STATI3_UP_OUT_btn = 11 g_3_STATI3_MID_OUT_btn = 12 g_3_STATI3_DWN_OUT_btn = 13

g_3_STATI4_UP_IN_btn = 22 g_3_STATI4_DWN_IN_btn = 23 g_3_STATI4_UP_OUT_btn = 14 g_3_STATI4_MID_OUT_btn = 15 g_3_STATI4_DWN_OUT_btn = 16

g_IDLE1_IN_btn = 29 g_IDLE2_IN_btn = 30 g_IDLE1_OUT_btn = 17 g_IDLE2_OUT_btn = 18

===================================

------- first 3 state switch

===================================

@throttle.button(g_3_STATI1_UP_IN_btn) def button1(event, joy, vjoy):

global g_3_STATI1_UP_OUT_btn, g_3_STATI1_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI1_UP_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI1_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI1_UP_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI1_MID_OUT_btn).is_pressed = True

@throttle.button(g_3_STATI1_DWN_IN_btn) def button2(event, joy, vjoy):

global g_3_STATI1_DWN_OUT_btn, g_3_STATI1_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI1_DWN_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI1_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI1_DWN_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI1_MID_OUT_btn).is_pressed = True

===================================

------- Second 3 state switch

===================================

@throttle.button(g_3_STATI2_UP_IN_btn) def button3(event, joy, vjoy):

global g_3_STATI2_UP_OUT_btn, g_3_STATI2_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI2_UP_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI2_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI2_UP_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI2_MID_OUT_btn).is_pressed = True

@throttle.button(g_3_STATI2_DWN_IN_btn) def button4(event, joy, vjoy):

global g_3_STATI2_DWN_OUT_btn, g_3_STATI2_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI2_DWN_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI2_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI2_DWN_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI2_MID_OUT_btn).is_pressed = True

===================================

------- Third 3 state switch

===================================

@throttle.button(g_3_STATI3_UP_IN_btn) def button5(event, joy, vjoy):

global g_3_STATI3_UP_OUT_btn, g_3_STATI3_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI3_UP_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI3_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI3_UP_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI3_MID_OUT_btn).is_pressed = True

@throttle.button(g_3_STATI3_DWN_IN_btn) def button6(event, joy, vjoy):

global g_3_STATI3_DWN_OUT_btn, g_3_STATI3_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI3_DWN_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI3_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI3_DWN_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI3_MID_OUT_btn).is_pressed = True

===================================

------- Fourth 3 state switch

===================================

@throttle.button(g_3_STATI4_UP_IN_btn) def button7(event, joy, vjoy):

global g_3_STATI4_UP_OUT_btn, g_3_STATI4_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI4_UP_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI4_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI4_UP_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI4_MID_OUT_btn).is_pressed = True

@throttle.button(g_3_STATI4_DWN_IN_btn) def button8(event, joy, vjoy):

global g_3_STATI4_DWN_OUT_btn, g_3_STATI4_MID_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_3_STATI4_DWN_OUT_btn).is_pressed = True
    vjoy[1].button(g_3_STATI4_MID_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_3_STATI4_DWN_OUT_btn).is_pressed = False
    vjoy[1].button(g_3_STATI4_MID_OUT_btn).is_pressed = True

===================================

------- IDLE DETENT Engine 1

===================================

@throttle.button(g_IDLE1_IN_btn) def button9(event, joy, vjoy):

global g_IDLE1_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_IDLE1_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_IDLE1_OUT_btn).is_pressed = True

===================================

------- IDLE DETENT Engine 2

===================================

@throttle.button(g_IDLE2_IN_btn) def button10(event, joy, vjoy):

global g_IDLE2_OUT_btn
if event.is_pressed:
    # Press the button
    vjoy[1].button(g_IDLE2_OUT_btn).is_pressed = False
else:
    vjoy[1].button(g_IDLE2_OUT_btn).is_pressed = True

`

Francky63 commented 6 years ago

after I read one of your previous answers about press and release condition issue i found how to do it with MACRO.... Never mind ... but i would like to know how to initialize the button state via script and if could be an enhancement

WhiteMagic commented 6 years ago

I don't have a device with three state switches but I'm assuming that to Windows they appear as three independent buttons right? This is probably a case where using a finite state machine ( https://en.wikipedia.org/wiki/Finite-state_machine ) will make life much easier. Gremlin actually has a simple implementation of those as it's used to handle button states etc. I'll see about writing your example up using that as it probably should make your life much easier.

As for synchronizing physical and virtual buttons for initialization I think for a script something along these lines should work:

import gremlin

joy_proxy = gremlin.input_devices.JoystickProxy()
vjoy_proxy = gremlin.joystick_handling.VJoyProxy()

vjoy_proxy[1].button(1).is_pressed = joy_proxy[1].button(1).is_pressed

If this is part of a module loaded by your profile this will run whenever Gremlin is activated. What it then does is read information from the physical joystick and writes it to a vJoy button.

This should mostly work, however, due to the way joysticks work, i.e. they send information about state change as opposed to one asking them for their state, this can at times not work if there hasn't been a change recently. I found this mainly to be an issue with axis which is the reason that one can set their initial values in the settings tab.

akahanaton commented 10 months ago

I don't have a device with three state switches but I'm assuming that to Windows they appear as three independent buttons right? This is probably a case where using a finite state machine ( https://en.wikipedia.org/wiki/Finite-state_machine ) will make life much easier. Gremlin actually has a simple implementation of those as it's used to handle button states etc. I'll see about writing your example up using that as it probably should make your life much easier.

As for synchronizing physical and virtual buttons for initialization I think for a script something along these lines should work:


import gremlin

joy_proxy = gremlin.input_devices.JoystickProxy()
vjoy_proxy = gremlin.joystick_handling.VJoyProxy()

vjoy_proxy[1].button(1).is_pressed = joy_proxy[1].button(1).is_pressed

Hi, I'm running those code, vjoy_proxy works good, but the joy_proxy variable report the exception:

Traceback (most recent call last):
   File "gremlin\ui\user_plugin_management.py", line 54, in new_module
   File "gremlin\ui\user_plugin_management.py", line 227, in _create_module_instance
   File "gremlin\user_plugin.py", line 57, in get_variable_definitions
   File "<frozen importlib._bootstrap_external>", line 940, in exec_module
   File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
   File "C:/Users/Bright/Downloads/buttons_to_hat.py", line 52, in <module>
    vjoy_proxy[1].button(3).is_pressed = joy_proxy[1].button(1).is_pressed
                                         ~~~~~~~~~^^^
   File "gremlin\input_devices.py", line 1399, in __getitem__
   File "dill\__init__.py", line 646, in device_exists
 AttributeError: 'int' object has no attribute 'ctypes'

Could you give an example code how to fix it, thx

WhiteMagic commented 10 months ago

You can't use an integer index to access devices. The JoystickProxy requires the device's guid to be used, see https://github.com/WhiteMagic/JoystickGremlin/blob/r13/gremlin/input_devices.py#L392

Also how tristate buttons appear probably depends on the specific hardware implementation, could also just be 2 buttons.

akahanaton commented 10 months ago

Thanks for response, yes find a solution here: #272