|
| 1 | +import evdev |
| 2 | +from evdev import UInput, ecodes as e |
| 3 | + |
| 4 | +# Open your PS4 controller device |
| 5 | +device = evdev.InputDevice('/dev/input/by-id/usb-Sony_Interactive_Entertainment_Wireless_Controller-if03-event-joystick') # Replace |
| 6 | + |
| 7 | +# Create a virtual keyboard |
| 8 | +ui = UInput() |
| 9 | + |
| 10 | +print(f"Listening for input from {device.name}...") |
| 11 | + |
| 12 | +for event in device.read_loop(): |
| 13 | + if event.type == e.EV_ABS: # Detects D-pad, Sticks and Triggers |
| 14 | + """ |
| 15 | + Sticks and Triggers |
| 16 | + ABS_X and ABS_Y 0 means left stick is most to the left or most down |
| 17 | + 227-228 is the middle 255 is most to the right or most up. |
| 18 | + dead zone should be something like 64 to 191. |
| 19 | +
|
| 20 | + We then have the trigger ABS_Z L2 0 means not pushed down |
| 21 | + and 255 means most pushed down. |
| 22 | +
|
| 23 | + We then have the same on the right, stick and R2. |
| 24 | + ABS_RX, ABS_RY and ABS_RZ. We might not use ABS_RX and ABS_RY. |
| 25 | +
|
| 26 | + Stick must have a threshold and pair of ways or single way |
| 27 | + so it can trigger one or two ways in the game. |
| 28 | + This is called 8-way digital stick. We can start simple |
| 29 | + with only a threshold. We should at lest calculate a circle |
| 30 | + threshold we can start with a 8 way square. |
| 31 | + """ |
| 32 | + if event.code == e.ABS_X: # Left stick X |
| 33 | + last_x = event.value |
| 34 | + if event.value < 63: # Left threshold |
| 35 | + ui.write(e.EV_KEY, e.KEY_LEFT, 1) # Press Left Arrow |
| 36 | + ui.syn() |
| 37 | + elif event.value > 192: # Right threshold |
| 38 | + ui.write(e.EV_KEY, e.KEY_RIGHT, 1) # Press Right Arrow |
| 39 | + ui.syn() |
| 40 | + else: |
| 41 | + ui.write(e.EV_KEY, e.KEY_LEFT, 0) |
| 42 | + ui.write(e.EV_KEY, e.KEY_RIGHT, 0) |
| 43 | + ui.syn() |
| 44 | + |
| 45 | + elif event.code == e.ABS_Y: # Left stick Y |
| 46 | + last_y = event.value |
| 47 | + if event.value < 63: # Up threshold |
| 48 | + ui.write(e.EV_KEY, e.KEY_UP, 1) # Press Up Arrow |
| 49 | + ui.syn() |
| 50 | + elif event.value > 192: # Down threshold |
| 51 | + ui.write(e.EV_KEY, e.KEY_DOWN, 1) # Press Down Arrow |
| 52 | + ui.syn() |
| 53 | + else: |
| 54 | + ui.write(e.EV_KEY, e.KEY_UP, 0) |
| 55 | + ui.write(e.EV_KEY, e.KEY_DOWN, 0) |
| 56 | + ui.syn() |
| 57 | + |
| 58 | + elif event.code == e.ABS_Z: # Left trigger Z |
| 59 | + if event.value > 200: |
| 60 | + ui.write(e.EV_KEY, e.KEY_S, 1) # Activate S |
| 61 | + ui.syn() |
| 62 | + else: |
| 63 | + ui.write(e.EV_KEY, e.KEY_S, 0) # Deactivate S |
| 64 | + ui.syn() |
| 65 | + |
| 66 | + elif event.code == e.ABS_RZ: # Right trigger Z |
| 67 | + if event.value > 200: |
| 68 | + ui.write(e.EV_KEY, e.KEY_C, 1) # Activate C |
| 69 | + ui.syn() |
| 70 | + else: |
| 71 | + ui.write(e.EV_KEY, e.KEY_C, 0) # Deactivate C |
| 72 | + ui.syn() |
| 73 | + |
| 74 | + if event.type == e.EV_KEY: # Detects simple click buttons |
| 75 | + """ |
| 76 | + start at 1 ends at 0 when lifted, super simple. |
| 77 | + BTN_EAST Ring |
| 78 | + BTN_SOUTH Cross |
| 79 | + BTN_WEST Square |
| 80 | + BTN_NORTH Triangle |
| 81 | +
|
| 82 | + BTN_TL L1 |
| 83 | + BTN_TR R1 |
| 84 | +
|
| 85 | + BTN_SELECT Share |
| 86 | + BTN_START Options |
| 87 | +
|
| 88 | + """ |
| 89 | + if event.code == e.BTN_EAST: # Ring |
| 90 | + if event.value == 1: |
| 91 | + ui.write(e.EV_KEY, e.KEY_END, 1) # Activate END |
| 92 | + ui.syn() |
| 93 | + else: |
| 94 | + ui.write(e.EV_KEY, e.KEY_END, 0) # Deactivate END |
| 95 | + ui.syn() |
| 96 | + |
| 97 | + if event.code == e.BTN_SOUTH: # Cross |
| 98 | + if event.value == 1: |
| 99 | + ui.write(e.EV_KEY, e.KEY_LEFTCTRL, 1) # Activate Left CTRL |
| 100 | + ui.syn() |
| 101 | + else: |
| 102 | + ui.write(e.EV_KEY, e.KEY_LEFTCTRL, 0) # Deactivate Left CTRL |
| 103 | + ui.syn() |
| 104 | + |
| 105 | + if event.code == e.BTN_WEST: # Square |
| 106 | + if event.value == 1: |
| 107 | + ui.write(e.EV_KEY, e.KEY_LEFTALT, 1) # Activate Left ALT |
| 108 | + ui.syn() |
| 109 | + else: |
| 110 | + ui.write(e.EV_KEY, e.KEY_LEFTALT, 0) # Deactivate Left ALT |
| 111 | + ui.syn() |
| 112 | + |
| 113 | + if event.code == e.BTN_NORTH: # Triangle |
| 114 | + if event.value == 1: |
| 115 | + ui.write(e.EV_KEY, e.KEY_SPACE, 1) # Activate SPACE |
| 116 | + ui.syn() |
| 117 | + else: |
| 118 | + ui.write(e.EV_KEY, e.KEY_SPACE, 0) # Deactivate SPACE |
| 119 | + ui.syn() |
| 120 | + |
| 121 | + if event.code == e.BTN_TL: # L1 |
| 122 | + if event.value == 1: |
| 123 | + ui.write(e.EV_KEY, e.KEY_KP0, 1) # Activate Numpad 0 |
| 124 | + ui.syn() |
| 125 | + else: |
| 126 | + ui.write(e.EV_KEY, e.KEY_KP0, 0) # Deactivate Numpad 0 |
| 127 | + ui.syn() |
| 128 | + |
| 129 | + if event.code == e.BTN_TR: # R1 |
| 130 | + if event.value == 1: |
| 131 | + ui.write(e.EV_KEY, e.KEY_LEFTSHIFT, 1) # Activate LEFTSHIFT |
| 132 | + ui.syn() |
| 133 | + else: |
| 134 | + ui.write(e.EV_KEY, e.KEY_LEFTSHIFT, 0) # Deactivate LEFTSHIFT |
| 135 | + ui.syn() |
| 136 | + |
| 137 | + if event.code == e.BTN_SELECT: # Share |
| 138 | + if event.value == 1: |
| 139 | + ui.write(e.EV_KEY, e.KEY_COMMA, 1) # Activate COMMA |
| 140 | + ui.syn() |
| 141 | + else: |
| 142 | + ui.write(e.EV_KEY, e.KEY_COMMA, 0) # Deactivate COMMA |
| 143 | + ui.syn() |
| 144 | + |
| 145 | + if event.code == e.BTN_START: # Options |
| 146 | + if event.value == 1: |
| 147 | + ui.write(e.EV_KEY, e.KEY_ESC, 1) # Activate ESC |
| 148 | + ui.syn() |
| 149 | + else: |
| 150 | + ui.write(e.EV_KEY, e.KEY_ESC, 0) # Deactivate ESC |
| 151 | + ui.syn() |
| 152 | + |
| 153 | + |
| 154 | +# This function implements an analog-to-digital conversion with angular thresholding, |
| 155 | +# where the joystick angle determines whether to send a full digital press or a pulsed key press. |
| 156 | +# This makes the joystick act more smooth to Lara's turning movement, |
| 157 | +# def map_analog_to_digital(joystick_input): |
| 158 | + # ... implementation details ... |
| 159 | + |
0 commit comments