20 Commits

Author SHA1 Message Date
Florian Kaiser
f5529f1463 Add state for microphone button 2021-03-07 21:40:55 +01:00
Florian Kaiser
b3ff9fd375 Update 0.5.2
- Added Microphone mute
- changed MicrphoneLED function to boolean instead of int parameter
- using diffrent hidapi library for interacting with c library to get length of reports from device for bt support later
2021-03-07 21:21:01 +01:00
Flo
98b13798cd Merge pull request #19 from nougator/master
Fixed verbose
2021-01-17 21:10:33 +01:00
Nougator
b51c8b49f6 Fixed verbose. 2021-01-17 20:55:59 +01:00
Nougator
cdbe03ad56 Merge pull request #1 from flok/master
e
2021-01-17 20:55:19 +01:00
Flo
3a14ab3e7a Update setup.py 2021-01-10 14:53:56 +01:00
Flo
32f9042abb Merge pull request #16 from flok/hidapi_rewrite
Refactor hidapi
2021-01-10 14:08:31 +01:00
Florian Kaiser
4c86d71633 Refactor hidapi 2021-01-10 14:06:53 +01:00
Flo
9c79d961f1 Merge pull request #15 from TheComputerDan/master
Adapting Platform Agnostic Practices
2021-01-07 10:13:15 +01:00
Dan
c1c10e4eac Remove self reference 2021-01-06 18:25:15 -05:00
Dan
04ce807bc0 Added platform check for add_dll_directory 2021-01-03 22:16:31 -05:00
Dan
71a49da5d2 Removing accidently merged imports 2021-01-02 23:29:59 -05:00
Dan
f4e1d73dd3 Merge remote-tracking branch 'upstream/master'
Updating Fork with Master
2021-01-02 23:25:19 -05:00
Florian K
e766dca70f Deleting mypy action
Mypy gives weird results on github. Lets only work with it locally
2021-01-01 23:42:29 +01:00
Florian K
1e0b23da41 Update python-mypy.yml 2021-01-01 23:41:15 +01:00
Florian K
ff01788c89 Mypy enums import error fix 2021-01-01 23:39:54 +01:00
Florian K
c07b975bc5 Merge pull request #13 from nougator/patch-1
Update README.md
2021-01-01 23:16:08 +01:00
Nougator
7b0270fa7d Update README.md 2021-01-01 20:56:57 +01:00
Dan
83a37750d1 linting 2021-01-01 00:28:46 -05:00
Dan
bc0eb35c3c Moving winreg check to support other OSes 2020-12-31 20:39:50 -05:00
8 changed files with 77 additions and 67 deletions

View File

@@ -1,21 +0,0 @@
name: Mypy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
name: Mypy
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install mypy
- name: mypy
run: |
mypy pydualsense/

3
.gitignore vendored
View File

@@ -149,6 +149,9 @@ dmypy.json
!.vscode/extensions.json !.vscode/extensions.json
*.code-workspace *.code-workspace
### pycharm ###
.idea/*
# End of https://www.toptal.com/developers/gitignore/api/python,vscode # End of https://www.toptal.com/developers/gitignore/api/python,vscode
pydualsense/interface.py pydualsense/interface.py

View File

@@ -12,7 +12,7 @@ pip install pydualsense
```python ```python
from pydualsense import pydualsense from pydualsense import pydualsense, TriggerModes
ds = pydualsense() # open controller ds = pydualsense() # open controller
ds.init() # initialize controller ds.init() # initialize controller
@@ -30,7 +30,7 @@ Help wanted from people that want to use this and have feature requests. Just op
# dependecies # dependecies
- hid >= 1.0.4 - hidapi-usb >= 0.2.6
# Credits # Credits

View File

@@ -5,8 +5,8 @@ dualsense = pydualsense()
dualsense.init() dualsense.init()
# set color around touchpad to red # set color around touchpad to red
dualsense.light.setColorI(255,0,0) dualsense.light.setColorI(255,0,0)
# enable microphone indicator # mute microphone
dualsense.audio.setMicrophoneLED(1) dualsense.audio.setMicrophoneMute(True)
# set all player 1 indicator on # set all player 1 indicator on
dualsense.light.setPlayerID(PlayerID.player1) dualsense.light.setPlayerID(PlayerID.player1)
# sleep a little to see the result on the controller # sleep a little to see the result on the controller

View File

@@ -1,5 +1,8 @@
from enum import IntFlag from enum import IntFlag
class ConnectionType(IntFlag):
BT = 0x0,
USB = 0x1
class LedOptions(IntFlag): class LedOptions(IntFlag):
Off=0x0, Off=0x0,
PlayerLedBrightness=0x1, PlayerLedBrightness=0x1,

View File

@@ -0,0 +1,18 @@
import winreg
import sys
def check_hide() -> bool:
"""check if hidguardian is used and controller is hidden
"""
if sys.platform.startswith('win32'):
try:
access_reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
access_key = winreg.OpenKey(access_reg, 'SYSTEM\CurrentControlSet\Services\HidGuardian\Parameters', 0, winreg.KEY_READ)
affected_devices = winreg.QueryValueEx(access_key, 'AffectedDevices')[0]
if "054C" in affected_devices and "0CE6" in affected_devices:
return True
return False
except OSError as e:
pass
return False

View File

@@ -1,21 +1,17 @@
# needed for python > 3.8 # needed for python > 3.8
import os, sys import os, sys
if sys.version_info >= (3,8): if sys.platform.startswith('win32') and sys.version_info >= (3,8):
os.add_dll_directory(os.getcwd()) os.add_dll_directory(os.getcwd())
import hid # type: ignore import hidapi
from .enums import (LedOptions, PlayerID, from .enums import (LedOptions, PlayerID, PulseOptions, TriggerModes, Brightness, ConnectionType) # type: ignore
PulseOptions, TriggerModes, Brightness)
import threading import threading
import winreg
class pydualsense: class pydualsense:
def __init__(self, verbose: bool = False) -> None:# def __init__(self, verbose: bool = False) -> None:#
# TODO: maybe add a init function to not automatically allocate controller when class is declared # TODO: maybe add a init function to not automatically allocate controller when class is declared
self.verbose = verbose self.verbose = verbose
self.receive_buffer_size = 64
self.send_report_size = 48
self.leftMotor = 0 self.leftMotor = 0
self.rightMotor = 0 self.rightMotor = 0
@@ -24,7 +20,7 @@ class pydualsense:
def init(self): def init(self):
"""initialize module and device states """initialize module and device states
""" """
self.device: hid.Device = self.__find_device() self.device: hidapi.Device = self.__find_device()
self.light = DSLight() # control led light of ds self.light = DSLight() # control led light of ds
self.audio = DSAudio() # ds audio setting self.audio = DSAudio() # ds audio setting
self.triggerL = DSTrigger() # left trigger self.triggerL = DSTrigger() # left trigger
@@ -32,13 +28,25 @@ class pydualsense:
self.state = DSState() # controller states self.state = DSState() # controller states
self.conType = self.determineConnectionType() # determine USB or BT connection
# thread for receiving and sending # thread for receiving and sending
self.ds_thread = True self.ds_thread = True
self.report_thread = threading.Thread(target=self.sendReport) self.report_thread = threading.Thread(target=self.sendReport)
self.report_thread.start() self.report_thread.start()
self.init = True def determineConnectionType(self) -> ConnectionType:
if self.device._device.input_report_length == 64:
self.input_report_length = 64
self.output_report_length = 64
return ConnectionType.USB
elif self.device._device.input_report_length == 78:
self.input_report_length = 78
self.output_report_length = 78
return ConnectionType.BT
def close(self): def close(self):
""" """
@@ -48,24 +56,8 @@ class pydualsense:
self.report_thread.join() self.report_thread.join()
self.device.close() self.device.close()
def _check_hide(self) -> bool:
"""check if hidguardian is used and controller is hidden
"""
if sys.platform.startswith('win32'):
try:
access_reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
access_key = winreg.OpenKey(access_reg, 'SYSTEM\CurrentControlSet\Services\HidGuardian\Parameters', 0, winreg.KEY_READ)
affected_devices = winreg.QueryValueEx(access_key, 'AffectedDevices')[0]
if "054C" in affected_devices and "0CE6" in affected_devices:
return True
return False
except OSError as e:
print(e)
return False def __find_device(self) -> hidapi.Device:
def __find_device(self) -> hid.Device:
""" """
find HID device and open it find HID device and open it
@@ -78,19 +70,21 @@ class pydualsense:
""" """
# TODO: detect connection mode, bluetooth has a bigger write buffer # TODO: detect connection mode, bluetooth has a bigger write buffer
# TODO: implement multiple controllers working # TODO: implement multiple controllers working
if self._check_hide(): if sys.platform.startswith('win32'):
import pydualsense.hidguardian as hidguardian
if hidguardian.check_hide():
raise Exception('HIDGuardian detected. Delete the controller from HIDGuardian and restart PC to connect to controller') raise Exception('HIDGuardian detected. Delete the controller from HIDGuardian and restart PC to connect to controller')
detected_device: hid.Device = None detected_device: hidapi.Device = None
devices = hid.enumerate(vid=0x054c) devices = hidapi.enumerate(vendor_id=0x054c)
for device in devices: for device in devices:
if device['vendor_id'] == 0x054c and device['product_id'] == 0x0CE6: if device.vendor_id == 0x054c and device.product_id == 0x0CE6:
detected_device = device detected_device = device
if detected_device == None: if detected_device == None:
raise Exception('No device detected') raise Exception('No device detected')
dual_sense = hid.Device(vid=detected_device['vendor_id'], pid=detected_device['product_id']) dual_sense = hidapi.Device(vendor_id=detected_device.vendor_id, product_id=detected_device.product_id)
return dual_sense return dual_sense
def setLeftMotor(self, intensity: int): def setLeftMotor(self, intensity: int):
@@ -135,10 +129,10 @@ class pydualsense:
"""background thread handling the reading of the device and updating its states """background thread handling the reading of the device and updating its states
""" """
while self.ds_thread: while self.ds_thread:
# read data from the input report of the controller # read data from the input report of the controller
inReport = self.device.read(self.receive_buffer_size) inReport = self.device.read(self.input_report_length)
if self.verbose:
print(inReport)
# decrypt the packet and bind the inputs # decrypt the packet and bind the inputs
self.readInput(inReport) self.readInput(inReport)
@@ -191,6 +185,7 @@ class pydualsense:
misc2 = states[10] misc2 = states[10]
self.state.ps = (misc2 & (1 << 0)) != 0 self.state.ps = (misc2 & (1 << 0)) != 0
self.state.touchBtn = (misc2 & 0x02) != 0 self.state.touchBtn = (misc2 & 0x02) != 0
self.state.micBtn = (misc2 & 0x04) != 0
# trackpad touch # trackpad touch
@@ -233,7 +228,8 @@ class pydualsense:
Returns: Returns:
list: report to send to controller list: report to send to controller
""" """
outReport = [0] * 48 # create empty list with range of output report
outReport = [0] * self.output_report_length # create empty list with range of output report
# packet type # packet type
outReport[0] = 0x2 outReport[0] = 0x2
@@ -267,6 +263,8 @@ class pydualsense:
# set Micrphone LED, setting doesnt effect microphone settings # set Micrphone LED, setting doesnt effect microphone settings
outReport[9] = self.audio.microphone_led # [9] outReport[9] = self.audio.microphone_led # [9]
outReport[10] = 0x10 if self.audio.microphone_mute == True else 0x00
# add right trigger mode + parameters to packet # add right trigger mode + parameters to packet
outReport[11] = self.triggerR.mode.value outReport[11] = self.triggerR.mode.value
outReport[12] = self.triggerR.forces[0] outReport[12] = self.triggerR.forces[0]
@@ -488,15 +486,24 @@ class DSAudio:
This doesnt change the mute/unmutes the microphone itself. This doesnt change the mute/unmutes the microphone itself.
Args: Args:
value (int): On or off microphone LED value (bool): On or off microphone LED
Raises: Raises:
Exception: false state for the led Exception: false state for the led
""" """
if value > 1 or value < 0: if not isinstance(value, bool):
raise Exception('Microphone LED can only be on or off (0 .. 1)') raise TypeError('MicrophoneLED can only be a bool')
self.microphone_led = value self.microphone_led = value
def setMicrophoneMute(self, state):
if not isinstance(state, bool):
raise TypeError('state needs to be bool')
self.setMicrophoneLED(state) # set led accordingly
self.microphone_mute = state
class DSTrigger: class DSTrigger:
def __init__(self) -> None: def __init__(self) -> None:
# trigger modes # trigger modes

View File

@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
setup( setup(
name='pydualsense', name='pydualsense',
version='0.4.2', version='0.5.2.5',
description='use your DualSense (PS5) controller with python', description='use your DualSense (PS5) controller with python',
long_description=long_description, long_description=long_description,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
@@ -14,5 +14,5 @@ setup(
author='Florian K', author='Florian K',
license='MIT License', license='MIT License',
packages=setuptools.find_packages(), packages=setuptools.find_packages(),
install_requires=['hid>=1.0.4'] install_requires=['hidapi-usb', 'cffi']
) )