windows-nt/Source/XPSP1/NT/base/mvdm/vdd/vjoy/vjoy.c
2020-09-26 16:20:57 +08:00

305 lines
6.7 KiB
C

/***************************************************************************
*
* vjoy.c
*
* Virtual (analog) joystick driver for ntvdm
*
* Copyright (c) 1991-1996 Microsoft Corporation. All Rights Reserved.
*
***************************************************************************/
/*****************************************************************************
*
* #includes
*
*****************************************************************************/
#include <windows.h> // The VDD is a win32 DLL
#include <vddsvc.h> // Definition of VDD calls
#include <ntddjoy.h>
#include <vjoy.h>
#define JOY_DRIVER_PATH L"\\\\.\\JOY1"
#define JOYSTICK_POLL_INTERVAL 100
JOY_DD_INPUT_DATA JoyData;
HANDLE hJoyDriver = INVALID_HANDLE_VALUE;
BOOL bInAnalogRead = FALSE;
BOOL bDataValid = FALSE;
ULONG ReadsSinceLastPortWrite = 0;
BOOL bEnabled = FALSE;
BOOL bAttemptedInit = FALSE;
UCHAR JoyFlags = 0xf;
USHORT TimeNdx;
ULONG Times[4];
UCHAR Values[4];
LONG InitialCount;
/*
* DLL entry point routine.
* Returns TRUE on success.
*/
BOOL WINAPI
DllEntryPoint(
HINSTANCE hInstance,
DWORD reason,
LPVOID reserved
)
{
static VDD_IO_PORTRANGE PortRange;
static VDD_IO_HANDLERS handlers = {
JoystickPortRead,
NULL,
NULL,
NULL,
JoystickPortWrite,
NULL,
NULL,
NULL};
switch (reason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInstance);
PortRange.First = JOYSTICK_PORT;
PortRange.Last = JOYSTICK_PORT;
if (!VDDInstallIOHook((HANDLE)hInstance, 1, &PortRange, &handlers)) {
return FALSE;
}
if (!JoystickInit()) {
VDDDeInstallIOHook((HANDLE)hInstance, 1, &PortRange);
return FALSE;
}
return TRUE;
case DLL_PROCESS_DETACH:
bEnabled = FALSE; // tell thread to exit
VDDDeInstallIOHook((HANDLE)hInstance, 1, &PortRange);
return TRUE;
default:
return TRUE;
}
}
BOOL
JoystickInit(
VOID
)
{
HANDLE tHandle;
ULONG ThreadId;
ULONG numread;
// BUGBUG: Should be using MM calls instead of this
hJoyDriver = CreateFile(JOY_DRIVER_PATH,
GENERIC_READ,
0,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
0,
(HANDLE) NULL);
if (hJoyDriver != INVALID_HANDLE_VALUE) {
if(!(tHandle = CreateThread(NULL, 0, JoystickPollThread,
NULL, CREATE_SUSPENDED, &ThreadId))) {
CloseHandle(hJoyDriver);
return FALSE;
}
bEnabled = TRUE;
//
// Do an initial read
//
if (ReadFile(hJoyDriver, &JoyData, sizeof(JOY_DD_INPUT_DATA), &numread, NULL)) {
bDataValid = TRUE;
} else {
bDataValid = FALSE;
}
ResumeThread(tHandle);
CloseHandle(tHandle);
}
return TRUE;
}
VOID
JoystickPortRead(
WORD port,
BYTE *pData
)
{
BYTE data = 0xff;
USHORT CurrentTime;
LONG TargetTime;
USHORT TargetCount;
LONG USecsElapsed;
ULONG TargetValue;
static USHORT LastWriteTime;
static LONG InitialCount;
if (!bAttemptedInit) {
bAttemptedInit = TRUE;
JoystickInit();
}
if (!bEnabled) {
*pData = data;
return;
}
if (bDataValid && !JoyData.Unplugged) {
//
// Get the button state
//
data = (BYTE) ((~JoyData.Buttons << 4) & 0xf0);
//
// Get the analog resistive inputs
//
if (bInAnalogRead) {
if (!ReadsSinceLastPortWrite) {
VdmParametersInfo(VDM_GET_TIMER0_INITIAL_COUNT, &InitialCount, sizeof(LONG));
VdmParametersInfo(VDM_GET_LAST_UPDATED_TIMER0_COUNT, &LastWriteTime, sizeof(USHORT));
VDM_TRACE(0x6a1, (USHORT) 0, LastWriteTime);
}
if (++ReadsSinceLastPortWrite > 256) {
// Too much time elapsed, we are done
VDM_TRACE(0x6bf, 0, 0);
if (JoyData.XTime) {
JoyFlags &= ~1;
}
if (JoyData.YTime) {
JoyFlags &= ~2;
}
if (JoyData.ZTime) {
JoyFlags &= ~4;
}
if (JoyData.TTime) {
JoyFlags &= ~8;
}
bInAnalogRead = FALSE;
} else {
TargetTime = (LONG)(LastWriteTime - (USHORT)(Times[TimeNdx]*3));
if (TargetTime < 0) {
TargetTime += InitialCount;
}
TargetCount = (USHORT) TargetTime;
VdmParametersInfo(VDM_SET_NEXT_TIMER0_COUNT, &TargetCount, sizeof(USHORT));
VDM_TRACE(0x6b2, Values[TimeNdx], TargetTime);
JoyFlags &= ~Values[TimeNdx];
if (++TimeNdx >= 4) {
bInAnalogRead = FALSE;
}
}
}
data += JoyFlags;
}
*pData = data;
// VDM_TRACE(0x6b0, data, 0);
}
VOID
JoystickPortWrite(
WORD port,
BYTE data
)
{
ULONG numread;
ULONG TTim;
CHAR TVal;
int i, j;
if (!bAttemptedInit) {
bAttemptedInit = TRUE;
JoystickInit();
}
ReadsSinceLastPortWrite = 0;
JoyFlags = 0xf;
Values[0] = 1;
Values[1] = 2;
Values[2] = 4;
Values[3] = 8;
Times[0] = JoyData.XTime;
Times[1] = JoyData.YTime;
Times[2] = JoyData.ZTime;
Times[3] = JoyData.TTime;
//
// Sort them
// Using just a bubble sort here with 4 items...
//
for (i=0; i<3; i++) {
for (j=0; j<3-i; j++) {
if (Times[j] > Times[j+1]) {
TTim = Times[j];
TVal = Values[j];
Times[j] = Times[j+1];
Values[j] = Values[j+1];
Times[j+1] = TTim;
Values[j+1] = TVal;
}
}
}
for (TimeNdx=0; TimeNdx<4; TimeNdx++) {
if (Times[TimeNdx]) {
break;
}
}
if (TimeNdx < 4) {
bInAnalogRead = TRUE;
}
for (i=0; i<4; i++) {
VDM_TRACE(0x6a0, (USHORT) Values[i], Times[i]);
}
}
DWORD WINAPI
JoystickPollThread(
LPVOID context
)
{
ULONG numread;
while(bEnabled) {
Sleep(JOYSTICK_POLL_INTERVAL);
if (ReadFile(hJoyDriver, &JoyData, sizeof(JOY_DD_INPUT_DATA), &numread, NULL)) {
bDataValid = TRUE;
} else {
bDataValid = FALSE;
}
}
return 0;
}