basic controller input from JSL

may need compiles for linux and mac
This commit is contained in:
minenice55 2022-07-19 18:50:35 -04:00
parent d4edc0d8f6
commit 8df667bfec
27 changed files with 1098 additions and 22 deletions

View File

@ -28,7 +28,7 @@ PluginImporter:
second: second:
enabled: 1 enabled: 1
settings: settings:
CPU: x86_64 CPU: AnyCPU
- first: - first:
Standalone: OSXUniversal Standalone: OSXUniversal
second: second:

View File

@ -28,7 +28,7 @@ PluginImporter:
second: second:
enabled: 1 enabled: 1
settings: settings:
CPU: x86_64 CPU: AnyCPU
- first: - first:
Standalone: OSXUniversal Standalone: OSXUniversal
second: second:

View File

@ -28,7 +28,7 @@ PluginImporter:
second: second:
enabled: 1 enabled: 1
settings: settings:
CPU: x86_64 CPU: AnyCPU
- first: - first:
Standalone: OSXUniversal Standalone: OSXUniversal
second: second:

8
Assets/Plugins/JSL.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5dfbaa1e85cf84f4c861f39c4d935a61
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,172 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
public static class JSL
{
public const int ButtonMaskUp = 0;
public const int ButtonMaskDown = 1;
public const int ButtonMaskLeft = 2;
public const int ButtonMaskRight = 3;
public const int ButtonMaskPlus = 4;
public const int ButtonMaskOptions = 4;
public const int ButtonMaskMinus = 5;
public const int ButtonMaskShare = 5;
public const int ButtonMaskLClick = 6;
public const int ButtonMaskRClick = 7;
public const int ButtonMaskL = 8;
public const int ButtonMaskR = 9;
public const int ButtonMaskZL = 10;
public const int ButtonMaskZR = 11;
public const int ButtonMaskS = 12;
public const int ButtonMaskE = 13;
public const int ButtonMaskW = 14;
public const int ButtonMaskN = 15;
public const int ButtonMaskHome = 16;
public const int ButtonMaskPS = 16;
public const int ButtonMaskCapture = 17;
public const int ButtonMaskTouchpadClick = 17;
public const int ButtonMaskSL = 18;
public const int ButtonMaskSR = 19;
public const int TypeJoyConLeft = 1;
public const int TypeJoyConRight = 2;
public const int TypeProController = 3;
public const int TypeDualShock4 = 4;
public const int TypeDualSense = 5;
public const int SplitLeft = 1;
public const int SplitRight = 2;
public const int SplitFull = 3;
// PS5 Player maps for the DS Player Lightbar
public const int DS5P1 = 4;
public const int DS5P2 = 10;
public const int DS5P3 = 21;
public const int DS5P4 = 27;
public const int DS5P5 = 31;
[StructLayout(LayoutKind.Sequential)]
public struct JOY_SHOCK_STATE
{
public int buttons;
public float lTrigger;
public float rTrigger;
public float stickLX;
public float stickLY;
public float stickRX;
public float stickRY;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMU_STATE
{
public float accelX;
public float accelY;
public float accelZ;
public float gyroX;
public float gyroY;
public float gyroZ;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOTION_STATE {
float quatW;
float quatX;
float quatY;
float quatZ;
float accelX;
float accelY;
float accelZ;
float gravX;
float gravY;
float gravZ;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOUCH_STATE {
int t0Id;
int t1Id;
bool t0Down;
bool t1Down;
float t0X;
float t0Y;
float t1X;
float t1Y;
}
public delegate void EventCallback(int handle, JOY_SHOCK_STATE state, JOY_SHOCK_STATE lastState,
IMU_STATE imuState, IMU_STATE lastImuState, float deltaTime);
[DllImport("JoyShockLibrary")]
public static extern int JslConnectDevices();
[DllImport("JoyShockLibrary")]
public static extern int JslGetConnectedDeviceHandles(int[] deviceHandleArray, int size);
[DllImport("JoyShockLibrary")]
public static extern void JslDisconnectAndDisposeAll();
[DllImport("JoyShockLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern JOY_SHOCK_STATE JslGetSimpleState(int deviceId);
[DllImport("JoyShockLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern IMU_STATE JslGetIMUState(int deviceId);
[DllImport("JoyShockLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern MOTION_STATE JslGetMotionState(int deviceId);
[DllImport("JoyShockLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern TOUCH_STATE JslGetTouchState(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern float JslGetStickStep(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern float JslGetTriggerStep(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern float JslGetPollRate(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern float JslGetTouchId(int deviceId, bool secondTouch = false);
[DllImport("JoyShockLibrary")]
public static extern float JslGetTouchDown(int deviceId, bool secondTouch = false);
[DllImport("JoyShockLibrary")]
public static extern float JslGetTouchX(int deviceId, bool secondTouch = false);
[DllImport("JoyShockLibrary")]
public static extern float JslGetTouchY(int deviceId, bool secondTouch = false);
[DllImport("JoyShockLibrary")]
public static extern void JslResetContinuousCalibration(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern void JslStartContinuousCalibration(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern void JslPauseContinuousCalibration(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern void JslGetCalibrationOffset(int deviceId, ref float xOffset, ref float yOffset, ref float zOffset);
[DllImport("JoyShockLibrary")]
public static extern void JslGetCalibrationOffset(int deviceId, float xOffset, float yOffset, float zOffset);
[DllImport("JoyShockLibrary")]
public static extern void JslSetCallback(EventCallback callback);
[DllImport("JoyShockLibrary")]
public static extern void JslSetTouchCallback(EventCallback callback);
[DllImport("JoyShockLibrary")]
public static extern int JslGetControllerType(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern int JslGetControllerSplitType(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern int JslGetControllerColour(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern int JslGetControllerButtonColour(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern int JslGetControllerLeftGripColour(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern int JslGetControllerRightGripColour(int deviceId);
[DllImport("JoyShockLibrary")]
public static extern void JslSetLightColour(int deviceId, int colour);
[DllImport("JoyShockLibrary")]
public static extern void JslSetRumble(int deviceId, int smallRumble, int bigRumble);
[DllImport("JoyShockLibrary")]
public static extern void JslSetRumbleFrequency(int deviceId, float smallRumble, float bigRumble, float smallFrequency, float bigFrequency);
[DllImport("JoyShockLibrary")]
public static extern void JslSetPlayerNumber(int deviceId, int number);
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dce4133e93426bb40a13278c4f90e742
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,217 @@
// JoyShockLibrary.h - Contains declarations of functions
#pragma once
#if _MSC_VER // this is defined when compiling with Visual Studio
#define JOY_SHOCK_API __declspec(dllexport) // Visual Studio needs annotating exported functions with this
#else
#define JOY_SHOCK_API // XCode does not need annotating exported functions, so define is empty
#endif
#define JS_TYPE_JOYCON_LEFT 1
#define JS_TYPE_JOYCON_RIGHT 2
#define JS_TYPE_PRO_CONTROLLER 3
#define JS_TYPE_DS4 4
#define JS_TYPE_DS 5
#define JS_SPLIT_TYPE_LEFT 1
#define JS_SPLIT_TYPE_RIGHT 2
#define JS_SPLIT_TYPE_FULL 3
#define JSMASK_UP 0x00001
#define JSMASK_DOWN 0x00002
#define JSMASK_LEFT 0x00004
#define JSMASK_RIGHT 0x00008
#define JSMASK_PLUS 0x00010
#define JSMASK_OPTIONS 0x00010
#define JSMASK_MINUS 0x00020
#define JSMASK_SHARE 0x00020
#define JSMASK_LCLICK 0x00040
#define JSMASK_RCLICK 0x00080
#define JSMASK_L 0x00100
#define JSMASK_R 0x00200
#define JSMASK_ZL 0x00400
#define JSMASK_ZR 0x00800
#define JSMASK_S 0x01000
#define JSMASK_E 0x02000
#define JSMASK_W 0x04000
#define JSMASK_N 0x08000
#define JSMASK_HOME 0x10000
#define JSMASK_PS 0x10000
#define JSMASK_CAPTURE 0x20000
#define JSMASK_TOUCHPAD_CLICK 0x20000
#define JSMASK_MIC 0x40000
#define JSMASK_SL 0x40000
#define JSMASK_SR 0x80000
#define JSOFFSET_UP 0
#define JSOFFSET_DOWN 1
#define JSOFFSET_LEFT 2
#define JSOFFSET_RIGHT 3
#define JSOFFSET_PLUS 4
#define JSOFFSET_OPTIONS 4
#define JSOFFSET_MINUS 5
#define JSOFFSET_SHARE 5
#define JSOFFSET_LCLICK 6
#define JSOFFSET_RCLICK 7
#define JSOFFSET_L 8
#define JSOFFSET_R 9
#define JSOFFSET_ZL 10
#define JSOFFSET_ZR 11
#define JSOFFSET_S 12
#define JSOFFSET_E 13
#define JSOFFSET_W 14
#define JSOFFSET_N 15
#define JSOFFSET_HOME 16
#define JSOFFSET_PS 16
#define JSOFFSET_CAPTURE 17
#define JSOFFSET_TOUCHPAD_CLICK 17
#define JSOFFSET_MIC 18
#define JSOFFSET_SL 18
#define JSOFFSET_SR 19
// PS5 Player maps for the DS Player Lightbar
#define DS5_PLAYER_1 = 4
#define DS5_PLAYER_2 = 10
#define DS5_PLAYER_3 = 21
#define DS5_PLAYER_4 = 27
#define DS5_PLAYER_5 = 31
typedef struct JOY_SHOCK_STATE {
int buttons;
float lTrigger;
float rTrigger;
float stickLX;
float stickLY;
float stickRX;
float stickRY;
} JOY_SHOCK_STATE;
typedef struct IMU_STATE {
float accelX;
float accelY;
float accelZ;
float gyroX;
float gyroY;
float gyroZ;
} IMU_STATE;
typedef struct MOTION_STATE {
float quatW;
float quatX;
float quatY;
float quatZ;
float accelX;
float accelY;
float accelZ;
float gravX;
float gravY;
float gravZ;
} MOTION_STATE;
typedef struct TOUCH_STATE {
int t0Id;
int t1Id;
bool t0Down;
bool t1Down;
float t0X;
float t0Y;
float t1X;
float t1Y;
} TOUCH_STATE;
extern "C" JOY_SHOCK_API int JslConnectDevices();
extern "C" JOY_SHOCK_API int JslGetConnectedDeviceHandles(int* deviceHandleArray, int size);
extern "C" JOY_SHOCK_API void JslDisconnectAndDisposeAll();
// get buttons as bits in the following order, using North South East West to name face buttons to avoid ambiguity between Xbox and Nintendo layouts:
// 0x00001: up
// 0x00002: down
// 0x00004: left
// 0x00008: right
// 0x00010: plus
// 0x00020: minus
// 0x00040: left stick click
// 0x00080: right stick click
// 0x00100: L
// 0x00200: R
// ZL and ZR are reported as analogue inputs (GetLeftTrigger, GetRightTrigger), because DS4 and XBox controllers use analogue triggers, but we also have them as raw buttons
// 0x00400: ZL
// 0x00800: ZR
// 0x01000: S
// 0x02000: E
// 0x04000: W
// 0x08000: N
// 0x10000: home / PS
// 0x20000: capture / touchpad-click
// 0x40000: SL
// 0x80000: SR
// These are the best way to get all the buttons/triggers/sticks, gyro/accelerometer (IMU), orientation/acceleration/gravity (Motion), or touchpad
extern "C" JOY_SHOCK_API JOY_SHOCK_STATE JslGetSimpleState(int deviceId);
extern "C" JOY_SHOCK_API IMU_STATE JslGetIMUState(int deviceId);
extern "C" JOY_SHOCK_API MOTION_STATE JslGetMotionState(int deviceId);
extern "C" JOY_SHOCK_API TOUCH_STATE JslGetTouchState(int deviceId, bool previous = false);
extern "C" JOY_SHOCK_API bool JslGetTouchpadDimension(int deviceId, int &sizeX, int &sizeY);
extern "C" JOY_SHOCK_API int JslGetButtons(int deviceId);
// get thumbsticks
extern "C" JOY_SHOCK_API float JslGetLeftX(int deviceId);
extern "C" JOY_SHOCK_API float JslGetLeftY(int deviceId);
extern "C" JOY_SHOCK_API float JslGetRightX(int deviceId);
extern "C" JOY_SHOCK_API float JslGetRightY(int deviceId);
// get triggers. Switch controllers don't have analogue triggers, but will report 0.0 or 1.0 so they can be used in the same way as others
extern "C" JOY_SHOCK_API float JslGetLeftTrigger(int deviceId);
extern "C" JOY_SHOCK_API float JslGetRightTrigger(int deviceId);
// get gyro
extern "C" JOY_SHOCK_API float JslGetGyroX(int deviceId);
extern "C" JOY_SHOCK_API float JslGetGyroY(int deviceId);
extern "C" JOY_SHOCK_API float JslGetGyroZ(int deviceId);
// get accelerometor
extern "C" JOY_SHOCK_API float JslGetAccelX(int deviceId);
extern "C" JOY_SHOCK_API float JslGetAccelY(int deviceId);
extern "C" JOY_SHOCK_API float JslGetAccelZ(int deviceId);
// get touchpad
extern "C" JOY_SHOCK_API int JslGetTouchId(int deviceId, bool secondTouch = false);
extern "C" JOY_SHOCK_API bool JslGetTouchDown(int deviceId, bool secondTouch = false);
extern "C" JOY_SHOCK_API float JslGetTouchX(int deviceId, bool secondTouch = false);
extern "C" JOY_SHOCK_API float JslGetTouchY(int deviceId, bool secondTouch = false);
// analog parameters have different resolutions depending on device
extern "C" JOY_SHOCK_API float JslGetStickStep(int deviceId);
extern "C" JOY_SHOCK_API float JslGetTriggerStep(int deviceId);
extern "C" JOY_SHOCK_API float JslGetPollRate(int deviceId);
// calibration
extern "C" JOY_SHOCK_API void JslResetContinuousCalibration(int deviceId);
extern "C" JOY_SHOCK_API void JslStartContinuousCalibration(int deviceId);
extern "C" JOY_SHOCK_API void JslPauseContinuousCalibration(int deviceId);
extern "C" JOY_SHOCK_API void JslSetAutomaticCalibration(int deviceId, bool enabled);
extern "C" JOY_SHOCK_API void JslGetCalibrationOffset(int deviceId, float& xOffset, float& yOffset, float& zOffset);
extern "C" JOY_SHOCK_API void JslSetCalibrationOffset(int deviceId, float xOffset, float yOffset, float zOffset);
// this function will get called for each input event from each controller
extern "C" JOY_SHOCK_API void JslSetCallback(void(*callback)(int, JOY_SHOCK_STATE, JOY_SHOCK_STATE, IMU_STATE, IMU_STATE, float));
// this function will get called for each input event, even if touch data didn't update
extern "C" JOY_SHOCK_API void JslSetTouchCallback(void(*callback)(int, TOUCH_STATE, TOUCH_STATE, float));
// what kind of controller is this?
extern "C" JOY_SHOCK_API int JslGetControllerType(int deviceId);
// is this a left, right, or full controller?
extern "C" JOY_SHOCK_API int JslGetControllerSplitType(int deviceId);
// what colour is the controller (not all controllers support this; those that don't will report white)
extern "C" JOY_SHOCK_API int JslGetControllerColour(int deviceId);
extern "C" JOY_SHOCK_API int JslGetControllerButtonColour(int deviceId);
extern "C" JOY_SHOCK_API int JslGetControllerLeftGripColour(int deviceId);
extern "C" JOY_SHOCK_API int JslGetControllerRightGripColour(int deviceId);
// set controller light colour (not all controllers have a light whose colour can be set, but that just means nothing will be done when this is called -- no harm)
extern "C" JOY_SHOCK_API void JslSetLightColour(int deviceId, int colour);
// set controller rumble
extern "C" JOY_SHOCK_API void JslSetRumble(int deviceId, int smallRumble, int bigRumble);
extern "C" JOY_SHOCK_API void JslSetRumbleFrequency(int deviceId, float smallRumble, float bigRumble, float smallFrequency, float bigFrequency);
// set controller player number indicator (not all controllers have a number indicator which can be set, but that just means nothing will be done when this is called -- no harm)
extern "C" JOY_SHOCK_API void JslSetPlayerNumber(int deviceId, int number);

View File

@ -0,0 +1,27 @@
fileFormatVersion: 2
guid: 129c872137ca57441bd8e920a0caceef
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,30 @@
### MIT License
Copyright 2018-2021 Julian Smart
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
This software incorporates some work from the following projects and their copyright holders, all also covered by the same MIT license, with the same permissions and disclaimers:
* mfosse's JoyCon-Driver (JoyCon driver), Copyright 2018 Matthew Fosse: https://github.com/mfosse/JoyCon-Driver
* chrippa's ds4drv (DualShock 4 driver), Copyright 2013-2014 Christopher Rosell: https://github.com/chrippa/ds4drv
* Ryochan7 and Jay2Kings' DS4Windows (DualShock 4 input mapper), Copyright 2019 Travis Nickles: https://github.com/Ryochan7/DS4Windows
---
This software also links to signal11's HIDAPI, and includes the source thereof in case it's needed for future builds. HIDAPI has its own permissive license: https://github.com/signal11/hidapi
HIDAPI - Multi-Platform library for
communication with HID devices.
Copyright 2009, Alan Ott, Signal 11 Software.
All Rights Reserved.
This software may be used by anyone for any reason so
long as the copyright notice in the source files
remains intact.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8aac471e2ae4e2c4691e7ebf7305175f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,179 @@
# JoyShockLibrary
The Sony PlayStation's DualShock 4, DualSense, Nintendo Switch Joy-Cons (used in pairs), and Nintendo Switch Pro Controller have much in common. They have many of the features expected of modern game controllers. They also have an incredibly versatile and underutilised input that their biggest rival (Microsoft's Xbox One controller) doesn't have: the gyro.
My goal with JoyShockLibrary is to enable game developers to support DS4, DS, Joy-Cons, and Pro Controllers natively in PC games. I've compiled the library for Windows, but it uses platform-agnostic tools, and my hope is that other developers would be able to get it working on other platforms (such as Linux or Mac) without too much trouble.
## Contents
* **[Releases](#releases)**
* **[Reference](#reference)**
* **[Structs](#structs)**
* **[Functions](#functions)**
* **[Known and Perceived Issues](#known-and-perceived-issues)**
* **[Backwards Compatibility](#backwards-compatibility)**
* **[Credits](#credits)**
* **[Helpful Resources](#helpful-resources)**
* **[License](#license)**
## Releases
The latest version of JoyShockLibrary can always be found [here](https://github.com/JibbSmart/JoyShockLibrary/releases). Included is a 64-bit dll and a 32-bit dll, both for Windows, and JoyShockLibrary.h and JoyShockLibrary.cs for using the dll in C/C++ and C\# (Unity), respectively.
## Reference
*JoyShockLibrary.h* has everything you need to use the library, but here's a breakdown of everything in there.
### Structs
**struct JOY\_SHOCK\_STATE** - This struct contains the state for all the sticks, buttons, and triggers on the controller. If you're just using JoyShockLibrary to be able to use Joy-Cons, Pro Controllers, DualSenses, and DualShock 4s similarly to how you'd use other devices, this has everything you need to know.
* **int buttons** contains the states of all the controller's buttons with the following masks:
* ```0x00001``` - d-pad ```up```
* ```0x00002``` - d-pad ```down```
* ```0x00004``` - d-pad ```left```
* ```0x00008``` - d-pad ```right```
* ```0x00010``` - ```+``` on Nintendo devices, ```Options``` on DS4
* ```0x00020``` - ```-``` on Nintendo devices, ```Share``` on DS4
* ```0x00040``` - ```left-stick click``` on Nintendo devices, ```L3``` on DS4
* ```0x00080``` - ```right-stick click``` on Nintendo devices, ```R3``` on DS4
* ```0x00100``` - ```L``` on Nintendo devices, ```L1``` on DS4
* ```0x00200``` - ```R``` on Nintendo devices, ```R1``` on DS4
* ```0x00400``` - ```ZL``` on Nintendo devices, ```L2``` on DS4
* ```0x00800``` - ```ZR``` on Nintendo devices, ```R2``` on DS4
* ```0x01000``` - the South face-button: ```B``` on Nintendo devices, ```⨉``` on DS4
* ```0x02000``` - the East face-button: ```A``` on Nintendo devices, ```○``` on DS4
* ```0x04000``` - the West face-button: ```Y``` on Nintendo devices, ```□``` on DS4
* ```0x08000``` - the North face-button: ```X``` on Nintendo devices, ```△``` on DS4
* ```0x10000``` - ```Home``` on Nintendo devices, ```PS``` on DS4
* ```0x20000``` - ```Capture``` on Nintendo devices, ```touchpad click``` on DS4, ```Create``` on DS5
* ```0x40000``` - ```SL``` on Nintendo Joy-Cons, ```Mic``` on DS5
* ```0x80000``` - ```SR``` on Nintendo Joy-Cons
* **float lTrigger** - how far has the left trigger been pressed? This will be 1 or 0 on Nintendo devices, which don't have analog triggers
* **float rTrigger** - how far has the right trigger been pressed? This will be 1 or 0 on Nintendo devices, which don't have analog triggers
* **float stickLX, stickLY** - left-stick X axis and Y axis, respectively, from -1 to 1
* **float stickRX, stickRX** - right-stick X axis and Y axis, respectively, from -1 to 1
**struct IMU_STATE** - Each supported device contains an IMU which has a 3-axis accelerometer and a 3-axis gyroscope. IMU\_STATE is where you find that info.
* **float accelX, accelY, accelZ** - accelerometer X axis, Y axis, and Z axis, respectively, in g (g-force).
* **float gyroX, gyroY, gyroZ** - gyroscope angular velocity X, Y, and Z, respectively, in dps (degrees per second), when correctly calibrated.
**struct MOTION_STATE** - The MOTION_STATE reports the orientation of the device as calculated using a sensor fusion solution to combine gyro and accelerometer data.
* **float quatW, quatX, quatY, quatZ** - a quaternion representing the orientation of the device.
* **float accelX, accelY, accelZ** - local acceleration after accounting for and removing the effect of gravity.
* **float gravX, gravY, gravZ** - local gravity direction.
### Functions
All these functions *should* be thread-safe, and none of them should cause any harm if given the wrong handle. If they do, please report this to me as an isuse.
**int JslConnectDevices()** - Register any connected devices. Returns the number of devices connected, which is helpful for getting the handles for those devices with the next function.
**int JslGetConnectedDeviceHandles(int\* deviceHandleArray, int size)** - Fills the array *deviceHandleArray* of size *size* with the handles for all connected devices, up to the length of the array. Use the length returned by *JslConnectDevices* to make sure you've got all connected devices' handles.
**void JslDisconnectAndDisposeAll()** - Disconnect devices, no longer polling them for input.
**JOY\_SHOCK\_STATE JslGetSimpleState(int deviceId)** - Get the latest button + trigger + stick state for the controller with the given id.
**IMU\_STATE JslGetIMUState(int deviceId)** - Get the latest accelerometer + gyroscope state for the controller with the given id.
**MOTION\_STATE JslGetMotionState(int deviceId)** - Get the latest motion state for the controller with the given id.
**TOUCH\_STATE JslGetTouchState(int deviceId)** - Get the latest touchpad state for the controller with the given id. Only DualShock 4s support this.
**int JslGetButtons(int deviceId)** - Get the latest button state for the controller with the given id. If you want more than just the buttons, it's more efficient to use JslGetSimpleState.
**float JslGetLeftX/JslGetLeftY/JslGetRightX/JslGetRightY(int deviceId)** - Get the latest stick state for the controller with the given id. If you want more than just a single stick axis, it's more efficient to use JslGetSimpleState.
**float JslGetLeftTrigger/JslGetRightTrigger(int deviceId)** - Get the latest trigger state for the controller with the given id. If you want more than just a single trigger, it's more efficient to use JslGetSimpleState.
**float JslGetGyroX/JslGetGyroY/JslGetGyroZ(int deviceId)** - Get the latest angular velocity for a given gyroscope axis. If you want more than just a single gyroscope axis velocity, it's more efficient to use JslGetIMUState.
**float JslGetAccelX/JslGetAccelY/JslGetAccelZ(int deviceId)** - Get the latest acceleration for a given axis. If you want more than just a accelerometer axis, it's more efficient to use JslGetIMUState.
**int JslGetTouchId(int deviceId, bool secondTouch=false)** - Get the last touch's id, which is a value in range of 0-127 that automaticaly increments whenever a new touch appears, for the controller with the given id. Only DualShock 4s support this. If you want more than just a touch's id, it's more efficient to use JslGetTouchState.
**bool JslGetTouchDown(int deviceId, bool secondTouch=false)** - Get the latest state of the touch being present on a touchpad for the controller with the given id. Only DualShock 4s support this. If you want more than just a presence of touch, it's more efficient to use JslGetTouchState.
**float JslGetTouchX/JslGetTouchY(int deviceId, bool secondTouch=false)** - Get the latest touch state for the controller with the given id. Only DualShock 4s support this. If you want more than just a single touch axis, it's more efficient to use JslGetTouchState.
**float JslGetStickStep(int deviceId)** - Different devices use different size data types and different ranges on those data types when reporting stick axes. For some calculations, it may be important to know the limits of the current device and work around them in different ways. This gives the smallest step size between two values for the given device's analog sticks.
**float JslGetTriggerStep(int deviceId)** - Some devices have analog triggers, some don't. For some calculations, it may be important to know the limits of the current device and work around them in different ways. This gives the smallest step size between two values for the given device's triggers, or 1.0 if they're actually just binary inputs.
**float JslGetTriggerStep(int deviceId)** - Some devices have analog triggers, some don't. For some calculations, it may be important to know the limits of the current device and work around them in different ways. This gives the smallest step size between two values for the given device's triggers, or 1.0 if they're actually just binary inputs.
**float JslGetPollRate(int deviceId)** - Different devices report back new information at different rates. For the given device, this gives how many times one would usually expect the device to report back per second.
**void JslResetContinuousCalibration(int deviceId)** - JoyShockLibrary has helpful functions for calibrating the gyroscope by averaging out its input over time. This deletes all calibration data that's been accumulated, if any, this session.
**void JslStartContinuousCalibration(int deviceId)** - Start collecting gyro data, recording the ongoing average and using that to offset gyro output.
**void JslPauseContinuousCalibration(int deviceId)** - Stop collecting gyro data, but don't delete it.
**void JslGetCalibrationOffset(int deviceId, float& xOffset, float& yOffset, float& zOffset)** - Get the calibrated offset value for the given device's gyro. You don't have to use it; all gyro output for this device is already being offset by this vector before leaving JoyShockLibrary.
**void JslSetCalibrationOffset(int deviceId, float xOffset, float yOffset, float zOffset)** - Manually set the calibrated offset value for the given device's gyro.
**void JslSetCallback(void(\*callback)(int, JOY\_SHOCK\_STATE, JOY\_SHOCK\_STATE, IMU\_STATE, IMU\_STATE, float))** - Set a callback function by which JoyShockLibrary can report the current state for each device. This callback will be given the *deviceId* for the reporting device, its current button + trigger + stick state, its previous button + trigger + stick state, its current accelerometer + gyro state, its previous accelerometer + gyro state, and the amount of time since the last report for this device (in seconds).
**void JslSetTouchCallback(void(\*callback)(int, TOUCH\_STATE, TOUCH\_STATE, float))** - Set a callback function by which JoyShockLibrary can report the current touchpad state for each device. Only DualShock 4s will use this. This callback will be given the *deviceId* for the reporting device, its current and previous touchpad states, and the amount of time since the last report for this device (in seconds).
**int JslGetControllerType(int deviceId)** - What type of controller is this device?
1. Left Joy-Con
2. Right Joy-Con
3. Switch Pro Controller
4. DualShock 4
5. DualSense
**int JslGetControllerSplitType(int deviceId)** - Is this a half-controller or full? If half, what kind?
1. Left half
2. Right half
3. Full controller
**int JslGetControllerColour(int deviceId)** - Get the colour of the controller. Only Nintendo devices support this. Others will report white.
**void JslSetLightColour(int deviceId, int colour)** - Set the light colour on the given controller. Only DualShock 4 and the DualSense support this. Players will often prefer to be able to disable the light, so make sure to give them that option, but when setting players up in a local multiplayer game, setting the light colour is a useful way to uniquely identify different controllers.
**void JslSetPlayerNumber(int deviceId, int number)** - Set the lights that indicate player number. This only works on Nintendo devices and the DualSense. NOTE: The DualSense sets each LED through a bitmask. Use the ```DS5_PLAYER_#``` definitions in the header file to get PS5-style lightbar formats.
Player 1: ```--x--```
Player 2: ```-x-x-```
Player 3: ```x-x-x```
Player 4: ```xx-xx```
Player 5: ```xxxxx```
**void JslSetRumble(int deviceId, int smallRumble, int bigRumble)** - DualShock 4s have two types of rumble, and they can be set at the same time with different intensities. These can be set from 0 to 255. Nintendo devices support rumble as well, but totally differently. They call it "HD rumble", and it's a great feature, but JoyShockLibrary doesn't yet support it.
## Known and Perceived Issues
### Bluetooth connectivity
Joy-Cons and Pro Controllers are normally only be connected by Bluetooth. Some Bluetooth adapters can't keep up with these devices, resulting in laggy input. This is especially common when more than one device is connected (such as when using a pair of Joy-Cons). There is nothing JoyShockMapper or JoyShockLibrary can do about this.
There is experimental support for connecting supported Switch controllers by USB now. Please let me know if you have any issues (or success!) with it.
### Gyro poll rate on Nintendo devices
The Nintendo devices report every 15ms, but their IMUs actually report every 5ms. Every 15ms report includes the last 3 gyro and accelerometer reports. When creating the latest IMU state for Nintendo devices, JoyShockLibrary averages out those 3 gyro and accelerometer reports, so that it can best include all that information in a sensible format. For things like controlling a cursor on a plane, this should be of little to no consequence, since the result is the same as adding all 3 reports separately over shorter time intervals. But for representing real 3D rotations of the controller, this causes the Nintendo devices to be *slightly* less accurate than they could be, because we're combining 3 rotations in a simplistic way.
In a future version I hope to either combine the 3 rotations in a way that works better in 3D, or to add a way for a single controller event to report several IMU events at the same time.
## Backwards Compatibility
JoyShockLibrary v2 changes the gyro and accelerometer axes from previous versions. Previous versions were inconsistent between gyro and accelerometer. When upgrading to JoyShockLibrary v2, in order to maintain previous behaviour:
* Invert Gyro X
* Swap Accel Z and Y
* Then invert Accel Z
## Credits
I'm Jibb Smart, and I made JoyShockLibrary. JoyShockLibrary has also benefited from the contributions of:
* Romeo Calota (Linux support + general portability improvements)
* RollinBarrel (touchpad support)
* Robin (wireless DS4/5 support)
JoyShockLibrary uses substantial portions of mfosse's [JoyCon-Driver](https://github.com/mfosse/JoyCon-Driver), a [vJoy](http://vjoystick.sourceforge.net/site/) feeder for most communication with Nintendo devices, building on it with info from dekuNukem's [Nintendo Switch Reverse Engineering](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/) page in order to (for example) unpack all gyro and accelerometer samples from each report.
JoyShockLibrary's DualShock 4 support would likely not be possible without the info available on [PSDevWiki](https://www.psdevwiki.com/ps4/Main_Page) and [Eleccelerator Wiki](http://eleccelerator.com/wiki/index.php?title=DualShock_4). chrippa's [ds4drv](https://github.com/chrippa/ds4drv) was also a handy reference for getting rumble and lights working right away, and some changes have been made while referencing Ryochan7's [DS4Windows](https://github.com/Ryochan7/DS4Windows).
This software depends on signal11's [HIDAPI](https://github.com/signal11/hidapi) to connect to USB and Bluetooth devices.
## Helpful Resources
* [GyroWiki](http://gyrowiki.jibbsmart.com) - All about good gyro controls for games:
* Why gyro controls make gaming better;
* How developers can do a better job implementing gyro controls;
* How to use JoyShockLibrary;
* How gamers can play any PC game with gyro controls using [JoyShockMapper](https://github.com/JibbSmart/JoyShockMapper), which uses JoyShockLibrary to read from supported controllers.
## License
JoyShockLibrary is licensed under the MIT License - see [LICENSE.md](LICENSE.md).

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9e1b398aaf3d3a8429068830e3168b86
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 46ec8bf5775b6af429f16d7140f02d54
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,63 @@
fileFormatVersion: 2
guid: c84ef0f74efdfa149b54ff639acd7c7b
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux64: 0
Exclude OSXUniversal: 0
Exclude Win: 1
Exclude Win64: 0
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: x86_64
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: x86_64
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 309dd656c95dd434ba2f1ccefa8b3ec0
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 099214b717710f8468369d6cfe2f7135
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,63 @@
fileFormatVersion: 2
guid: c603b06f7fc73b9448935991b913d915
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 1
Exclude Linux64: 0
Exclude OSXUniversal: 0
Exclude Win: 0
Exclude Win64: 1
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 1
settings:
CPU: x86
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 12b152ed16fe1eb4698be175f621ffe4
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -736,7 +736,7 @@ GameObject:
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 m_IsActive: 0
--- !u!224 &14095204 --- !u!224 &14095204
RectTransform: RectTransform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -10733,6 +10733,7 @@ GameObject:
- component: {fileID: 527828798} - component: {fileID: 527828798}
- component: {fileID: 527828797} - component: {fileID: 527828797}
- component: {fileID: 527828796} - component: {fileID: 527828796}
- component: {fileID: 527828799}
m_Layer: 5 m_Layer: 5
m_Name: ControllerSetup m_Name: ControllerSetup
m_TagString: Untagged m_TagString: Untagged
@ -10799,6 +10800,20 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &527828799
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 527828795}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 10d59ed8edc40a448a61794f93c74ccd, type: 3}
m_Name:
m_EditorClassIdentifier:
numConnectedLabel: {fileID: 976256976}
currentControllerLabel: {fileID: 1007704296}
--- !u!1 &528192059 --- !u!1 &528192059
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -14362,7 +14377,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1} m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 591, y: -224} m_AnchoredPosition: {x: 591, y: -174}
m_SizeDelta: {x: 1142, y: 200} m_SizeDelta: {x: 1142, y: 200}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &674573517 --- !u!114 &674573517
@ -19100,7 +19115,7 @@ MonoBehaviour:
m_HandleRect: {fileID: 1589389271} m_HandleRect: {fileID: 1589389271}
m_Direction: 2 m_Direction: 2
m_Value: 1 m_Value: 1
m_Size: 0.99703497 m_Size: 1
m_NumberOfSteps: 0 m_NumberOfSteps: 0
m_OnValueChanged: m_OnValueChanged:
m_PersistentCalls: m_PersistentCalls:
@ -20659,7 +20674,7 @@ GameObject:
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 0 m_IsActive: 1
--- !u!224 &976256975 --- !u!224 &976256975
RectTransform: RectTransform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -20699,7 +20714,7 @@ MonoBehaviour:
m_OnCullStateChanged: m_OnCullStateChanged:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_text: '? Controllers Connected (? JoyShock)' m_text:
m_isRightToLeft: 0 m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 4810e200fa0cb24438bac52343d7674b, type: 2} m_fontAsset: {fileID: 11400000, guid: 4810e200fa0cb24438bac52343d7674b, type: 2}
m_sharedMaterial: {fileID: 8580487687356851718, guid: 4810e200fa0cb24438bac52343d7674b, type: 2} m_sharedMaterial: {fileID: 8580487687356851718, guid: 4810e200fa0cb24438bac52343d7674b, type: 2}
@ -24807,7 +24822,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0.5} m_AnchorMin: {x: 0, y: 0.5}
m_AnchorMax: {x: 1, y: 0.5} m_AnchorMax: {x: 1, y: 0.5}
m_AnchoredPosition: {x: 0, y: 130.0065} m_AnchoredPosition: {x: 0, y: 130.0071}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 1} m_Pivot: {x: 0.5, y: 1}
--- !u!114 &1154875944 --- !u!114 &1154875944
@ -26452,7 +26467,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1} m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1} m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 329} m_SizeDelta: {x: 0, y: 279}
m_Pivot: {x: 0, y: 1} m_Pivot: {x: 0, y: 1}
--- !u!114 &1219233812 --- !u!114 &1219233812
MonoBehaviour: MonoBehaviour:
@ -31033,7 +31048,19 @@ MonoBehaviour:
m_TargetGraphic: {fileID: 1436502936} m_TargetGraphic: {fileID: 1436502936}
m_OnClick: m_OnClick:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls:
- m_Target: {fileID: 527828799}
m_TargetAssemblyTypeName: HeavenStudio.Editor.ControllerSettings, Assembly-CSharp
m_MethodName: SearchAndConnectControllers
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
--- !u!114 &1436502936 --- !u!114 &1436502936
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -198,6 +198,8 @@ namespace HeavenStudio
// LateUpdate works a bit better(?) but causes some bugs (like issues with bop animations). // LateUpdate works a bit better(?) but causes some bugs (like issues with bop animations).
private void Update() private void Update()
{ {
PlayerInput.UpdateJoyShocks();
if (BeatmapEntities() < 1) //bruh really you forgot to ckeck tempo changes if (BeatmapEntities() < 1) //bruh really you forgot to ckeck tempo changes
return; return;
if (!Conductor.instance.isPlaying) if (!Conductor.instance.isPlaying)
@ -526,5 +528,12 @@ namespace HeavenStudio
{ {
HeavenStudio.GameCamera.ResetAdditionalTransforms(); HeavenStudio.GameCamera.ResetAdditionalTransforms();
} }
void OnApplicationQuit()
{
Debug.Log("Disconnecting JoyShocks...");
JSL.JslSetCallback(null);
JSL.JslDisconnectAndDisposeAll();
}
} }
} }

View File

@ -0,0 +1,23 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using HeavenStudio;
using static JSL;
namespace HeavenStudio.Editor
{
public class ControllerSettings : MonoBehaviour
{
[SerializeField] private TMP_Text numConnectedLabel;
[SerializeField] private TMP_Text currentControllerLabel;
public void SearchAndConnectControllers()
{
int connected = PlayerInput.InitJoyShocks();
numConnectedLabel.text = "Connected: " + connected;
//do this better
currentControllerLabel.text = "Current Controller: " + PlayerInput.GetJoyShockName(0);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10d59ed8edc40a448a61794f93c74ccd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -2,10 +2,159 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using static JSL;
namespace HeavenStudio namespace HeavenStudio
{ {
public class PlayerInput public class PlayerInput
{ {
///////////////////////////////
////TEMPORARY JSL FUNCTIONS////
///////////////////////////////
static string[] joyShockNames =
{
"Unknown",
"Joy-Con (L)",
"Joy-Con (R)",
"Pro Controller",
"DualShock 4",
"DualSense"
};
static int numDevicesFound = 0;
static int numDevicesConnected = 0;
static int[] deviceHandles;
static Dictionary<int, JOY_SHOCK_STATE> joyBtStateCurrent;
static Dictionary<int, JOY_SHOCK_STATE> joyBtStateLast;
static Dictionary<int, IMU_STATE> joyImuStateCurrent;
static Dictionary<int, IMU_STATE> joyImuStateLast;
public static int InitJoyShocks()
{
//flush old joyshocks
Debug.Log("Flushing possible JoyShocks...");
JslDisconnectAndDisposeAll();
numDevicesFound = 0;
numDevicesConnected = 0;
numDevicesFound = JslConnectDevices();
if (numDevicesFound > 0)
{
deviceHandles = new int[numDevicesFound];
numDevicesConnected = JslGetConnectedDeviceHandles(deviceHandles, numDevicesFound);
joyBtStateCurrent = new Dictionary<int, JOY_SHOCK_STATE>();
joyBtStateLast = new Dictionary<int, JOY_SHOCK_STATE>();
if (numDevicesConnected < numDevicesFound)
{
Debug.Log("Found " + numDevicesFound + " JoyShocks, but only " + numDevicesConnected + " are connected.");
}
else
{
Debug.Log("Found " + numDevicesFound + " JoyShocks.");
Debug.Log("Connected " + numDevicesConnected + " JoyShocks.");
}
foreach (int i in deviceHandles)
{
Debug.Log("Setting up JoyShock: " + joyShockNames[JslGetControllerType(i)] + " ( Player " + i + ", type " + JslGetControllerType(i) + " )");
}
return numDevicesConnected;
}
else
{
Debug.Log("No JoyShocks found.");
return 0;
}
}
public static string GetJoyShockName(int playerNum)
{
return joyShockNames[JslGetControllerType(deviceHandles[playerNum])];
}
public static void UpdateJoyShocks()
{
if (deviceHandles == null || numDevicesConnected == 0) return;
foreach (var id in deviceHandles)
{
if (joyBtStateCurrent.ContainsKey(id))
{
joyBtStateLast[id] = joyBtStateCurrent[id];
}
else
{
joyBtStateLast[id] = new JOY_SHOCK_STATE();
}
joyBtStateCurrent[id] = JslGetSimpleState(id);
}
}
//TODO: refactor to allow controller selection (and for split controllers, multiple controllers)
static bool GetJoyBtDown(int bt)
{
if (deviceHandles == null || numDevicesConnected <= 0) // <= player number in the future
{
return false;
}
bt = 1 << bt;
int p1Id = deviceHandles[0];
try
{
int curBt = joyBtStateCurrent[p1Id].buttons;
int oldBt = joyBtStateLast[p1Id].buttons;
return ((curBt & bt) == bt) && ((oldBt & bt) != bt);
}
catch (System.Exception)
{
return false;
}
}
static bool GetJoyBt(int bt)
{
if (deviceHandles == null || numDevicesConnected <= 0) // <= player number in the future
{
return false;
}
bt = 1 << bt;
int p1Id = deviceHandles[0];
try
{
int curBt = joyBtStateCurrent[p1Id].buttons;
return (curBt & bt) == bt;
}
catch (System.Exception)
{
return false;
}
}
static bool GetJoyBtUp(int bt)
{
if (deviceHandles == null || numDevicesConnected <= 0) // <= player number in the future
{
return false;
}
bt = 1 << bt;
int p1Id = deviceHandles[0];
try
{
int curBt = joyBtStateCurrent[p1Id].buttons;
int oldBt = joyBtStateLast[p1Id].buttons;
return ((curBt & bt) != bt) && ((oldBt & bt) == bt);
}
catch (System.Exception)
{
return false;
}
}
////END TEMPORARY JSL FUNCTIONS
///////////////////////////////
//Clockwise //Clockwise
public const int UP = 0; public const int UP = 0;
@ -26,39 +175,43 @@ namespace HeavenStudio
/*--------------------*/ /*--------------------*/
// BUTTONS // BUTTONS
//TODO: refactor for controller and custom binds, currently uses temporary button checks
public static bool Pressed(bool includeDPad = false) public static bool Pressed(bool includeDPad = false)
{ {
bool keyDown = Input.GetKeyDown(KeyCode.Z) || (includeDPad && GetAnyDirectionDown()); bool keyDown = Input.GetKeyDown(KeyCode.Z) || GetJoyBtDown(ButtonMaskE) || (includeDPad && GetAnyDirectionDown());
return keyDown && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput ; return keyDown && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput ;
} }
public static bool PressedUp(bool includeDPad = false) public static bool PressedUp(bool includeDPad = false)
{ {
bool keyUp = Input.GetKeyUp(KeyCode.Z) || (includeDPad && GetAnyDirectionUp()); bool keyUp = Input.GetKeyUp(KeyCode.Z) || GetJoyBtUp(ButtonMaskE) || (includeDPad && GetAnyDirectionUp());
return keyUp && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput; return keyUp && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
} }
public static bool Pressing(bool includeDPad = false) public static bool Pressing(bool includeDPad = false)
{ {
bool pressing = Input.GetKey(KeyCode.Z) || (includeDPad && GetAnyDirection()); bool pressing = Input.GetKey(KeyCode.Z) || GetJoyBt(ButtonMaskE) || (includeDPad && GetAnyDirection());
return pressing && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput; return pressing && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
} }
public static bool AltPressed() public static bool AltPressed()
{ {
return Input.GetKeyDown(KeyCode.X) && playerHasControl(); bool down = Input.GetKeyDown(KeyCode.X) || GetJoyBtDown(ButtonMaskS);
return down && playerHasControl();
} }
public static bool AltPressedUp() public static bool AltPressedUp()
{ {
return Input.GetKeyUp(KeyCode.X) && playerHasControl(); bool up = Input.GetKeyUp(KeyCode.X) || GetJoyBtUp(ButtonMaskS);
return up && playerHasControl();
} }
public static bool AltPressing() public static bool AltPressing()
{ {
return Input.GetKey(KeyCode.X) && playerHasControl(); bool pressing = Input.GetKey(KeyCode.X) || GetJoyBt(ButtonMaskS);
return pressing && playerHasControl();
} }
//Directions //Directions
@ -68,7 +221,13 @@ namespace HeavenStudio
return (Input.GetKeyDown(KeyCode.UpArrow) return (Input.GetKeyDown(KeyCode.UpArrow)
|| Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.DownArrow)
|| Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.LeftArrow)
|| Input.GetKeyDown(KeyCode.RightArrow)) && playerHasControl(); || Input.GetKeyDown(KeyCode.RightArrow)
|| GetJoyBtDown(ButtonMaskUp)
|| GetJoyBtDown(ButtonMaskDown)
|| GetJoyBtDown(ButtonMaskLeft)
|| GetJoyBtDown(ButtonMaskRight)
) && playerHasControl();
} }
@ -77,7 +236,13 @@ namespace HeavenStudio
return (Input.GetKeyUp(KeyCode.UpArrow) return (Input.GetKeyUp(KeyCode.UpArrow)
|| Input.GetKeyUp(KeyCode.DownArrow) || Input.GetKeyUp(KeyCode.DownArrow)
|| Input.GetKeyUp(KeyCode.LeftArrow) || Input.GetKeyUp(KeyCode.LeftArrow)
|| Input.GetKeyUp(KeyCode.RightArrow)) && playerHasControl(); || Input.GetKeyUp(KeyCode.RightArrow)
|| GetJoyBtUp(ButtonMaskUp)
|| GetJoyBtUp(ButtonMaskDown)
|| GetJoyBtUp(ButtonMaskLeft)
|| GetJoyBtUp(ButtonMaskRight)
) && playerHasControl();
} }
@ -86,7 +251,13 @@ namespace HeavenStudio
return (Input.GetKey(KeyCode.UpArrow) return (Input.GetKey(KeyCode.UpArrow)
|| Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.DownArrow)
|| Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.LeftArrow)
|| Input.GetKey(KeyCode.RightArrow)) && playerHasControl(); || Input.GetKey(KeyCode.RightArrow)
|| GetJoyBt(ButtonMaskUp)
|| GetJoyBt(ButtonMaskDown)
|| GetJoyBt(ButtonMaskLeft)
|| GetJoyBt(ButtonMaskRight)
) && playerHasControl();
} }
@ -95,7 +266,9 @@ namespace HeavenStudio
KeyCode targetCode = getKeyCode(direction); KeyCode targetCode = getKeyCode(direction);
if (targetCode == KeyCode.None) return false; if (targetCode == KeyCode.None) return false;
return Input.GetKeyDown(targetCode) && playerHasControl(); int targetMask = getButtonMask(direction);
if (targetMask == 0) return false;
return (Input.GetKeyDown(targetCode) || GetJoyBtDown(targetMask)) && playerHasControl();
} }
public static bool GetSpecificDirectionUp(int direction) public static bool GetSpecificDirectionUp(int direction)
@ -103,7 +276,10 @@ namespace HeavenStudio
KeyCode targetCode = getKeyCode(direction); KeyCode targetCode = getKeyCode(direction);
if (targetCode == KeyCode.None) return false; if (targetCode == KeyCode.None) return false;
return Input.GetKeyUp(targetCode) && playerHasControl(); int targetMask = getButtonMask(direction);
if (targetMask == 0) return false;
return (Input.GetKeyUp(targetCode) || GetJoyBtUp(targetMask)) && playerHasControl();
} }
@ -123,5 +299,21 @@ namespace HeavenStudio
return targetKeyCode; return targetKeyCode;
} }
private static int getButtonMask(int direction)
{
int targetKeyCode;
switch (direction)
{
case PlayerInput.UP: targetKeyCode = ButtonMaskUp; break;
case PlayerInput.DOWN: targetKeyCode = ButtonMaskDown; break;
case PlayerInput.LEFT: targetKeyCode = ButtonMaskLeft; break;
case PlayerInput.RIGHT: targetKeyCode = ButtonMaskRight; break;
default: targetKeyCode = -1; break;
}
return targetKeyCode;
}
} }
} }