gods4

package
v0.0.0-...-a545287 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2022 License: MIT, MIT Imports: 9 Imported by: 0

README

gods4

A userspace cross-platform driver for Sony DualShock 4 controller over HID. Works for Bluetooth and USB connections.

Features

  • Buttons: x, circle, square, triangle, share, options, touchpad
  • D-pad: up, down, left, right (also intermediate positions)
  • Analog sticks: left, right
  • Analog triggers: L2, R2
  • Touchpad: 2 touches and button
  • Battery
  • Gyroscope (absolute orientation)
  • Accelerometer (relative movement)
  • Activating the motors (rumble)
  • Setting the LED color

Install

Use go get to install the latest version of the library:

go get github.com/kpeu3i/gods4@v1.0.0

Next, include ds4 in your application:

import "github.com/kpeu3i/gods4"

Usage

First, connect the controller to your computer using a micro-USB cable or Bluetooth.

package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/kpeu3i/gods4"
	"github.com/kpeu3i/gods4/led"
	"github.com/kpeu3i/gods4/rumble"
)

func main() {
	// Find all controllers connected to your machine via USB or Bluetooth
	controllers := gods4.Find()
	if len(controllers) == 0 {
		panic("No connected DS4 controllers found")
	}

	// Select first controller from the list
	controller := controllers[0]

	// Connect to the controller
	err := controller.Connect()
	if err != nil {
		panic(err)
	}

	log.Printf("* Controller #1 | %-10s | name: %s, connection: %s\n", "Connect", controller, controller.ConnectionType())

	// Disconnect controller when a program is terminated
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-signals
		err := controller.Disconnect()
		if err != nil {
			panic(err)
		}
		log.Printf("* Controller #1 | %-10s | bye!\n", "Disconnect")
	}()

	// Register callback for "BatteryUpdate" event
	controller.On(gods4.EventBatteryUpdate, func(data interface{}) error {
		battery := data.(gods4.Battery)
		log.Printf("* Controller #1 | %-10s | capacity: %v%%, charging: %v, cable: %v\n",
			"Battery",
			battery.Capacity,
			battery.IsCharging,
			battery.IsCableConnected,
		)

		return nil
	})

	// Register callback for "CrossPress" event
	controller.On(gods4.EventCrossPress, func(data interface{}) error {
		log.Printf("* Controller #1 | %-10s | state: press\n", "Cross")

		return nil
	})

	// Register callback for "CrossRelease" event
	controller.On(gods4.EventCrossRelease, func(data interface{}) error {
		log.Printf("* Controller #1 | %-10s | state: release\n", "Cross")

		return nil
	})

	// Register callback for "RightStickMove" event
	controller.On(gods4.EventRightStickMove, func(data interface{}) error {
		stick := data.(gods4.Stick)
		log.Printf("* Controller #1 | %-10s | x: %v, y: %v\n", "RightStick", stick.X, stick.Y)

		return nil
	})

	// Enable left and right rumble motors
	err = controller.Rumble(rumble.Both())
	if err != nil {
		panic(err)
	}

	// Enable LED (yellow) with flash
	err = controller.Led(led.Yellow().Flash(50, 50))
	if err != nil {
		panic(err)
	}

	// Start listening for controller events
	err = controller.Listen()
	if err != nil {
		panic(err)
	}

	// Output:
	// 2019/02/16 17:00:23 * Controller #1 | Connect    | name: Wireless Controller (vendor: 1356, product: 2508), connection: BT
	// 2019/02/16 17:00:23 * Controller #1 | Battery    | capacity: 77%, charging: false, cable: false
	// 2019/02/16 17:00:34 * Controller #1 | Cross      | state: press
	// 2019/02/16 17:00:34 * Controller #1 | Cross      | state: release
	// 2019/02/16 17:00:39 * Controller #1 | RightStick | x: 187, y: 98
	// 2019/02/16 17:00:39 * Controller #1 | RightStick | x: 191, y: 94
	// 2019/02/16 17:00:39 * Controller #1 | RightStick | x: 196, y: 93
	// 2019/02/16 17:00:39 * Controller #1 | RightStick | x: 212, y: 88
	// 2019/02/16 17:00:39 * Controller #1 | RightStick | x: 228, y: 79
	// 2019/02/16 17:02:52 * Controller #1 | Disconnect | bye!
}

Events

Events on which you can subscribe are listed below:

Name Data
EventCrossPress nil
EventCrossRelease nil
EventCirclePress nil
EventCircleRelease nil
EventSquarePress nil
EventSquareRelease nil
EventTrianglePress nil
EventTriangleRelease nil
EventL1Press nil
EventL1Release nil
EventL2Press byte
EventL2Release byte
EventL3Press nil
EventL3Release nil
EventR1Press nil
EventR1Release nil
EventR2Press byte
EventR2Release byte
EventR3Press nil
EventR3Release nil
EventDPadUpPress nil
EventDPadUpRelease nil
EventDPadDownPress nil
EventDPadDownRelease nil
EventDPadLeftPress nil
EventDPadLeftRelease nil
EventDPadRightPress nil
EventDPadRightRelease nil
EventSharePress nil
EventShareRelease nil
EventOptionsPress nil
EventOptionsRelease nil
EventTouchpadSwipe Touchpad
EventTouchpadPress Touchpad
EventTouchpadRelease Touchpad
EventPSPress nil
EventPSRelease nil
EventLeftStickMove Stick
EventRightStickMove Stick
EventAccelerometerUpdate Accelerometer
EventGyroscopeUpdate Gyroscope
EventBatteryUpdate Battery

TODO

  • Microphone/speaker
  • Tests

References

The DualShock 4 report format is not open and these resources have been very helpful when creating gods4:

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidConnectionType    = errors.New("ds4: can't detect connection type")
	ErrControllerIsConnected    = errors.New("ds4: controller is already connected")
	ErrControllerIsNotConnected = errors.New("ds4: controller is not connected")
	ErrControllerIsListening    = errors.New("ds4: controller is already listening for events")
)

Functions

This section is empty.

Types

type Accelerometer

type Accelerometer struct {
	X int16
	Y int16
	Z int16
}

type Battery

type Battery struct {
	Capacity         byte
	IsCharging       bool
	IsCableConnected bool
}

type Callback

type Callback func(data interface{}) error

type ConnectionType

type ConnectionType uint
const (
	ConnectionTypeNone ConnectionType = iota
	ConnectionTypeUSB
	ConnectionTypeBluetooth
)

func (ConnectionType) String

func (t ConnectionType) String() string

type Controller

type Controller struct {
	// contains filtered or unexported fields
}

func Find

func Find() []*Controller

func NewController

func NewController(device Device) *Controller

func (*Controller) Connect

func (c *Controller) Connect() error

func (*Controller) ConnectionType

func (c *Controller) ConnectionType() ConnectionType

func (*Controller) Disconnect

func (c *Controller) Disconnect() error

func (*Controller) Led

func (c *Controller) Led(led *led.Led) error

func (*Controller) Listen

func (c *Controller) Listen() error

func (*Controller) Name

func (c *Controller) Name() string

func (*Controller) Off

func (c *Controller) Off(event Event)

func (*Controller) On

func (c *Controller) On(event Event, fn Callback)

func (*Controller) ProductID

func (c *Controller) ProductID() uint16

func (*Controller) Rumble

func (c *Controller) Rumble(rumble *rumble.Rumble) error

func (*Controller) String

func (c *Controller) String() string

func (*Controller) VendorID

func (c *Controller) VendorID() uint16

type Device

type Device interface {
	VendorID() uint16
	ProductID() uint16
	Path() string
	Release() uint16
	Serial() string
	Manufacturer() string
	Product() string
	Open() error
	Close() error
	Read(b []byte) (int, error)
	Write(b []byte) (int, error)
	GetFeatureReport(code byte) ([]byte, error)
}

type Event

type Event string
const (
	// Cross
	EventCrossPress   Event = "cross.press"
	EventCrossRelease Event = "cross.release"

	// Circle
	EventCirclePress   Event = "circle.press"
	EventCircleRelease Event = "circle.release"

	// Square
	EventSquarePress   Event = "square.press"
	EventSquareRelease Event = "square.release"

	// Triangle
	EventTrianglePress   Event = "triangle.press"
	EventTriangleRelease Event = "triangle.release"

	// L1
	EventL1Press   Event = "l1.press"
	EventL1Release Event = "l1.release"

	// L2
	EventL2Press   Event = "l2.press"
	EventL2Release Event = "l2.release"

	// L3
	EventL3Press   Event = "l3.press"
	EventL3Release Event = "l3.release"

	// R1
	EventR1Press   Event = "r1.press"
	EventR1Release Event = "r1.release"

	// R2
	EventR2Press   Event = "r2.press"
	EventR2Release Event = "r2.release"

	// R3
	EventR3Press   Event = "r3.press"
	EventR3Release Event = "r3.release"

	// D-pad up
	EventDPadUpPress   Event = "dpad_up.press"
	EventDPadUpRelease Event = "dpad_up.release"

	// D-pad down
	EventDPadDownPress   Event = "dpad_down.press"
	EventDPadDownRelease Event = "dpad_down.release"

	// D-pad left
	EventDPadLeftPress   Event = "dpad_left.press"
	EventDPadLeftRelease Event = "dpad_left.release"

	// D-pad right
	EventDPadRightPress   Event = "dpad_right.press"
	EventDPadRightRelease Event = "dpad_right.release"

	// Share
	EventSharePress   Event = "share.press"
	EventShareRelease Event = "share.release"

	// Options
	EventOptionsPress   Event = "options.press"
	EventOptionsRelease Event = "options.release"

	// Touchpad
	EventTouchpadSwipe   Event = "touchpad.swipe"
	EventTouchpadPress   Event = "touchpad.press"
	EventTouchpadRelease Event = "touchpad.release"

	// PS
	EventPSPress   Event = "ps.press"
	EventPSRelease Event = "ps.release"

	// Left stick
	EventLeftStickMove Event = "left_stick.move"

	// Right stick
	EventRightStickMove Event = "right_stick.move"

	// Accelerometer
	EventAccelerometerUpdate Event = "accelerometer.update"

	// Gyroscope
	EventGyroscopeUpdate Event = "gyroscope.update"

	// Battery
	EventBatteryUpdate Event = "battery.update"
)

type Gyroscope

type Gyroscope struct {
	Roll  int16
	Yaw   int16
	Pitch int16
}

type Stick

type Stick struct {
	X byte
	Y byte
}

type Touch

type Touch struct {
	IsActive bool
	X        byte
	Y        byte
}

type Touchpad

type Touchpad struct {
	Press bool
	Swipe []Touch
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL