Last active
December 2, 2023 13:49
-
-
Save drscotthawley/63369e77796f2a24cefbbe0245a467cf to your computer and use it in GitHub Desktop.
Revisions
-
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 0 additions and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -18,7 +18,6 @@ import numpy as np pygame.font.init() GAME_FONT = pygame.font.SysFont(None, 48) def stickchange(stick, center=[128,128], -
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,6 +10,7 @@ # 4. Run this script! # working on making the mic work. will require a usb connection. # No idea how to do the touchpad yet. import os import pygame -
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,8 +5,8 @@ # Instructions: # 1. Pair the DualSense controller with your computer # 2. Install hidapi system binary, e.g. on Mac: brew install hidapi # 3. Install Python packages: pip install hidapi pygame numpy # 4. Run this script! # working on making the mic work. will require a usb connection. -
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,7 @@ # Instructions: # 1. Pair the DualSense controller with your computer # 2. Install hidapi system binary, e.g. on Mac: brew install hidapi numpy # 3. Install Python packages: pip install hidapi pygame # 4. Run this script! -
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,7 +6,7 @@ # Instructions: # 1. Pair the DualSense controller with your computer # 2. Install hidapi system binary, e.g. on Mac: brew install hidapi # 3. Install Python packages: pip install hidapi pygame # 4. Run this script! # working on making the mic work. will require a usb connection. -
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 31 additions and 30 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,8 +1,20 @@ #! /usr/bin/env python # OS-Agnostic PS5 DualSense Controller Listener # Author: Scott H. Hawley # Instructions: # 1. Pair the DualSense controller with your computer # 2. Install hidapi system binary, e.g. on Mac: brew install hidapi # 3. Install hidapi Python package: pip install hidapi # 4. Run this script! # working on making the mic work. will require a usb connection. import os import pygame import hid import numpy as np pygame.font.init() GAME_FONT = pygame.font.Font(pygame.font.get_default_font(), 36) @@ -27,20 +39,25 @@ def get_controller_ids(): def get_controller_state(report, debug=False): connection = "bluetooth" if len(report) == 64: connection = "usb" elif len(report) != 8: assert False, "Unknown connection type" report = np.array(report) lstick, rstick = report[1:3], report[3:5] button_pad_ind = 8 if 'usb'==connection else 5 dpad_state = report[button_pad_ind] & 0x0F [dpadu, dpadr, dpadd, dpadl] = [dpad_state==y for y in [0,2,4,6]] shapes = report[button_pad_ind] [cross, circle, square, triangle] = [(shapes & (1<<y))!=0 for y in [5,6,4,7]] button_id = 9 if 'usb'==connection else 6 [l1,r1,l2,r2,l3,r3] = [report[button_id] & y for y in [1,2,4,8,64,128]] # 16 & 32 go where? state = {'lstick':lstick, 'rstick':rstick, 'dpadu':dpadu, 'dpadr':dpadr, 'dpadd':dpadd, 'dpadl':dpadl, 'cross':cross, 'circle':circle, 'square':square, 'triangle':triangle, @@ -60,11 +77,8 @@ def get_controller_state(report, debug=False): def draw_buttons_and_joysticks(window, state): # Draw buttons (X, Circle, Square, Triangle) img = GAME_FONT.render("L1", True, 'red' if state['l1'] else 'grey') window.blit(img, (185, 60)) img = GAME_FONT.render("L2", True, 'red' if state['l2'] else 'grey') @@ -109,11 +123,7 @@ def draw_buttons_and_joysticks(window, state): def draw_controller(window): pass # eh skip it for now def main(): @@ -142,18 +152,8 @@ def main(): report = gamepad.read(64) if report: report = np.array(report) state = get_controller_state(report) window.fill((0, 0, 0)) # Fill the screen with black draw_controller(window) # Draw the controller @@ -164,3 +164,4 @@ def main(): if __name__ == "__main__": main() -
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 0 additions and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -17,7 +17,6 @@ def stickchange(stick, center=[128,128], return None def get_controller_ids(): vendor_id, product_id = None, None for device in hid.enumerate(): if "DualSense" in device['product_string']: -
drscotthawley revised this gist
Dec 2, 2023 . 1 changed file with 132 additions and 50 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,20 +1,12 @@ import os import hid import numpy as np import pygame # used for the ugly gui ;-) pygame.font.init() GAME_FONT = pygame.font.Font(pygame.font.get_default_font(), 36) GAME_FONT = pygame.font.SysFont(None, 48) def stickchange(stick, center=[128,128], tol=5, # tolerance in "pixels" b/c sticks sometimes get stuck a bit off-center @@ -35,51 +27,141 @@ def get_controller_ids(): return vendor_id, product_id def get_controller_state(report, debug=False): report = np.array(report) lstick, rstick = report[1:3], report[3:5] #lstick = stickchange(lstick) #rstick = stickchange(rstick) dpad_state = report[5] & 0x0F if debug: print("dpad_state =",dpad_state) [dpadu, dpadr, dpadd, dpadl] = [dpad_state==y for y in [0,2,4,6]] shapes = report[5] [cross, circle, square, triangle] = [(shapes & (1<<y))!=0 for y in [5,6,4,7]] LRbuttons = report[6] [l1,r1,l2,r2,l3,r3] = [LRbuttons & y for y in [1,2,4,8,64,128]] # 16 & 32 go where? state = {'lstick':lstick, 'rstick':rstick, 'dpadu':dpadu, 'dpadr':dpadr, 'dpadd':dpadd, 'dpadl':dpadl, 'cross':cross, 'circle':circle, 'square':square, 'triangle':triangle, 'l1':l1, 'r1':r1, 'l2':l2, 'r2':r2, 'l3':l3,'r3':r3,} if debug: if lstick is not None: print(f"lstick = {lstick}, ",end="",flush=True) if rstick is not None: print(f"rstick = {rstick}, ",end="",flush=True) buttons = [dpadu, dpadr, dpadd, dpadl, cross, circle, square, triangle,l1,r1,l2,r2,l3,r3] for button, label in zip(buttons, ["DPadU","DPadR","DpadD","DPadL","Cross","Circle","Square","Triangle","L1","R1","L2","R2","L3","R3"]): if button: print(f"{label}, ",end="",flush=True) return state def draw_buttons_and_joysticks(window, state): #pygame.font.init() # you have to call this at the start, # if you want to use this module. #my_font = pygame.font.SysFont('Comic Sans MS', 30) # Draw buttons (X, Circle, Square, Triangle) img = GAME_FONT.render("L1", True, 'red' if state['l1'] else 'grey') window.blit(img, (185, 60)) img = GAME_FONT.render("L2", True, 'red' if state['l2'] else 'grey') window.blit(img, (185, 10)) img = GAME_FONT.render("R1", True, 'red' if state['r1'] else 'grey') window.blit(img, (585, 60)) img = GAME_FONT.render("R2", True, 'red' if state['r2'] else 'grey') window.blit(img, (585, 10)) img = GAME_FONT.render("Δ", True, 'red' if state['triangle'] else 'grey') window.blit(img, (600, 150)) #img = GAME_FONT.render("[]", True, 'red' if state['square'] else 'grey') #window.blit(img, (550, 200)) pygame.draw.rect(window, 'red' if state['square'] else 'grey', (550, 205, 20, 20)) img = GAME_FONT.render("O", True, 'red' if state['circle'] else 'grey') window.blit(img, (650, 200)) img = GAME_FONT.render("X", True, 'red' if state['cross'] else 'grey') window.blit(img, (600, 250)) img = GAME_FONT.render("^", True, 'red' if state['dpadu'] else 'grey') window.blit(img, (200, 150)) img = GAME_FONT.render("<-", True, 'red' if state['dpadl'] else 'grey') window.blit(img, (150, 200)) img = GAME_FONT.render("->", True, 'red' if state['dpadr'] else 'grey') window.blit(img, (250, 200)) img = GAME_FONT.render("V", True, 'red' if state['dpadd'] else 'grey') window.blit(img, (200, 250)) # Draw joysticks lcenter, rcenter = np.array((300,400)), np.array((500, 400)) scale = 0.5 lstickpos = lcenter + scale*(np.array(state['lstick']) - np.array((128,128))) pygame.draw.circle(window, 'grey', lcenter, 5) # left center dot pygame.draw.circle(window, 'red' if state['l3'] else 'blue', lstickpos, 20) # left active dot rstickpos = rcenter + scale*(np.array(state['rstick']) - np.array((128,128))) pygame.draw.circle(window, 'grey', rcenter, 5) # right center dot pygame.draw.circle(window, 'red' if state['r3'] else 'blue', rstickpos, 20) # left active dot def draw_controller(window): pass #pygame.draw.rect(window, 'darkgrey', (250, 150, 500, 300)) # White rectangle #font = pygame.font.SysFont(None, 24) #img = GAME_FONT.render('hello', True, 'blue') #window.blit(img, (20, 20)) def main(): vendor_id, product_id = get_controller_ids() assert (vendor_id is not None) and (product_id is not None), "No DualSense controller found." gamepad = hid.device() gamepad.open(vendor_id, product_id) gamepad.set_nonblocking(True) pygame.init() width, height = 800, 500 window = pygame.display.set_mode((width, height)) pygame.display.set_caption("PS5 Controller GUI") running = True default, state = None, None # save the non-active state of the controller while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False report = gamepad.read(64) if report: report = np.array(report) if default is None: default = report # save initial state as defeault if not np.array_equal( report[:7] , default[:7]): # if anything changed state = get_controller_state(report) #for k, v in state.items(): # if (v is not None) and (k not in ['lstick','rstick']) and (v): # if v!=False: print(f"{k}={v} ",end="", flush=False) # elif (k in ['lstick','rstick']) and (v is not None): # print(f"{k}={v}") #print("") window.fill((0, 0, 0)) # Fill the screen with black draw_controller(window) # Draw the controller if state: draw_buttons_and_joysticks(window, state) pygame.display.flip() # Update the screen with what we've drawn. pygame.quit() if __name__ == "__main__": main() -
drscotthawley revised this gist
Dec 1, 2023 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,6 +9,10 @@ # 3. Install hidapi Python package: pip install hidapi # 4. Run this script! # NB: This currently doesn't make use of the microphone but I'm working on that. # The mic doesn't work over bluetooth, only via a wired connection to the machine, # after which it just appears as a normal system audio input device. import hid import numpy as np -
drscotthawley created this gist
Dec 1, 2023 .There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,81 @@ #! /usr/bin/env python # OS-Agnostic PS5 DualSense Controller Listener # Author: Scott H. Hawley # Instructions: # 1. Pair the DualSense controller with your computer # 2. Install hidapi system binary, e.g. on Mac: brew install hidapi # 3. Install hidapi Python package: pip install hidapi # 4. Run this script! import hid import numpy as np def stickchange(stick, center=[128,128], tol=5, # tolerance in "pixels" b/c sticks sometimes get stuck a bit off-center ): for ax in [0,1]: # x ad y axes if stick[ax] < center[ax]-tol or stick[ax] > center[ax]+tol: return stick return None def get_controller_ids(): # print whichever device is the DualSense Controller vendor_id, product_id = None, None for device in hid.enumerate(): if "DualSense" in device['product_string']: vendor_id, product_id = device['vendor_id'], device['product_id'] print(f"Found: {device['product_string']} at 0x{device['vendor_id']:04x}:0x{device['product_id']:04x}") break return vendor_id, product_id if __name__ == '__main__': vendor_id, product_id = get_controller_ids() assert (vendor_id is not None) and (product_id is not None), "No DualSense controller found." gamepad = hid.device() gamepad.open(vendor_id, product_id) gamepad.set_nonblocking(True) default = None # safe the non-active state of the controller print("Listening...") while True: report = gamepad.read(64) # get the tate of the controller if report: report = np.array(report) if default is None: default = report # save initial state as defeault if not np.array_equal( report[:7] , default[:7]): # if anything changed ##-----0 get values of sticks and buttons lstick, rstick = report[1:3], report[3:5] lstick = stickchange(lstick) dpad_state = report[5] & 0x0F [dpadu, dpadr, dpadd, dpadl] = [dpad_state==y for y in [0,2,4,6]] shapes = report[5] [cross, circle, square, triangle] = [(shapes & (1<<y))!=0 for y in [5,6,4,7]] LRbuttons = report[6] [l1,r1,l2,r2,l3,r3] = [LRbuttons & y for y in [1,2,4,8,64,128]] # 16 & 32 go where? ##------- print out our values for sticks and buttons # not sure what bits for 16 and 32 do so print them out... if (LRbuttons & 16) or (LRbuttons & 32): print("report[6] =",report[6]) if lstick is not None: print(f"lstick = {lstick}, ",end="",flush=True) rstick = stickchange(rstick) if rstick is not None: print(f"rstick = {rstick}, ",end="",flush=True) buttons = [dpadu, dpadr, dpadd, dpadl, cross, circle, square, triangle,l1,r1,l2,r2,l3,r3] for button, label in zip(buttons, ["DPadU","DPadR","DpadD","DPadL","Cross","Circle","Square","Triangle","L1","R1","L2","R2","L3","R3"]): if button: print(f"{label}, ",end="",flush=True) if any(y != False for y in buttons+[lstick is not None,rstick is not None]): print("") # newline