JEvent
JEvent is a lightweight Python library for using gamepad/joystick input like keyboard input.
It is designed especially for simple games and applications where you already have keyboard controls and want to add gamepad support without rewriting your input system.
Features
- Converts gamepad events into keyboard-style events.
- Provides a
keysymattribute so the same callback can handle keyboard-like input. - Supports buttons, analog sticks, triggers, and the D-pad.
- Customizable gamepad-to-keyboard mappings with
configure(). - Handles controller disconnection and reconnection while the event loop is running.
- Designed to be simple to add to existing Python programs.
- Tested without requiring a gamepad-specific window.
- Uses Pygame's joystick support.
- Includes optional
doublify()functionality for Tkinter integration.doublify()is experimental/unstable and is not required.
Installation
pip install JEvent
For TestPyPI:
pip install -i https://test.pypi.org/simple/ JEvent
Basic usage
import JEvent
def on_key_press(event):
if event.keysym == 'a':
move_left()
elif event.keysym == 'd':
move_right()
JEvent.mainloop(on_key_press)
mainloop() continuously checks for gamepad input and passes a JEvent
object to your callback.
The idea is simple: let your existing keyboard-oriented code handle gamepad input too.
The JEvent object
A JEvent contains:
event.key
event.type
event.value
event.keysym
key
The gamepad control that generated the event. Supported controls include:
A, B, X, Y
L1, R1, L2, R2
-, +, HOME
LPad, RPad
LPad X, LPad Y
RPad X, RPad Y
DPad
type
Events use:
"<KeyPress>"
"<KeyRelease>"
Convenience properties are also available:
event.pressed
event.released
value
The underlying state/value of the event.
Buttons normally use 1 for press and 0 for release. Analog controls
use normalized values, while D-pad events use an (x, y) pair.
keysym
The keyboard-style key associated with the gamepad event.
For example:
if event.keysym == 'e':
print("A button")
The mapping can be changed with configure().
Comparing events
== compares the event type and control:
if event == JEvent('A', '<KeyPress>', 1):
...
For an exact comparison, including the value, use:
if event.isnt(other_event):
...
This distinction is intentional: two motions of the same analog control
are still the same kind of event, while isnt() lets you check whether
their complete states differ.
JEvent also has a boolean representation:
if event:
print("A real event was received")
An empty JEvent() evaluates as false.
Custom mappings
Change the keyboard mapping with configure():
JEvent.configure([
'space', 'e', 'r', 'q',
'shift_L', 'x', 'c', 'z',
'Tab', 'Return', 'Escape',
'ctrl_L', 'm',
'a', 'd', 's', 'w',
'j', 'l', 'k', 'i',
'1', '2', '3', '4',
'Left', 'Right', 'Up', 'Down'
])
The mapping order is:
B
A
X
Y
L1
R1
L2
R2
-
+
HOME
LPad
RPad
LPad Left
LPad Right
LPad Down
LPad Up
RPad Left
RPad Right
RPad Down
RPad Up
DPad NW
DPad NE
DPad SW
DPad SE
DPad W
DPad E
DPad N
DPad S
A dictionary can also be used to replace selected entries:
JEvent.configure({
0: 'space',
1: 'e'
})
Analog sticks
Analog stick movement is translated into directional keyboard-style events.
For example:
if event.keysym == 'a':
move_left()
elif event.keysym == 'd':
move_right()
elif event.keysym == 'w':
move_up()
elif event.keysym == 's':
move_down()
The analog value is available through event.value.
The neutral position is treated as a release, allowing an analog stick to behave more like a keyboard direction.
D-pad
D-pad events use:
event.key == 'DPad'
and store the D-pad position as an (x, y) pair.
JEvent also provides keyboard-style mappings for:
DPad NW
DPad NE
DPad SW
DPad SE
DPad W
DPad E
DPad N
DPad S
Tkinter integration
JEvent was designed with Tkinter integration in mind.
A normal Tkinter-style callback can process a JEvent because it has a
keysym attribute:
def on_key_press(event):
if event.keysym == 'a':
move_left()
elif event.keysym == 'd':
move_right()
If you are running JEvent alongside Tkinter, pending Tk events can be serviced with:
root.update()
For example:
def on_key_press(event):
root.update()
if event.keysym == 'a':
move_left()
This can allow Tkinter callbacks, redraws, and scheduled work to be processed while JEvent's loop is running.
mainloop()
The main loop is:
JEvent.mainloop(event_func)
It also accepts:
JEvent.mainloop(
event_func,
condition=lambda: False,
verbose=True
)
event_func
The function receiving each JEvent:
def event_func(event):
print(event)
condition
A function that determines when the loop should stop:
running = True
def finished():
return not running
JEvent.mainloop(event_func, finished)
The loop continues until condition() returns True.
verbose
Controls warnings about gamepad availability:
JEvent.mainloop(event_func, verbose=False)
No-window use
JEvent has been tested without requiring a gamepad-specific window.
This is useful when another framework already owns the application's window, or when you simply want to receive controller input without creating another one.
Controller reconnection
The main loop can continue running if the controller is disconnected.
When no gamepad is available, the callback receives an empty:
JEvent()
When a gamepad becomes available again, JEvent reconnects to it.
This means an application does not have to restart its input loop just because a controller was unplugged and plugged back in.
Lower-level API: on_pad_press()
If you want to handle Pygame events yourself, on_pad_press() converts
a Pygame joystick event into a JEvent:
event = JEvent.on_pad_press(pygame_event)
This is useful when you need more control over the event loop.
eval_keys()
A JEvent calculates its keysym from its current control and value.
You can re-evaluate it with:
event.eval_keys()
This is useful after changing an event's state or the mapping.
doublify() --- Experimental
doublify() is optional and unstable.
It is intended to help connect JEvent input with an existing Tkinter
<KeyPress> binding.
You do not need doublify() to use JEvent.
For normal use, prefer:
JEvent.mainloop(...)
and the event.keysym interface.
Example: add gamepad support to keyboard-style movement
import JEvent
x = 0
def move_left():
global x
x -= 1
def move_right():
global x
x += 1
def on_input(event):
if event.keysym == 'a':
move_left()
elif event.keysym == 'd':
move_right()
JEvent.mainloop(on_input)
The same movement functions can also be called by a normal keyboard binding.
That is the main purpose of JEvent:
gamepad
↓
JEvent
↓
keyboard-style event
↓
existing input handler
↓
game logic
Instead of rewriting a keyboard-controlled game to understand controllers separately.
Requirements
JEvent uses Pygame's joystick support.
It is intended for Python programs that can use Pygame's joystick functionality.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jevent-1.0.3.tar.gz.
File metadata
- Download URL: jevent-1.0.3.tar.gz
- Upload date:
- Size: 7.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba7c026bea79d3b5134d073c99f074c07bf26cf127b21c645b9661ae5a250712
|
|
| MD5 |
2f08cec2d820238b3072dde10287c00b
|
|
| BLAKE2b-256 |
2d2c1d4ada52870b0a665d8d017e86d5ac48b3f28655d986782880ce4753baa9
|
File details
Details for the file jevent-1.0.3-py3-none-any.whl.
File metadata
- Download URL: jevent-1.0.3-py3-none-any.whl
- Upload date:
- Size: 8.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3894f2b8eb9628b041a05137a6596b9f9a94c454b409487fb3d01b8d3e21805
|
|
| MD5 |
fdaac81fb8a7f587800d78b151471e1d
|
|
| BLAKE2b-256 |
99c52b13a6017bd3ef18d49463e82e9b38e0ca9acc93f451e106334e2637e6af
|