|
|
|
@ -2,7 +2,7 @@ |
|
|
|
|
|
|
|
|
|
# |
|
|
|
|
# evalgamepad.py |
|
|
|
|
# Reading two USB gamepads & making sense of it ... |
|
|
|
|
# Reading two USB gamepads & making sense of it (try pong)... |
|
|
|
|
# |
|
|
|
|
#----------------------------------------------------------------------- |
|
|
|
|
# 'lsusb' ouput: Bus 002 Device 003: ID 0079:0011 DragonRise Inc. Gamepad |
|
|
|
@ -12,7 +12,7 @@ |
|
|
|
|
# /dev/input/event7 |
|
|
|
|
# |
|
|
|
|
|
|
|
|
|
import sys, os, fcntl |
|
|
|
|
import sys, os, fcntl, time |
|
|
|
|
import libevdev |
|
|
|
|
|
|
|
|
|
# Buttons in 'state<n>' |
|
|
|
@ -25,6 +25,42 @@ BTN_PINKIE = 32 # [Frontal right] |
|
|
|
|
BTN_BASE3 = 64 # [Centre left] |
|
|
|
|
BTN_BASE4 = 128 # [Centre right] |
|
|
|
|
|
|
|
|
|
GAMEAREA_MIN_X = 0 # Game area definition |
|
|
|
|
GAMEAREA_MAX_X = 1920 # Assume FHD resolution |
|
|
|
|
GAMEAREA_MIN_Y = 0 |
|
|
|
|
GAMEAREA_MAX_Y = 1080 |
|
|
|
|
|
|
|
|
|
def init_player(path): |
|
|
|
|
# Gamepad init. |
|
|
|
|
fd = open(path, "rb") |
|
|
|
|
fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) |
|
|
|
|
dev = libevdev.Device(fd) |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
"fd" : fd, # File descriptor to close (later ...) |
|
|
|
|
"dev" : dev, # Actual gamepad of this player |
|
|
|
|
"state" : 0, # Button mask (as above) |
|
|
|
|
"delta_x" : 0, # Current delta setting |
|
|
|
|
"delta_y" : 0, |
|
|
|
|
"x" : GAMEAREA_MAX_X/2, # Current actual position |
|
|
|
|
"y" : GAMEAREA_MAX_Y/2, # Start at center |
|
|
|
|
"w" : 10, |
|
|
|
|
"h" : 100 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
def exit_player(player): |
|
|
|
|
player["fd"].close() |
|
|
|
|
|
|
|
|
|
def init_object(x, y, w, h, delta_x, delta_y): |
|
|
|
|
return { |
|
|
|
|
"delta_x" : delta_x, # Current movement |
|
|
|
|
"delta_y" : delta_y, |
|
|
|
|
"x" : x, # Current position |
|
|
|
|
"y" : y, |
|
|
|
|
"w" : w, # Size of object |
|
|
|
|
"h" : h, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
def print_event(e): |
|
|
|
|
print("Event: time {}.{:06d}, ".format(e.sec, e.usec), end='') |
|
|
|
|
if e.matches(libevdev.EV_SYN): |
|
|
|
@ -37,11 +73,11 @@ def print_event(e): |
|
|
|
|
else: |
|
|
|
|
print("type {:02x} {} code {:03x} {:20s} value {:4d}".format(e.type.value, e.type.name, e.code.value, e.code.name, e.value)) |
|
|
|
|
|
|
|
|
|
def evalgamepad(dev, state, x, y): |
|
|
|
|
|
|
|
|
|
def eval_gamepad(player): |
|
|
|
|
bChanged = False |
|
|
|
|
try: |
|
|
|
|
for e in dev.events(): |
|
|
|
|
bChanged = True |
|
|
|
|
try: |
|
|
|
|
for e in player["dev"].events(): |
|
|
|
|
#print_event(e) |
|
|
|
|
|
|
|
|
|
# Event type 1 (EV_KEY) |
|
|
|
@ -58,105 +94,158 @@ def evalgamepad(dev, state, x, y): |
|
|
|
|
if e.type.value == 1: # Non-Cross events |
|
|
|
|
if e.value == 1: # Simple buttons may act as toggles |
|
|
|
|
if e.code.value == 288: # BTN_TRIGGER |
|
|
|
|
state = state ^ BTN_TRIGGER |
|
|
|
|
player["state"] = player["state"] ^ BTN_TRIGGER |
|
|
|
|
elif e.code.value == 289: # BTN_THUMB |
|
|
|
|
state = state ^ BTN_THUMB |
|
|
|
|
player["state"] = player["state"] ^ BTN_THUMB |
|
|
|
|
elif e.code.value == 290: # BTN_THUMB2 |
|
|
|
|
state = state ^ BTN_THUMB2 |
|
|
|
|
player["state"] = player["state"] ^ BTN_THUMB2 |
|
|
|
|
elif e.code.value == 291: # BTN_TOP |
|
|
|
|
state = state ^ BTN_TOP |
|
|
|
|
player["state"] = player["state"] ^ BTN_TOP |
|
|
|
|
elif e.code.value == 292: # BTN_TOP2 |
|
|
|
|
state = state ^ BTN_TOP2 |
|
|
|
|
player["state"] = player["state"] ^ BTN_TOP2 |
|
|
|
|
elif e.code.value == 293: # BTN_PINKIE |
|
|
|
|
state = state ^ BTN_PINKIE |
|
|
|
|
player["state"] = player["state"] ^ BTN_PINKIE |
|
|
|
|
elif e.code.value == 296: # BTN_BASE3 |
|
|
|
|
state = state ^ BTN_BASE3 |
|
|
|
|
player["state"] = player["state"] ^ BTN_BASE3 |
|
|
|
|
elif e.code.value == 297: # BTN_BASE4 |
|
|
|
|
state = state ^ BTN_BASE4 |
|
|
|
|
|
|
|
|
|
player["state"] = player["state"] ^ BTN_BASE4 |
|
|
|
|
bChanged = True |
|
|
|
|
|
|
|
|
|
# Event type 3 (EV_ABS) |
|
|
|
|
# Event code 0 (ABS_X) <- Cross: 127=Neutral, 0=[Left], 255=[Right] |
|
|
|
|
# Event code 1 (ABS_Y) <- Cross: 127=Neutral, 0=[Top], 255=[Down] |
|
|
|
|
elif e.type.value == 3: # EV_ABS |
|
|
|
|
if e.code.value == 0: # ABS_X |
|
|
|
|
if e.value == 0: |
|
|
|
|
x = x - 1 |
|
|
|
|
player["delta_x"] = player["delta_x"] - 1 |
|
|
|
|
elif e.value == 255: |
|
|
|
|
x = x + 1 |
|
|
|
|
player["delta_x"] = player["delta_x"] + 1 |
|
|
|
|
else: # 127/Neutral |
|
|
|
|
x = 0 |
|
|
|
|
player["delta_x"] = 0 |
|
|
|
|
else: # ABS_Y |
|
|
|
|
if e.value == 0: |
|
|
|
|
y = y + 1 |
|
|
|
|
player["delta_y"] = player["delta_y"] + 1 |
|
|
|
|
elif e.value == 255: |
|
|
|
|
y = y - 1 |
|
|
|
|
player["delta_y"] = player["delta_y"] - 1 |
|
|
|
|
else: # 127/Neutral |
|
|
|
|
y = 0 |
|
|
|
|
|
|
|
|
|
print("State=",state, "X=", x, "Y=", y) |
|
|
|
|
player["delta_y"] = 0 |
|
|
|
|
bChanged = True |
|
|
|
|
|
|
|
|
|
#if bChanged: |
|
|
|
|
# print("State=",player["state"], "X=", player["delta_x"], "Y=", player["delta_y"]) |
|
|
|
|
|
|
|
|
|
except libevdev.EventsDroppedException: |
|
|
|
|
print("Dropped!") |
|
|
|
|
for e in dev.sync(): |
|
|
|
|
for e in player["dev"].sync(): |
|
|
|
|
print_event(e) |
|
|
|
|
|
|
|
|
|
return bChanged, state, x, y |
|
|
|
|
|
|
|
|
|
def evalposition(sum_x, sum_y, delta_x, delta_y): |
|
|
|
|
sum_x = sum_x + delta_x |
|
|
|
|
sum_y = sum_y + delta_y |
|
|
|
|
if sum_x < 0: |
|
|
|
|
sum_x = 0 |
|
|
|
|
elif sum_x > 16384: |
|
|
|
|
sum_x = 16384 |
|
|
|
|
if sum_y < 0: |
|
|
|
|
sum_y = 0 |
|
|
|
|
elif sum_y > 8192: |
|
|
|
|
sum_y = 8192 |
|
|
|
|
return sum_x, sum_y |
|
|
|
|
|
|
|
|
|
def gameloop(dev1, dev2): |
|
|
|
|
state1 = 0 |
|
|
|
|
state2 = 0 |
|
|
|
|
x1 = 0 |
|
|
|
|
x2 = 0 |
|
|
|
|
y1 = 0 |
|
|
|
|
y2 = 0 |
|
|
|
|
player1_x = 0 |
|
|
|
|
player2_x = 0 |
|
|
|
|
player1_y = 0 |
|
|
|
|
player2_y = 0 |
|
|
|
|
return bChanged |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def eval_position(player): |
|
|
|
|
bChanged = False |
|
|
|
|
sum_x = player["x"] + player["delta_x"]/255 |
|
|
|
|
sum_y = player["y"] + player["delta_y"]/255 |
|
|
|
|
|
|
|
|
|
if sum_x < GAMEAREA_MIN_X: |
|
|
|
|
sum_x = GAMEAREA_MIN_X |
|
|
|
|
elif sum_x + player["w"] > GAMEAREA_MAX_X: |
|
|
|
|
sum_x = GAMEAREA_MAX_X - player["w"] |
|
|
|
|
|
|
|
|
|
if sum_y < GAMEAREA_MIN_Y: |
|
|
|
|
sum_y = GAMEAREA_MIN_Y |
|
|
|
|
elif sum_y + player["h"] > GAMEAREA_MAX_Y: |
|
|
|
|
sum_y = GAMEAREA_MAX_Y - player["h"] |
|
|
|
|
|
|
|
|
|
if (sum_x != player["x"]) or (sum_y != player["y"]): |
|
|
|
|
bChanged = True |
|
|
|
|
player["x"] = sum_x |
|
|
|
|
player["y"] = sum_y |
|
|
|
|
|
|
|
|
|
return bChanged |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def eval_object(obj): |
|
|
|
|
sum_x = obj["x"] + obj["delta_x"] |
|
|
|
|
sum_y = obj["y"] + obj["delta_y"] |
|
|
|
|
|
|
|
|
|
if sum_x < GAMEAREA_MIN_X: |
|
|
|
|
sum_x = GAMEAREA_MIN_X |
|
|
|
|
obj["delta_x"] = -obj["delta_x"] |
|
|
|
|
elif sum_x + obj["w"] > GAMEAREA_MAX_X: |
|
|
|
|
sum_x = GAMEAREA_MAX_X - obj["w"] |
|
|
|
|
obj["delta_x"] = -obj["delta_x"] |
|
|
|
|
|
|
|
|
|
if sum_y < GAMEAREA_MIN_Y: |
|
|
|
|
sum_y = GAMEAREA_MIN_Y |
|
|
|
|
obj["delta_y"] = -obj["delta_y"] |
|
|
|
|
elif sum_y + obj["h"] > GAMEAREA_MAX_Y: |
|
|
|
|
sum_y = GAMEAREA_MAX_Y - obj["h"] |
|
|
|
|
obj["delta_y"] = -obj["delta_y"] |
|
|
|
|
|
|
|
|
|
obj["x"] = sum_x |
|
|
|
|
obj["y"] = sum_y |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def draw_objects(ball, player1, player2): # Update objects on playground |
|
|
|
|
print("\rB: ", ball["x"], "/", ball["y"], end="") |
|
|
|
|
print(" P1: ", player1["x"], "/", player1["y"], " S:", hex(player1["state"]), " ", end="") |
|
|
|
|
print(" P2: ", player2["x"], "/", player2["y"], " S:", hex(player2["state"]), " ", end="") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def gameloop(ball, player1, player2): |
|
|
|
|
while True: |
|
|
|
|
bChanged, state1, x1, y1 = evalgamepad(dev1, state1, x1, y1) |
|
|
|
|
if (state1 & BTN_BASE4) > 0: # Exit? |
|
|
|
|
print("Player #1 aborted game") |
|
|
|
|
break |
|
|
|
|
bChanged, state2, x2, y2 = evalgamepad(dev2, state2, x2, y2) # Exit? |
|
|
|
|
if (state2 & BTN_BASE4) > 0: |
|
|
|
|
print("Player #2 aborted game") |
|
|
|
|
break |
|
|
|
|
player1_x, player1_y = evalposition(player1_x, player1_y, x1, y1) |
|
|
|
|
print("Player #1: ", player1_x," / ",player1_y) |
|
|
|
|
player2_x, player2_y = evalposition(player2_x, player2_y, x2, y2) |
|
|
|
|
print("Player #2: ", player2_x," / ",player2_y) |
|
|
|
|
# 1. Retrieve user entries |
|
|
|
|
bChanged = eval_gamepad(player1) |
|
|
|
|
if bChanged: |
|
|
|
|
if (player1["state"] & BTN_BASE4) > 0: # Exit? |
|
|
|
|
print("Player #1 aborted game") |
|
|
|
|
break |
|
|
|
|
else: |
|
|
|
|
print("Player #1: {}h".format(hex(player1["state"]))) |
|
|
|
|
bChanged = eval_gamepad(player2) # Exit? |
|
|
|
|
if bChanged: |
|
|
|
|
if (player2["state"] & BTN_BASE4) > 0: |
|
|
|
|
print("Player #2 aborted game") |
|
|
|
|
break |
|
|
|
|
else: |
|
|
|
|
print("Player #2: {}h".format(hex(player2["state"]))) |
|
|
|
|
|
|
|
|
|
# 2. Adjust player positions |
|
|
|
|
bChanged = eval_position(player1) |
|
|
|
|
if bChanged: |
|
|
|
|
print("Player #1: ", player1["x"], " / ", player1["y"]) |
|
|
|
|
bChanged = eval_position(player2) |
|
|
|
|
if bChanged: |
|
|
|
|
print("Player #2: ", player2["x"], " / ", player2["y"]) |
|
|
|
|
|
|
|
|
|
# 3. Adjust object positions |
|
|
|
|
eval_object(ball) |
|
|
|
|
|
|
|
|
|
# 4. Refresh game area drawing |
|
|
|
|
draw_objects(ball, player1, player2) |
|
|
|
|
|
|
|
|
|
# 5. Little delay for testing |
|
|
|
|
time.sleep(0.1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def init_gamearea(): # Create base playground |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def main(args): |
|
|
|
|
path1 = args[1] |
|
|
|
|
path2 = args[2] |
|
|
|
|
try: |
|
|
|
|
# Gamepad #1 init. |
|
|
|
|
fd1 = open(path1, "rb") |
|
|
|
|
fcntl.fcntl(fd1, fcntl.F_SETFL, os.O_NONBLOCK) |
|
|
|
|
dev1 = libevdev.Device(fd1) |
|
|
|
|
# Gamepad #2 init. |
|
|
|
|
fd2 = open(path2, "rb") |
|
|
|
|
fcntl.fcntl(fd2, fcntl.F_SETFL, os.O_NONBLOCK) |
|
|
|
|
dev2 = libevdev.Device(fd2) |
|
|
|
|
# Initialize |
|
|
|
|
init_gamearea() |
|
|
|
|
ball = init_object(10, 10, 15, 15, 2.0, 1.5) |
|
|
|
|
player1 = init_player(args[1]) |
|
|
|
|
player2 = init_player(args[2]) |
|
|
|
|
|
|
|
|
|
# Work ... |
|
|
|
|
gameloop(dev1, dev2) |
|
|
|
|
gameloop(ball, player1, player2) |
|
|
|
|
|
|
|
|
|
# Quit gracefully |
|
|
|
|
fd2.close() |
|
|
|
|
fd1.close() |
|
|
|
|
exit_player(player2) |
|
|
|
|
exit_player(player1) |
|
|
|
|
|
|
|
|
|
except KeyboardInterrupt: # Never comes ... (?!) |
|
|
|
|
pass |
|
|
|
|