add ps4 controller
This commit is contained in:
Binary file not shown.
@@ -9,17 +9,21 @@ import adsk.fusion
|
|||||||
import adsk.cam
|
import adsk.cam
|
||||||
import traceback
|
import traceback
|
||||||
import json
|
import json
|
||||||
|
from ...lib import hid
|
||||||
|
|
||||||
CMD_NAME = 'View Controller backend'
|
CMD_NAME = 'View Controller backend'
|
||||||
|
|
||||||
app = adsk.core.Application.get()
|
app = adsk.core.Application.get()
|
||||||
ui = app.userInterface
|
ui = app.userInterface
|
||||||
|
|
||||||
|
myThread = None
|
||||||
stopFlag = None
|
stopFlag = None
|
||||||
|
|
||||||
cameraViewEvent = 'CameraViewEventId'
|
cameraViewEvent = 'CameraViewEventId'
|
||||||
updateConstantsEvent = "UpdateConstantsEventId"
|
updateConstantsEvent = "UpdateConstantsEventId"
|
||||||
|
|
||||||
customEvents = []
|
customEvents = []
|
||||||
local_handlers = []
|
l_handlers = []
|
||||||
|
|
||||||
X_ROTATION = 0
|
X_ROTATION = 0
|
||||||
Y_ROTATION = 0
|
Y_ROTATION = 0
|
||||||
@@ -44,6 +48,7 @@ class UpdateConstantsEventHandler(adsk.core.CustomEventHandler):
|
|||||||
X_PAN = float(eventArgs["X_pan"])
|
X_PAN = float(eventArgs["X_pan"])
|
||||||
Y_PAN = float(eventArgs["Y_pan"])
|
Y_PAN = float(eventArgs["Y_pan"])
|
||||||
Z_PAN = float(eventArgs["Z_pan"])
|
Z_PAN = float(eventArgs["Z_pan"])
|
||||||
|
myThread.start()
|
||||||
|
|
||||||
|
|
||||||
# The event handler that responds to the custom event being fired.
|
# The event handler that responds to the custom event being fired.
|
||||||
@@ -93,9 +98,9 @@ class CameraViewEventHandler(adsk.core.CustomEventHandler):
|
|||||||
eye.transformBy(rotate_matrix)
|
eye.transformBy(rotate_matrix)
|
||||||
up.transformBy(rotate_matrix)
|
up.transformBy(rotate_matrix)
|
||||||
|
|
||||||
X_pan = float(eventArgs.get('X_pan', 0)) * X_pan
|
X_pan = float(eventArgs.get('X_pan', 0)) * X_PAN
|
||||||
Y_pan = float(eventArgs.get('Y_pan', 0)) * Y_pan
|
Y_pan = float(eventArgs.get('Y_pan', 0)) * Y_PAN
|
||||||
Z_pan = float(eventArgs.get('Z_pan', 0)) * Z_pan
|
Z_pan = float(eventArgs.get('Z_pan', 0)) * Z_PAN
|
||||||
if any([X_pan, Z_pan]):
|
if any([X_pan, Z_pan]):
|
||||||
move_vector = adsk.core.Vector3D.create(X_pan, 0, Z_pan)
|
move_vector = adsk.core.Vector3D.create(X_pan, 0, Z_pan)
|
||||||
move_vector.transformBy(rotate_matrix)
|
move_vector.transformBy(rotate_matrix)
|
||||||
@@ -105,7 +110,7 @@ class CameraViewEventHandler(adsk.core.CustomEventHandler):
|
|||||||
if Y_pan:
|
if Y_pan:
|
||||||
zoom = zoom + Y_pan * 10
|
zoom = zoom + Y_pan * 10
|
||||||
|
|
||||||
camera.isSmoothTransition = True
|
camera.isSmoothTransition = False
|
||||||
camera.eye = eye
|
camera.eye = eye
|
||||||
camera.upVector = up
|
camera.upVector = up
|
||||||
camera.target = target
|
camera.target = target
|
||||||
@@ -128,13 +133,30 @@ class ControllerThread(threading.Thread):
|
|||||||
self.stopped = event
|
self.stopped = event
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
futil.log(f'{CMD_NAME} ControllerThread started')
|
||||||
|
gamepad = hid.Device(vid=1356, pid=1476)
|
||||||
|
gamepad.nonblocking = True
|
||||||
# Every five seconds fire a custom event, passing a random number.
|
# Every five seconds fire a custom event, passing a random number.
|
||||||
while not self.stopped.wait(2):
|
while not self.stopped.wait(0.01):
|
||||||
futil.log(f'{CMD_NAME} Thread start sending data')
|
# futil.log(f'{CMD_NAME} Thread start sending data')
|
||||||
args = {'X_rotation': 0.0, 'Y_rotation': 0.0, 'Z_rotation': 0.0,
|
report = list(gamepad.read(128))
|
||||||
'X_pan': 0.0, 'Y_pan': 0.0, 'Z_pan': 0.0}
|
args = {
|
||||||
|
'X_rotation': 0.0,
|
||||||
|
'Y_rotation': self.convert(report[4], 10),
|
||||||
|
'Z_rotation': self.convert(report[3], 10),
|
||||||
|
'X_pan': self.convert(report[1], 10),
|
||||||
|
'Y_pan': self.convert(report[2], 10),
|
||||||
|
'Z_pan': 0.0
|
||||||
|
}
|
||||||
app.fireCustomEvent(cameraViewEvent, json.dumps(args))
|
app.fireCustomEvent(cameraViewEvent, json.dumps(args))
|
||||||
|
|
||||||
|
def convert(self, input, dedzone) -> float:
|
||||||
|
normal: float = input - 127
|
||||||
|
if abs(normal) < dedzone:
|
||||||
|
return 0.0
|
||||||
|
normal = normal / 128
|
||||||
|
return normal
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
|
|
||||||
@@ -144,26 +166,25 @@ def start():
|
|||||||
customEvents.append(app.registerCustomEvent(cameraViewEvent))
|
customEvents.append(app.registerCustomEvent(cameraViewEvent))
|
||||||
onCameraViewEvent = CameraViewEventHandler()
|
onCameraViewEvent = CameraViewEventHandler()
|
||||||
customEvents[0].add(onCameraViewEvent)
|
customEvents[0].add(onCameraViewEvent)
|
||||||
local_handlers.append(onCameraViewEvent)
|
l_handlers.append(onCameraViewEvent)
|
||||||
futil.log(f'{CMD_NAME} CameraViewEvent register')
|
futil.log(f'{CMD_NAME} CameraViewEvent register')
|
||||||
|
|
||||||
customEvents.append(app.registerCustomEvent(updateConstantsEvent))
|
customEvents.append(app.registerCustomEvent(updateConstantsEvent))
|
||||||
onUpadateConstantEvent = UpdateConstantsEventHandler()
|
onUpadateConstantEvent = UpdateConstantsEventHandler()
|
||||||
customEvents[1].add(onUpadateConstantEvent)
|
customEvents[1].add(onUpadateConstantEvent)
|
||||||
local_handlers.append(onUpadateConstantEvent)
|
l_handlers.append(onUpadateConstantEvent)
|
||||||
futil.log(f'{CMD_NAME} UpdateConstantsEvent register')
|
futil.log(f'{CMD_NAME} UpdateConstantsEvent register')
|
||||||
|
|
||||||
# Create a new thread for the other processing.
|
# Create a new thread for the other processing.
|
||||||
global stopFlag
|
global stopFlag, myThread
|
||||||
stopFlag = threading.Event()
|
stopFlag = threading.Event()
|
||||||
myThread = ControllerThread(stopFlag)
|
myThread = ControllerThread(stopFlag)
|
||||||
# myThread.start()
|
# myThread.start()
|
||||||
futil.log(f'{CMD_NAME} ControllerThread started')
|
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
def stop():
|
||||||
try:
|
try:
|
||||||
for event, handler in zip(customEvents, local_handlers):
|
for event, handler in zip(customEvents, l_handlers):
|
||||||
event.remove(handler)
|
event.remove(handler)
|
||||||
# if local_handlers.count:
|
# if local_handlers.count:
|
||||||
# customEvent.remove(local_handlers[0])
|
# customEvent.remove(local_handlers[0])
|
||||||
|
|||||||
235
ControllByPs4/lib/hid/__init__.py
Normal file
235
ControllByPs4/lib/hid/__init__.py
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
import os
|
||||||
|
import ctypes
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['HIDException', 'DeviceInfo', 'Device', 'enumerate']
|
||||||
|
|
||||||
|
dir = os.path.dirname(__file__).replace("/", "\\")
|
||||||
|
|
||||||
|
hidapi = None
|
||||||
|
library_paths = (
|
||||||
|
'libhidapi-hidraw.so',
|
||||||
|
'libhidapi-hidraw.so.0',
|
||||||
|
'libhidapi-libusb.so',
|
||||||
|
'libhidapi-libusb.so.0',
|
||||||
|
'libhidapi-iohidmanager.so',
|
||||||
|
'libhidapi-iohidmanager.so.0',
|
||||||
|
'libhidapi.dylib',
|
||||||
|
'hidapi.dll',
|
||||||
|
'libhidapi-0.dll'
|
||||||
|
)
|
||||||
|
|
||||||
|
for lib in library_paths:
|
||||||
|
try:
|
||||||
|
hidapi = ctypes.cdll.LoadLibrary(os.path.join(dir, lib))
|
||||||
|
break
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
error = "Unable to load any of the following libraries:{}"\
|
||||||
|
.format(' '.join(library_paths))
|
||||||
|
raise ImportError(error)
|
||||||
|
|
||||||
|
|
||||||
|
hidapi.hid_init()
|
||||||
|
atexit.register(hidapi.hid_exit)
|
||||||
|
|
||||||
|
|
||||||
|
class HIDException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceInfo(ctypes.Structure):
|
||||||
|
def as_dict(self):
|
||||||
|
ret = {}
|
||||||
|
for name, type in self._fields_:
|
||||||
|
if name == 'next':
|
||||||
|
continue
|
||||||
|
ret[name] = getattr(self, name, None)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
DeviceInfo._fields_ = [
|
||||||
|
('path', ctypes.c_char_p),
|
||||||
|
('vendor_id', ctypes.c_ushort),
|
||||||
|
('product_id', ctypes.c_ushort),
|
||||||
|
('serial_number', ctypes.c_wchar_p),
|
||||||
|
('release_number', ctypes.c_ushort),
|
||||||
|
('manufacturer_string', ctypes.c_wchar_p),
|
||||||
|
('product_string', ctypes.c_wchar_p),
|
||||||
|
('usage_page', ctypes.c_ushort),
|
||||||
|
('usage', ctypes.c_ushort),
|
||||||
|
('interface_number', ctypes.c_int),
|
||||||
|
('next', ctypes.POINTER(DeviceInfo)),
|
||||||
|
]
|
||||||
|
|
||||||
|
hidapi.hid_init.argtypes = []
|
||||||
|
hidapi.hid_init.restype = ctypes.c_int
|
||||||
|
hidapi.hid_exit.argtypes = []
|
||||||
|
hidapi.hid_exit.restype = ctypes.c_int
|
||||||
|
hidapi.hid_enumerate.argtypes = [ctypes.c_ushort, ctypes.c_ushort]
|
||||||
|
hidapi.hid_enumerate.restype = ctypes.POINTER(DeviceInfo)
|
||||||
|
hidapi.hid_free_enumeration.argtypes = [ctypes.POINTER(DeviceInfo)]
|
||||||
|
hidapi.hid_free_enumeration.restype = None
|
||||||
|
hidapi.hid_open.argtypes = [ctypes.c_ushort, ctypes.c_ushort, ctypes.c_wchar_p]
|
||||||
|
hidapi.hid_open.restype = ctypes.c_void_p
|
||||||
|
hidapi.hid_open_path.argtypes = [ctypes.c_char_p]
|
||||||
|
hidapi.hid_open_path.restype = ctypes.c_void_p
|
||||||
|
hidapi.hid_write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_write.restype = ctypes.c_int
|
||||||
|
hidapi.hid_read_timeout.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t, ctypes.c_int]
|
||||||
|
hidapi.hid_read_timeout.restype = ctypes.c_int
|
||||||
|
hidapi.hid_read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_read.restype = ctypes.c_int
|
||||||
|
hidapi.hid_get_input_report.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_get_input_report.restype = ctypes.c_int
|
||||||
|
hidapi.hid_set_nonblocking.argtypes = [ctypes.c_void_p, ctypes.c_int]
|
||||||
|
hidapi.hid_set_nonblocking.restype = ctypes.c_int
|
||||||
|
hidapi.hid_send_feature_report.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int]
|
||||||
|
hidapi.hid_send_feature_report.restype = ctypes.c_int
|
||||||
|
hidapi.hid_get_feature_report.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_get_feature_report.restype = ctypes.c_int
|
||||||
|
hidapi.hid_close.argtypes = [ctypes.c_void_p]
|
||||||
|
hidapi.hid_close.restype = None
|
||||||
|
hidapi.hid_get_manufacturer_string.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_get_manufacturer_string.restype = ctypes.c_int
|
||||||
|
hidapi.hid_get_product_string.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_get_product_string.restype = ctypes.c_int
|
||||||
|
hidapi.hid_get_serial_number_string.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_get_serial_number_string.restype = ctypes.c_int
|
||||||
|
hidapi.hid_get_indexed_string.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.c_int, ctypes.c_wchar_p, ctypes.c_size_t]
|
||||||
|
hidapi.hid_get_indexed_string.restype = ctypes.c_int
|
||||||
|
hidapi.hid_error.argtypes = [ctypes.c_void_p]
|
||||||
|
hidapi.hid_error.restype = ctypes.c_wchar_p
|
||||||
|
|
||||||
|
|
||||||
|
def enumerate(vid=0, pid=0):
|
||||||
|
ret = []
|
||||||
|
info = hidapi.hid_enumerate(vid, pid)
|
||||||
|
c = info
|
||||||
|
|
||||||
|
while c:
|
||||||
|
ret.append(c.contents.as_dict())
|
||||||
|
c = c.contents.next
|
||||||
|
|
||||||
|
hidapi.hid_free_enumeration(info)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class Device(object):
|
||||||
|
def __init__(self, vid=None, pid=None, serial=None, path=None):
|
||||||
|
if path:
|
||||||
|
self.__dev = hidapi.hid_open_path(path)
|
||||||
|
elif serial:
|
||||||
|
serial = ctypes.create_unicode_buffer(serial)
|
||||||
|
self.__dev = hidapi.hid_open(vid, pid, serial)
|
||||||
|
elif vid and pid:
|
||||||
|
self.__dev = hidapi.hid_open(vid, pid, None)
|
||||||
|
else:
|
||||||
|
raise ValueError('specify vid/pid or path')
|
||||||
|
|
||||||
|
if not self.__dev:
|
||||||
|
raise HIDException('unable to open device')
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def __hidcall(self, function, *args, **kwargs):
|
||||||
|
if not self.__dev:
|
||||||
|
raise HIDException('device closed')
|
||||||
|
|
||||||
|
ret = function(*args, **kwargs)
|
||||||
|
|
||||||
|
if ret == -1:
|
||||||
|
err = hidapi.hid_error(self.__dev)
|
||||||
|
raise HIDException(err)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def __readstring(self, function, max_length=255):
|
||||||
|
buf = ctypes.create_unicode_buffer(max_length)
|
||||||
|
self.__hidcall(function, self.__dev, buf, max_length)
|
||||||
|
return buf.value
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
return self.__hidcall(hidapi.hid_write, self.__dev, data, len(data))
|
||||||
|
|
||||||
|
def read(self, size, timeout=None):
|
||||||
|
data = ctypes.create_string_buffer(size)
|
||||||
|
|
||||||
|
if timeout is None:
|
||||||
|
size = self.__hidcall(hidapi.hid_read, self.__dev, data, size)
|
||||||
|
else:
|
||||||
|
size = self.__hidcall(
|
||||||
|
hidapi.hid_read_timeout, self.__dev, data, size, timeout)
|
||||||
|
|
||||||
|
return data.raw[:size]
|
||||||
|
|
||||||
|
def get_input_report(self, report_id, size):
|
||||||
|
data = ctypes.create_string_buffer(size)
|
||||||
|
|
||||||
|
# Pass the id of the report to be read.
|
||||||
|
data[0] = bytearray((report_id,))
|
||||||
|
|
||||||
|
size = self.__hidcall(
|
||||||
|
hidapi.hid_get_input_report, self.__dev, data, size)
|
||||||
|
return data.raw[:size]
|
||||||
|
|
||||||
|
def send_feature_report(self, data):
|
||||||
|
return self.__hidcall(hidapi.hid_send_feature_report,
|
||||||
|
self.__dev, data, len(data))
|
||||||
|
|
||||||
|
def get_feature_report(self, report_id, size):
|
||||||
|
data = ctypes.create_string_buffer(size)
|
||||||
|
|
||||||
|
# Pass the id of the report to be read.
|
||||||
|
data[0] = bytearray((report_id,))
|
||||||
|
|
||||||
|
size = self.__hidcall(
|
||||||
|
hidapi.hid_get_feature_report, self.__dev, data, size)
|
||||||
|
return data.raw[:size]
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.__dev:
|
||||||
|
hidapi.hid_close(self.__dev)
|
||||||
|
self.__dev = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nonblocking(self):
|
||||||
|
return getattr(self, '_nonblocking', 0)
|
||||||
|
|
||||||
|
@nonblocking.setter
|
||||||
|
def nonblocking(self, value):
|
||||||
|
self.__hidcall(hidapi.hid_set_nonblocking, self.__dev, value)
|
||||||
|
setattr(self, '_nonblocking', value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def manufacturer(self):
|
||||||
|
return self.__readstring(hidapi.hid_get_manufacturer_string)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def product(self):
|
||||||
|
return self.__readstring(hidapi.hid_get_product_string)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serial(self):
|
||||||
|
return self.__readstring(hidapi.hid_get_serial_number_string)
|
||||||
|
|
||||||
|
def get_indexed_string(self, index, max_length=255):
|
||||||
|
buf = ctypes.create_unicode_buffer(max_length)
|
||||||
|
self.__hidcall(hidapi.hid_get_indexed_string,
|
||||||
|
self.__dev, index, buf, max_length)
|
||||||
|
return buf.value
|
||||||
BIN
ControllByPs4/lib/hid/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
ControllByPs4/lib/hid/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
ControllByPs4/lib/hid/hidapi.dll
Normal file
BIN
ControllByPs4/lib/hid/hidapi.dll
Normal file
Binary file not shown.
BIN
ControllByPs4/lib/hid/hidapi.lib
Normal file
BIN
ControllByPs4/lib/hid/hidapi.lib
Normal file
Binary file not shown.
BIN
ControllByPs4/lib/hid/hidapi.pdb
Normal file
BIN
ControllByPs4/lib/hid/hidapi.pdb
Normal file
Binary file not shown.
Reference in New Issue
Block a user