目錄

vJoystick

vJoystick

可橋接非遊戲控制器的任何設備與需要遊戲控制器的應用程式的設備驅動程序

http://vjoystick.sourceforge.net/joomla/

Download

https://sourceforge.net/projects/vjoystick/ or https://github.com/shauleiz/vJoy

vJoystick with UCR

Source Code : tajtiattila/vjoy

https://github.com/tajtiattila/vjoy

Include dll

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var dll = syscall.NewLazyDLL("vJoyInterface.dll")

var (
	procGetvJoyVersion            = dll.NewProc("GetvJoyVersion")
	procvJoyEnabled               = dll.NewProc("vJoyEnabled")
	procGetvJoyProductString      = dll.NewProc("GetvJoyProductString")
	procGetvJoyManufacturerString = dll.NewProc("GetvJoyManufacturerString")
	procGetvJoySerialNumberString = dll.NewProc("GetvJoySerialNumberString")
	procGetVJDButtonNumber        = dll.NewProc("GetVJDButtonNumber") // Get the number of buttons defined in the specified VDJ
	procGetVJDDiscPovNumber       = dll.NewProc("GetVJDDiscPovNumber") // Get the number of descrete-type POV hats defined in the specified VDJ
	procGetVJDContPovNumber       = dll.NewProc("GetVJDContPovNumber")
	procGetVJDAxisExist           = dll.NewProc("GetVJDAxisExist")
	procGetVJDAxisMax             = dll.NewProc("GetVJDAxisMax")
	procGetVJDAxisMin             = dll.NewProc("GetVJDAxisMin")
	procAcquireVJD                = dll.NewProc("AcquireVJD")
	procRelinquishVJD             = dll.NewProc("RelinquishVJD")
	procUpdateVJD                 = dll.NewProc("UpdateVJD")
	procGetVJDStatus              = dll.NewProc("GetVJDStatus")
	procResetVJD                  = dll.NewProc("ResetVJD")
	procResetAll                  = dll.NewProc("ResetAll")
	procResetButtons              = dll.NewProc("ResetButtons")
	procResetPovs                 = dll.NewProc("ResetPovs")
	procSetAxis                   = dll.NewProc("SetAxis")
	procSetBtn                    = dll.NewProc("SetBtn")
	procSetDiscPov                = dll.NewProc("SetDiscPov")
	procSetContPov                = dll.NewProc("SetContPov")
)

Variable

Axis values can be:

inc/public.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// HID Descriptor definitions - Axes
#define HID_USAGE_X   0x30  // X Axis
#define HID_USAGE_Y   0x31  // Y Axis
#define HID_USAGE_Z   0x32  // Z Axis
#define HID_USAGE_RX  0x33  // Rx Axis
#define HID_USAGE_RY  0x34  // Ry Axis
#define HID_USAGE_RZ  0x35  // Rz Axis
#define HID_USAGE_SL0 0x36  // Slider 0
#define HID_USAGE_SL1 0x37  // Slider 1
#define HID_USAGE_WHL 0x38  // Wheel
#define HID_USAGE_POV 0x39

// HID Descriptor definitions - FFB Effects
#define HID_USAGE_CONST 0x26    //    Usage ET Constant Force
#define HID_USAGE_RAMP  0x27    //    Usage ET Ramp
#define HID_USAGE_SQUR  0x30    //    Usage ET Square 正方形
#define HID_USAGE_SINE  0x31    //    Usage ET Sine
#define HID_USAGE_TRNG  0x32    //    Usage ET Triangle 三角形
#define HID_USAGE_STUP  0x33    //    Usage ET Sawtooth Up
#define HID_USAGE_STDN  0x34    //    Usage ET Sawtooth Down
#define HID_USAGE_SPRNG 0x40    //    Usage ET Spring
#define HID_USAGE_DMPR  0x41    //    Usage ET Damper
#define HID_USAGE_INRT  0x42    //    Usage ET Inertia
#define HID_USAGE_FRIC  0x43    //    Usage ET Friction


// HID Descriptor definitions - FFB Report IDs
#define HID_ID_STATE	0x02	// Usage PID State report
#define HID_ID_EFFREP	0x01	// Usage Set Effect Report
#define HID_ID_ENVREP	0x02	// Usage Set Envelope Report
#define HID_ID_CONDREP	0x03	// Usage Set Condition Report
#define HID_ID_PRIDREP	0x04	// Usage Set Periodic Report
#define HID_ID_CONSTREP	0x05	// Usage Set Constant Force Report
#define HID_ID_RAMPREP	0x06	// Usage Set Ramp Force Report
#define HID_ID_CSTMREP	0x07	// Usage Custom Force Data Report
#define HID_ID_SMPLREP	0x08	// Usage Download Force Sample
#define HID_ID_EFOPREP	0x0A	// Usage Effect Operation Report
#define HID_ID_BLKFRREP	0x0B	// Usage PID Block Free Report
#define HID_ID_CTRLREP	0x0C	// Usage PID Device Control
#define HID_ID_GAINREP	0x0D	// Usage Device Gain Report
#define HID_ID_SETCREP	0x0E	// Usage Set Custom Force Report
#define HID_ID_NEWEFREP	0x01	// Usage Create New Effect Report
#define HID_ID_BLKLDREP	0x02	// Usage Block Load Report
#define HID_ID_POOLREP	0x03	// Usage PID Pool Report

Value in the range 0x1-0x8000

dll/dll.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// constants used for GetVJDStatus()
const (
	VJD_STAT_OWN  = iota // The vJoy Device is owned by this application.
	VJD_STAT_FREE        // The vJoy Device is NOT owned by any application (including this one).
	VJD_STAT_BUSY        // The vJoy Device is owned by another application. It cannot be acquired by this application.
	VJD_STAT_MISS        // The vJoy Device is missing. It either does not exist or the driver is down.
	VJD_STAT_UNKN        // Unknown
)

const (
	HID_USAGE_X   = 0x30
	HID_USAGE_Y   = 0x31
	HID_USAGE_Z   = 0x32
	HID_USAGE_RX  = 0x33
	HID_USAGE_RY  = 0x34
	HID_USAGE_RZ  = 0x35
	HID_USAGE_SL0 = 0x36
	HID_USAGE_SL1 = 0x37
	HID_USAGE_WHL = 0x38
	HID_USAGE_POV = 0x39
)

type JOYSTICK_POSITION struct {
	Device     byte // Index of device. 1-based.
	Throttle   int32
	Rudder     int32
	Aileron    int32
	AxisX      int32
	AxisY      int32
	AxisZ      int32
	AxisXRot   int32
	AxisYRot   int32
	AxisZRot   int32
	Slider     int32
	Dial       int32
	Wheel      int32
	AxisVX     int32
	AxisVY     int32
	AxisVZ     int32
	AxisVBRX   int32
	AxisVBRY   int32
	AxisVBRZ   int32
	Buttons    int32  // 32 buttons: 0x00000001 means button1 is pressed, 0x80000000 -> button32 is pressed
	Hats       uint32 // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch
	HatsEx1    uint32 // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch
	HatsEx2    uint32 // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch
	HatsEx3    uint32 // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch
	ButtonsEx1 int32  // Buttons 33-64
	ButtonsEx2 int32  // Buttons 65-96
	ButtonsEx3 int32  // Buttons 97-128
}

Test vJoy Driver

Before you start, check if the vJoy driver is installed and check that it is what you expected:

dll/dll.go

1
2
3
4
5
// Returns wether vJoy version 2.x is installed and enabled.
func VJoyEnabled() bool {
	r, _, _ := procGetvJoyVersion.Call()
	return r != 0
}

Test Interface DLL

dll/proc.go

1
2
3
4
5
6
7
8
package dll

import (
	"syscall"
	"unsafe"
)

var dll = syscall.NewLazyDLL("vJoyInterface.dll")

dll/dll.go

1
2
3
4
package dll
func Load() error {
	return dll.Load()
}

vjoy.go

1
2
3
4
func Available() bool {
	err := dll.Load()
	return err == nil && dll.VJoyEnabled()
}

Test vJoy Virtual Devices

dll/dll.go

1
2
3
4
5
6
7
const (
	VJD_STAT_OWN  = iota // The vJoy Device is owned by this application.
	VJD_STAT_FREE        // The vJoy Device is NOT owned by any application (including this one).
	VJD_STAT_BUSY        // The vJoy Device is owned by another application. It cannot be acquired by this application.
	VJD_STAT_MISS        // The vJoy Device is missing. It either does not exist or the driver is down.
	VJD_STAT_UNKN        // Unknown
)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
type Device struct {
	rid           uint                  // rid Device opened with
	st            dll.JOYSTICK_POSITION // state for Update()
	noi           int32
	nou           uint32
	axes          []*Axis
	buttons       []*Button
	hats          []Hat
	invalidaxis   *Axis
	invalidbutton *Button
	invalidhat    Hat
}

Check which devices are installed and what their state is it. make sure that the axes, buttons (and POV hat switches) are as expected

vjoy.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
func (d *Device) init() error {
	d.st.Device = byte(d.rid)
	var err error
	switch dll.GetVJDStatus(d.rid) {
	case dll.VJD_STAT_OWN:
		return ErrDeviceAlreadyOwned
	case dll.VJD_STAT_FREE:
		// no op
	case dll.VJD_STAT_BUSY:
		err = ErrDeviceBusy
	case dll.VJD_STAT_MISS:
		err = ErrDeviceMissing
	default:
		//case VJD_STAT_UNKN:
		err = ErrDeviceUnknown
	}
	if !dll.AcquireVJD(d.rid) {
		return err
	}

	d.invalidaxis = &Axis{p: &d.noi, exists: false}
	d.invalidbutton = &Button{p: &d.noi, exists: false}
	d.invalidhat = &discreteHat{p: &d.nou, exists: false}

	d.axes = make([]*Axis, MaxAxis)
	for i := AxisName(0); i < MaxAxis; i++ {
		axn := axisNumber(i)
		a := &Axis{exists: dll.GetVJDAxisExist(d.rid, axn)}
		switch i {
		case AxisX:
			a.p = &d.st.AxisX
		case AxisY:
			a.p = &d.st.AxisY
		case AxisZ:
			a.p = &d.st.AxisZ
		case AxisRX:
			a.p = &d.st.AxisXRot
		case AxisRY:
			a.p = &d.st.AxisYRot
		case AxisRZ:
			a.p = &d.st.AxisZRot
		case Slider0:
			a.p = &d.st.Slider
		case Slider1:
			a.p = &d.st.Dial
		default:
			a.p = &d.noi // unused
		}
		if a.exists {
			dll.GetVJDAxisMin(d.rid, axn, &a.min)
			dll.GetVJDAxisMax(d.rid, axn, &a.max)
		}
		d.axes[i] = a
	}

	n := dll.GetVJDButtonNumber(d.rid)
	for i := 0; i < n; i++ {
		p, mask := d.button(i)
		if p != nil {
			d.buttons = append(d.buttons, &Button{p: p, exists: true, mask: mask})
		} else {
			d.buttons = append(d.buttons, d.invalidbutton)
		}
	}

	n = dll.GetVJDDiscPovNumber(d.rid)
	for i := 0; i < n; i++ {
		p, shift := d.dhat(i)
		if p != nil {
			d.hats = append(d.hats, &discreteHat{p: p, exists: true, shift: shift})
		}
	}

	n = dll.GetVJDContPovNumber(d.rid)
	for i := 0; i < n; i++ {
		p, shift := d.chat(i)
		if p != nil {
			d.hats = append(d.hats, &continuousHat{p: p, exists: true, shift: shift})
		}
	}

	return nil
}

Acquire the vJoy Device:

Until now you just made inquiries about the system and about the vJoy device status. In order to change the position of the vJoy device you need to Acquire it (if it is not already owned):

1
2
3
if !dll.AcquireVJD(d.rid) {
  return err
}

Feed vJoy Device

  1. Efficient: Collect position data, place the data in a position structure then finally send the data to the device.
  2. Robust: Reset the device once then send the position data for every control (axis, button,POV) at a time.

Relinquish the vJoy Device:

You must relinquish the device when the driver exits: RelinquishVJD(iInterface);

vjoy.go

1
2
3
4
// Relinquish closes an acquired device
func (d *Device) Relinquish() {
	dll.RelinquishVJD(d.rid)
}

dll/dll.go

1
2
3
4
5
// Relinquish the specified vJoy Device.
func RelinquishVJD(rID uint) bool {
	r, _, _ := procRelinquishVJD.Call(uintptr(rID))
	return r != 0
}

Interface Function Reference:

General driver data

vJoyEnabled

Returns TRUE if vJoy version 2.x is installed and enabled.

1
VJOYINTERFACE_API BOOL	__cdecl vJoyEnabled(void);
GetvJoyVersion

Return the version number of the installed vJoy. To be used only after vJoyEnabled()

1
VJOYINTERFACE_API SHORT __cdecl GetvJoyVersion(void);
GetvJoyProductString / GetvJoyManufacturerString / GetvJoySerialNumberString

These functions return an LPTSTR that points to the correct data (Product, Manufacturer or Serial number). To be used only after vJoyEnabled()

1
2
3
VJOYINTERFACE_API PVOID	__cdecl	GetvJoyProductString(void);
VJOYINTERFACE_API PVOID	__cdecl	GetvJoyManufacturerString(void);
VJOYINTERFACE_API PVOID	__cdecl	GetvJoySerialNumberString(void);
DriverMatch

Returns TRUE if vJoyInterface.dll file version and vJoy Driver version are identical. Otherwise returns FALSE. Optional (You may pass NULL): Output parameter DllVer: If a pointer to WORD is passed then the value of the DLL file version will be written to this parameter (e.g. 0x215). Output parameter DrvVer: If a pointer to WORD is passed then the value of the Driver version will be written to this parameter (e.g. 0x215).

1
VJOYINTERFACE_API BOOL	__cdecl	DriverMatch(WORD * DllVer, WORD * DrvVer);
RegisterRemovalCB
  • This function registers a user-defined ConfChangedCB callback fuction that is called everytime a vJoy device is added or removed. Paremeter ConfChangedCB is a pointer to the user-defined callback function. Parameter UserData is a pointer to a user-defined data item. The callback function recieves this pointer as its third parameter. More in section Detecting Changes.
1
VJOYINTERFACE_API VOID	__cdecl	RegisterRemovalCB(RemovalCB cb, PVOID data);

__cdecl : https://docs.microsoft.com/zh-tw/cpp/cpp/cdecl?view=msvc-170 __declspec : https://docs.microsoft.com/zh-tw/cpp/cpp/declspec?view=msvc-170

Write access to vJoy Device

The following functions access the virtual device by its ID (rID). The value of rID may vary between 1 and 16. There may be more than one virtual device installed on a given system. VJD stands for Virtual Joystick Device.

GetVJDStatus

Returns the status of the specified device The status can be one of the following values:

1
2
3
4
5
• VJD_STAT_OWN  // The vJoy Device is owned by this application.
• VJD_STAT_FREE // The vJoy Device is NOT owned by any application (including this one).
• VJD_STAT_BUSY // The vJoy Device is owned by another application. It cannot be acquired by this application.
• VJD_STAT_MISS // The vJoy Device is missing. It either does not exist or the driver is disabled. 
• VJD_STAT_UNKN // Unknown
1
VJOYINTERFACE_API enum VjdStat	__cdecl	GetVJDStatus(UINT rID); // Get the status of the specified vJoy Device.
[v2.1.6] isVJDExists

Returns TRUE if the specified device exists (Configured and enabled). Returns FALSE otherwise (Including the following cases: Device does not exist, disabled, driver not installed)

1
2
// Added in 2.1.6
VJOYINTERFACE_API BOOL	__cdecl	isVJDExists(UINT rID); // TRUE if the specified vJoy Device exists
[v2.1.8] GetOwnerPid

Returns the Process ID (PID) of the process that owns the specified device. If the device is owned by a process, then the function returns a positive integer which is the PID of the owner. Otherwise, the function returns one of the following negative numbers: NO_FILE_EXIST (-13): Usually indicates a FREE device (No owner) NO_DEV_EXIST (-12): Usually indicates a MISSING device BAD_DEV_STAT (-11): Indicates some internal problem

1
2
// Added in 2.1.8
VJOYINTERFACE_API int	__cdecl	GetOwnerPid(UINT rID); // Reurn owner's Process ID if the specified vJoy Device exists

Write access to vJoy Device - Basic

AcquireVJD

Acquire the specified device. Only a device in state VJD_STAT_FREE can be acquired. If acquisition is successful the function returns TRUE and the device status becomes VJD_STAT_OWN.

1
VJOYINTERFACE_API BOOL		__cdecl	AcquireVJD(UINT rID); // Acquire the specified vJoy Device.
RelinquishVJD

Relinquish the previously acquired specified device. Use only when device is state VJD_STAT_OWN. State becomes VJD_STAT_FREE immediately after this function returns.

1
VJOYINTERFACE_API VOID		__cdecl	RelinquishVJD(UINT rID); // Relinquish the specified vJoy Device.
UpdateVJD

Update the position data of the specified device. Use only after device has been successfully acquired. Input parameter is a pointer to structure of type JOYSTICK_POSITION that holds the position data. Returns TRUE if device updated.

1
VJOYINTERFACE_API BOOL		__cdecl	UpdateVJD(UINT rID, PVOID pData); // Update the position data of the specified vJoy Device.

vJoy Device properties

The following functions receive the virtual device ID (rID) and return the relevant data. The value of rID may vary between 1 and 16. There may be more than one virtual device installed on a given system. The return values are meaningful only if the specified device exists VJD stands for Virtual Joystick Device.

GetVJDButtonNumber

If function succeeds, returns the number of buttons in the specified device. Valid values are 0 to 128 If function fails, returns a negative error code: • NO_HANDLE_BY_INDEX • BAD_PREPARSED_DATA • NO_CAPS • BAD_N_BTN_CAPS • BAD_BTN_CAPS • BAD_BTN_RANGE

1
VJOYINTERFACE_API int	__cdecl  GetVJDButtonNumber(UINT rID); // Get the number of buttons defined in the specified VDJ
GetVJDDiscPovNumber

Returns the number of discrete-type POV hats in the specified device Discrete-type POV Hat values may be North, East, South, West or neutral Valid values are 0 to 4 (from version 2.0.1)

1
VJOYINTERFACE_API int	__cdecl  GetVJDDiscPovNumber(UINT rID); // Get the number of descrete-type POV hats defined in the specified VDJ
GetVJDContPovNumber

Returns the number of continuous-type POV hats in the specified device continuous-type POV Hat values may be 0 to 35900 Valid values are 0 to 4 ( from version 2.0.1)

1
VJOYINTERFACE_API int	__cdecl  GetVJDContPovNumber(UINT rID); // Get the number of descrete-type POV hats defined in the specified VDJ
GetVJDAxisExist

Returns TRUE is the specified axis exists in the specified device Axis values can be:

1
2
3
4
5
6
7
8
9
HID_USAGE_X // X Axis
HID_USAGE_Y // Y Axis 
HID_USAGE_Z // Z Axis
HID_USAGE_RX // Rx Axis
HID_USAGE_RY // Ry Axis
HID_USAGE_RZ // Rz Axis
HID_USAGE_SL0  // Slider 0
HID_USAGE_SL1  // Slider 1
HID_USAGE_WHL // Wheel
1
VJOYINTERFACE_API BOOL	__cdecl  GetVJDAxisExist(UINT rID, UINT Axis); // Test if given axis defined in the specified VDJ

Robust write access to vJoy Devices

The following functions receive the virtual device ID (rID) and return the relevant data. These functions hide the details of the position data structure by allowing you to alter the value of a specific control. The downside of these functions is that you inject the data to the device serially as opposed to function UpdateVJD(). The value of rID may vary between 1 and 16. There may be more than one virtual device installed on a given system.

ResetVJD

Resets all the controls of the specified device to a set of values. These values are hard coded in the interface DLL and are currently set as follows: • Axes X, Y & Z: Middle point. • All other axes: 0. • POV Switches: Neutral (-1) • Buttons: Not Pressed (0).

1
VJOYINTERFACE_API BOOL		__cdecl	ResetVJD(UINT rID); // Reset all controls to predefined values in the specified VDJ
ResetAll

Resets all the controls of the all devices to a set of values. See function Reset VJD for details.

1
VJOYINTERFACE_API VOID		__cdecl	ResetAll(void); // Reset all controls to predefined values in all VDJ
ResetButtons

Resets all buttons (To 0) in the specified device.

1
VJOYINTERFACE_API BOOL		__cdecl	ResetButtons(UINT rID); // Reset all buttons (To 0) in the specified VDJ
ResetPovs

Resets all POV Switches (To -1) in the specified device.

1
VJOYINTERFACE_API BOOL		__cdecl	ResetPovs(UINT rID); // Reset all POV Switches (To -1) in the specified VDJ
SetAxis

Write Value to a given axis defined in the specified VDJ. Value in the range 0x1-0x8000 Axis can be one of the following:

HID_USAGE_X // X Axis HID_USAGE_Y // Y Axis HID_USAGE_Z // Z Axis HID_USAGE_RX // Rx Axis HID_USAGE_RY // Ry Axis HID_USAGE_RZ // Rz Axis HID_USAGE_SL0 // Slider 0 HID_USAGE_SL1 // Slider 1 HID_USAGE_WHL // Wheel

1
VJOYINTERFACE_API BOOL		__cdecl	SetAxis(LONG Value, UINT rID, UINT Axis);		// Write Value to a given axis defined in the specified VDJ 
SetBtn

Write Value (TRUE or FALSE) to a given button defined in the specified VDJ. nBtn can in the range 1-128

1
VJOYINTERFACE_API BOOL		__cdecl	SetBtn(BOOL Value, UINT rID, UCHAR nBtn);		// Write Value to a given button defined in the specified VDJ 
SetDiscPov

Write Value to a given discrete POV defined in the specified VDJ Value can be one of the following: 0: North (or Forwards) 1: East (or Right) 2: South (or backwards) 3: West (or left) -1: Neutral (Nothing pressed) nPov selects the destination POV Switch. It can be 1 to 4

1
VJOYINTERFACE_API BOOL		__cdecl	SetDiscPov(int Value, UINT rID, UCHAR nPov); // Write Value to a given descrete POV defined in the specified VDJ 
SetContPov

Write Value to a given continuous POV defined in the specified VDJ Value can be in the range: -1 to 35999. It is measured in units of one-hundredth a degree. -1 means Neutral (Nothing pressed). nPov selects the destination POV Switch. It can be 1 to 4

1
VJOYINTERFACE_API BOOL		__cdecl	SetContPov(DWORD Value, UINT rID, UCHAR nPov);	// Write Value to a given continuous POV defined in the specified VDJ 

FFB Functions

The following functions are used for accessing and manipulating Force Feedback data.

FfbRegisterGenCB

Register a FFB callback function that will be called by the driver every time a FFB data packet arrives. For additional information see Receptor Unit section.

1
VJOYINTERFACE_API VOID		__cdecl	FfbRegisterGenCB(FfbGenCB cb, PVOID data);
FfbStart

Enable the FFB mechanism of the specified VDJ Return TRUE on success. Otherwise return FALSE.

1
VJOYINTERFACE_API BOOL		__cdecl	FfbStart(UINT rID);	// Start the FFB queues of the specified vJoy Device.
FfbStop

Disable the FFB mechanism of the specified VDJ

1
VJOYINTERFACE_API VOID		__cdecl	FfbStop(UINT rID);				  // Stop the FFB queues of the specified vJoy Device.
IsDeviceFfb

Return TRUE if specified device supports FFB. Otherwise return FALSE.

1
VJOYINTERFACE_API BOOL		__cdecl	IsDeviceFfb(UINT rID);
IsDeviceFfbEffect

Return TRUE if specified device supports a specific FFB Effect. Otherwise return FALSE. The FFB Effect is indicated by its Usage. List of effect Usages:

HID_USAGE_CONST (0x26):Usage ET Constant Force Usage HID_USAGE_RAMP (0x27): ET Ramp HID_USAGE_SQUR (0x30): Usage ET Square HID_USAGE_SINE (0x31): Usage ET Sine HID_USAGE_TRNG (0x32): Usage ET Triangle HID_USAGE_STUP (0x33): Usage ET Sawtooth Up HID_USAGE_STDN (0x34): Up Usage ET Sawtooth Down HID_USAGE_SPRNG (0x40): Usage ET Spring HID_USAGE_DMPR (0x41): Usage ET Damper HID_USAGE_INRT (0x42): Usage ET Inertia HID_USAGE_FRIC (0x43): Usage ET Friction

1
VJOYINTERFACE_API BOOL		__cdecl	IsDeviceFfbEffect(UINT rID, UINT Effect);

FFB Helper Functions

Ffb_h_DeviceID

Get the origin of the FFB data packet. If valid device ID was found then returns ERROR_SUCCESS and sets the ID (Range 1-15) in DeviceID. If Packet is NULL then returns ERROR_INVALID_PARAMETER. DeviceID is undefined. If Packet is malformed or Device ID is out of range then returns ERROR_INVALID_DATA. DeviceID is undefined.

1
VJOYINTERFACE_API DWORD 	__cdecl	Ffb_h_DeviceID(const FFB_DATA * Packet, int *DeviceID);
Ffb_h_Type

Get the type of the FFB data packet. Type may be one of the following: // Write PT_EFFREP // Usage Set Effect Report PT_ENVREP // Usage Set Envelope Report PT_CONDREP // Usage Set Condition Report PT_PRIDREP // Usage Set Periodic Report PT_CONSTREP // Usage Set Constant Force Report PT_RAMPREP // Usage Set Ramp Force Report PT_CSTMREP // Usage Custom Force Data Report PT_SMPLREP // Usage Download Force Sample PT_EFOPREP // Usage Effect Operation Report PT_BLKFRREP // Usage PID Block Free Report PT_CTRLREP // Usage PID Device Control PT_GAINREP // Usage Device Gain Report PT_SETCREP // Usage Set Custom Force Report

// Feature PT_NEWEFREP // Usage Create New Effect Report PT_BLKLDREP // Usage Block Load Report PT_POOLREP // Usage PID Pool Report

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_Type(const FFB_DATA * Packet, FFBPType *Type);

If valid Type was found then returns ERROR_SUCCESS and sets Type. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Feature is undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Feature is undefined.

Ffb_h_Packet

Extract the raw FFB data packet and the command type (Write/Set Feature). If valid Packet was found then returns ERROR_SUCCESS and - Sets Type to IOCTRL value (Expected values are IOCTL_HID_WRITE_REPORT and IOCTL_HID_SET_FEATURE). Sets DataSize to the size (in bytes) of the payload data (FFB_DATA.data ). Sets Data to the payload data (FFB_DATA.data ) - this is an array of bytes. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_Packet(const FFB_DATA * Packet, WORD *Type, int *DataSize, BYTE *Data[]);
Ffb_h_EBI

Get the Effect Block Index If valid Packet was found then returns ERROR_SUCCESS and sets Index to the value of Effect Block Index (if applicable). Expected value is ‘1’. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed or does not contain an Effect Block Index then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_EBI(const FFB_DATA * Packet, int *Index);
Ffb_h_Eff_Const

Get parameters of an Effect of type Constant (PT_EFFREP) Effect structure (FFB_EFF_CONST) definition:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 typedef
struct _FFB_EFF_CONST{
	BYTE EffectBlockIndex; // Usually 1
	FFBEType EffecType; // ET_CONST(1)
	WORD Duration; // Value in milliseconds. 0xFFFF means infinite
	WORD TrigerRpt;
	WORD SamplePrd;
	BYTE Gain;
	BYTE TrigerBtn;
	BOOL Polar; // How to interpret force direction Polar (0-360°) or Cartesian (X,Y)

	union(
		BYTE Direction; // Polar direction: (0x00-0xFF correspond to 0-360°)
		BYTE DirX; // X direction:
					// Positive values are To the right of the centre (X);
					// Negative are Two's complement
	);
	BYTE DirY; // Y direction:
				// Positive values are below the centre (Y);
				// Negative are Two's complement
} FFB_EFF_CONST;

If Constant Effect Packet was found then returns ERROR_SUCCESS and fills structure Effect If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_Eff_Const(const FFB_DATA * Packet, FFB_EFF_CONST*  Effect);
Ffb_h_Eff_Ramp

Get parameters of an Effect of type Ramp (PT_RAMPREP) Effect structure (FFB_EFF_RAMP) definition:

1
2
3
4
5
typedef struct _FFB_EFF_RAMP {
	BYTE EffectBlockIndex; // Usually 1
	BYTE Start; // The Normalized magnitude at the start of the effect
	BYTE End; // The Normalized magnitude at the end of the effect
} FFB_EFF_RAMP;

If Ramp effect Packet was found then returns ERROR_SUCCESS and fills structure Effect. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD		__cdecl Ffb_h_Eff_Ramp(const FFB_DATA * Packet, FFB_EFF_RAMP*  RampEffect);
Ffb_h_EffOp

Get parameters of an Effect of type Operation (PT_EFOPREP) that describe the effect operation (Start/Solo/Stop) and loop count. Effect structure (FFB_EFF_OP) definition:

1
2
3
4
5
typedef struct _FFB_EFF_OP {
	BYTE EffectBlockIndex; // Usually 1
	FFBOP EffectOp; // Operation (EFF_START(1)/EFF_SOLO(2)/EFF_STOP(3))
	BYTE LoopCount; // Number of repetitions
} FFB_EFF_OP;

If Operation Effect Packet was found then returns ERROR_SUCCESS and fills structure Operation- this structure holds Effect Block Index, Operation(Start, Start Solo, Stop) and Loop Count. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_EffOp(const FFB_DATA * Packet, FFB_EFF_OP*  Operation);
Ffb_h_Eff_Period

Get parameters of an Effect of type Periodic (PT_PRIDREP) that describe the periodic attribute of an effect. Effect structure (FFB_EFF_PERIOD) definition:

1
2
3
4
5
6
7
typedef struct _FFB_EFF_PERIOD {
	BYTE EffectBlockIndex; // Usually 1
	BYTE Magnitude;
	BYTE Offset;
	BYTE Phase;
	WORD Period;
} FFB_EFF_PERIOD;

If Periodic Packet was found then returns ERROR_SUCCESS and fills structure Effect – this structure holds Effect Block Index, Magnitude, Offset, Phase and period. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_Eff_Period(const FFB_DATA * Packet, FFB_EFF_PERIOD*  Effect);
Ffb_h_Eff_Cond

Get parameters of an Effect of type Conditional (PT_CONDREP). Effect structure (FFB_EFF_COND) definition:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
typedef struct _FFB_EFF_COND {
	BYTE EffectBlockIndex; // Usually 1
	BOOL isY;
	BYTE CenterPointOffset; // CP Offset: Range 10000 to 10000
	BYTE PosCoeff; // Positive Coefficient: Range 10000 to 10000
	BYTE NegCoeff; // Negative Coefficient: Range 10000 to 10000
	BYTE PosSatur; // Positive Saturation: Range 0 – 10000
	BYTE NegSatur; // Negative Saturation: Range 0 – 10000
	BYTE DeadBand; // Dead Band: : Range 0 – 10000
} FFB_EFF_COND;

If Condition Packet was found then returns ERROR_SUCCESS and fills structure Condition - this structure holds Effect Block Index, Direction (X/Y), Centre Point Offset, Dead Band and other conditions. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_Eff_Cond(const FFB_DATA * Packet, FFB_EFF_COND*  Condition);
Ffb_h_Eff_Envlp

Get parameters of an Effect of type Envelope (PT_ENVREP). Effect structure (FFB_EFF_ENVLP) definition:

1
2
3
4
5
6
7
typedef struct _FFB_EFF_ENVLP {
	BYTE EffectBlockIndex; // Usually 1
	BYTE AttackLevel;
	BYTE FadeLevel;
	WORD AttackTime;
	WORD FadeTime;
} FFB_EFF_ENVLP;

If Envelope Packet was found then returns ERROR_SUCCESS and fills structure Envelope If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD		__cdecl Ffb_h_Eff_Envlp(const FFB_DATA * Packet, FFB_EFF_ENVLP*  Envelope);
Ffb_h_EffNew

Get the type of the next effect. Parameter Effect can get one of the following values:

ET_NONE = 0 // No Force ET_CONST = 1 // Constant Force ET_RAMP = 2 // Ramp ET_SQR = 3 // Square ET_SINE = 4 // Sine ET_TRNGL = 5 // Triangle ET_STUP = 6 // Sawtooth Up ET_STDN = 7 // Sawtooth Down ET_SPRNG = 8 // Spring ET_DMPR = 9 // Damper ET_INRT = 10 // Inertia ET_FRCTN = 11 // Friction ET_CSTM = 12 // Custom Force Data

If valid Packet was found then returns ERROR_SUCCESS and sets the new Effect type If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD		__cdecl Ffb_h_EffNew(const FFB_DATA * Packet, FFBEType * Effect);
Ffb_h_Eff_Constant

Get parameters of an Effect of type Constant ( ). If Constant Packet was found then returns ERROR_SUCCESS and fills structure ConstantEffect If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

1
VJOYINTERFACE_API DWORD		__cdecl Ffb_h_Eff_Constant(const FFB_DATA * Packet, FFB_EFF_CONSTANT *  ConstantEffect);
Ffb_h_DevCtrl

Get device-wide control instructions. Control can get one of the following values:

CTRL_ENACT = 1 // Enable all device actuators. CTRL_DISACT = 2 // Disable all the device actuators. CTRL_STOPALL = 3 // Stop All Effects Issues a stop on every running effect. CTRL_DEVRST = 4 // Device Reset. Clears any device paused condition, enables all actuators and clears all effects from memory. CTRL_DEVPAUSE = 5 // Device Pause. All effects on the device are paused at the current.time step. CTRL_DEVCONT = 6 // Device Continue. All effects that running when the device was paused are restarted from their last time step.

1
VJOYINTERFACE_API DWORD 	__cdecl Ffb_h_DevCtrl(const FFB_DATA * Packet, FFB_CTRL *  Control);
Ffb_h_DevGain

Get device Global gain in parameter Gain. If valid Packet was found then returns ERROR_SUCCESS and gets the device global gain. If Packet is NULL then returns ERROR_INVALID_PARAMETER. Output parameters are undefined. If Packet is malformed then returns ERROR_INVALID_DATA. Output parameters are undefined.

XOutput

將遊戲控制器的輸入轉換爲 Xbox 360 的信號輸入 https://github.com/csutorasa/XOutput

ViGEmBus

XOutput需要的一個Windows遊戲控制器模擬器 https://github.com/ViGEm/ViGEmBus

Test

https://gamepad-tester.com/

Reference