AxibugEmuOnline/References/virtuanessrc097-master/DirectInput.cpp
2024-08-05 17:58:53 +08:00

481 lines
26 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// DirectInput class
//
#include "DebugOut.h"
#include "DirectInput.h"
#include "COM.h"
#include "Config.h"
CDirectInput DirectInput;
#define COMUSE TRUE
//
// Table
//
CDirectInput::DIKEYTBL CDirectInput::DIKeyTable[] = {
DIK_ESCAPE, "ESC", DIK_1, "1",
DIK_2, "2", DIK_3, "3",
DIK_4, "4", DIK_5, "5",
DIK_6, "6", DIK_7, "7",
DIK_8, "8", DIK_9, "9",
DIK_0, "0", DIK_MINUS, "-",
DIK_EQUALS, "=", DIK_BACK, "BackSpace",
DIK_TAB, "TAB", DIK_Q, "Q",
DIK_W, "W", DIK_E, "E",
DIK_R, "R", DIK_T, "T",
DIK_Y, "Y", DIK_U, "U",
DIK_I, "I", DIK_O, "O",
DIK_P, "P", DIK_LBRACKET, "[",
DIK_RBRACKET, "]", DIK_RETURN, "Enter",
DIK_LCONTROL, "L Ctrl", DIK_A, "A",
DIK_S, "S", DIK_D, "D",
DIK_F, "F", DIK_G, "G",
DIK_H, "H", DIK_J, "J",
DIK_K, "K", DIK_L, "L",
DIK_SEMICOLON, ";", DIK_APOSTROPHE, "'",
DIK_GRAVE, "`", DIK_LSHIFT, "L Shift",
DIK_BACKSLASH, "\\", DIK_Z, "Z",
DIK_X, "X", DIK_C, "C",
DIK_V, "V", DIK_B, "B",
DIK_N, "N", DIK_M, "M",
DIK_COMMA, ",", DIK_PERIOD, ".",
DIK_SLASH, "/", DIK_RSHIFT, "R Shift",
DIK_MULTIPLY, "*", DIK_LMENU, "L Alt",
DIK_SPACE, "Space",
DIK_F1, "F1", DIK_F2, "F2",
DIK_F3, "F3", DIK_F4, "F4",
DIK_F5, "F5", DIK_F6, "F6",
DIK_F7, "F7", DIK_F8, "F8",
DIK_F9, "F9", DIK_F10, "F10",
DIK_NUMPAD7, "Num 7", DIK_NUMPAD8, "Num 8",
DIK_NUMPAD9, "Num 9", DIK_SUBTRACT, "Num -",
DIK_NUMPAD4, "Num 4", DIK_NUMPAD5, "Num 5",
DIK_NUMPAD6, "Num 6", DIK_ADD, "Num +",
DIK_NUMPAD1, "Num 1", DIK_NUMPAD2, "Num 2",
DIK_NUMPAD3, "Num 3", DIK_NUMPAD0, "Num 0",
DIK_DECIMAL, "Num .", DIK_F11, "F11",
DIK_F12, "F12", DIK_F13, "F13",
DIK_F14, "F14", DIK_F15, "F15",
DIK_CONVERT, "変換",
DIK_NOCONVERT, "無変換", DIK_YEN, "\\",
DIK_NUMPADEQUALS,"Num =", DIK_CIRCUMFLEX, "^",
DIK_AT, "@", DIK_COLON, ":",
DIK_UNDERLINE, "_",
DIK_STOP, "Stop", DIK_NUMPADENTER,"Num Enter",
DIK_RCONTROL, "R Ctrl", DIK_NUMPADCOMMA,"Num ,",
DIK_DIVIDE, "Num /", DIK_SYSRQ, "SysRq",
DIK_RMENU, "R Alt", DIK_PAUSE, "Pause",
DIK_HOME, "Home", DIK_UP, "Up",
DIK_PRIOR, "Page Up", DIK_LEFT, "Left",
DIK_RIGHT, "Right", DIK_END, "End",
DIK_DOWN, "Down", DIK_NEXT, "Page Down",
DIK_INSERT, "Insert", DIK_DELETE, "Delete",
DIK_LWIN, "L Windows", DIK_LWIN, "R Windows",
DIK_APPS, "AppMenu",
#if 0
// トグル系キーなので使えない
DIK_CAPITAL, "Caps Lock",
DIK_NUMLOCK, "NumLock",
DIK_SCROLL, "ScrollLock",
DIK_KANA, "カナ",
DIK_KANJI, "漢字",
#endif
0x00, NULL
};
LPSTR CDirectInput::DIKeyDirTable[] = {
"X+", "X-", "Y+", "Y-", "Z+", "Z-",
"RX+", "RX-", "RY+", "RY-", "RZ+", "RZ-",
"S0+", "S0-", "S1+", "S1-",
};
LPSTR CDirectInput::DIKeyDirTable2[] = {
"P0 Up", "P0 Down", "P0 Left", "P0 Right",
"P1 Up", "P1 Down", "P1 Left", "P1 Right",
"P2 Up", "P2 Down", "P2 Left", "P2 Right",
"P3 Up", "P3 Down", "P3 Left", "P3 Right",
};
//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////
CDirectInput::CDirectInput()
{
m_lpDI = NULL;
m_lpKeyboard = NULL;
m_nJoystickNum = 0;
ZEROMEMORY( m_lpJoystick, sizeof(m_lpJoystick) );
ZEROMEMORY( m_Sw, sizeof(m_Sw) );
ZEROMEMORY( m_JoyAxisMode, sizeof(m_JoyAxisMode) );
#if COMUSE
COM::AddRef();
#endif
}
CDirectInput::~CDirectInput()
{
ReleaseDInput();
#if COMUSE
COM::AddRef();
#endif
}
//////////////////////////////////////////////////////////////////////
// メンバ関数
//////////////////////////////////////////////////////////////////////
// デバイスオブジェクト列挙コールバック
BOOL CALLBACK CDirectInput::DIEnumDevicesCallback( LPDIDEVICEINSTANCE lpddi, LPVOID pvRef )
{
CDirectInput* pCDi = (CDirectInput*)pvRef;
// DEBUGOUT( "dwDevType=%08X IName:%s PName:%s\n", lpddi->dwDevType, lpddi->tszInstanceName, lpddi->tszProductName );
if( pCDi->AddJoystickDevice( lpddi->guidInstance ) )
return DIENUM_CONTINUE;
return DIENUM_STOP;
}
// ジョイスティックデバイスオブジェクトの作成
BOOL CDirectInput::AddJoystickDevice( GUID deviceguid )
{
LPDIRECTINPUTDEVICE7 lpDIDev;
if( m_lpDI->CreateDeviceEx( deviceguid, IID_IDirectInputDevice7,
(LPVOID*)&lpDIDev, NULL ) != DI_OK ) {
return FALSE;
}
if( lpDIDev->SetDataFormat( &c_dfDIJoystick ) != DI_OK ) {
DEBUGOUT( "CDirectInput:SetDataFormat failed.\n" );
RELEASE( lpDIDev );
return FALSE;
}
INT nID = m_nJoystickNum;
if( !Config.general.bNoJoystickID ) {
// DX7では隠し要素のジョイスティックIDの取得(DX8からはマニュアルに記載されている)
DIPROPDWORD diprp_dw;
ZEROMEMORY( &diprp_dw, sizeof(diprp_dw) );
diprp_dw.diph.dwSize = sizeof(DIPROPDWORD);
diprp_dw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprp_dw.diph.dwHow = DIPH_DEVICE;
diprp_dw.diph.dwObj = 0;
if( lpDIDev->GetProperty( DIPROP_JOYSTICKID, &diprp_dw.diph ) != DI_OK ) {
DEBUGOUT( "CDirectInput:GetProperty failed.\n" );
RELEASE( lpDIDev );
return FALSE;
}
DEBUGOUT( "ID:%d\n", diprp_dw.dwData );
nID = diprp_dw.dwData;
}
if( nID < DIJOYSTICK_MAX ) {
m_lpJoystick[ nID ] = lpDIDev;
// 各軸のレンジを設定
DIPROPRANGE diprg;
diprg.diph.dwSize = sizeof(DIPROPRANGE);
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprg.diph.dwHow = DIPH_BYOFFSET;
diprg.diph.dwObj = DIJOFS_X;
diprg.lMin = -10000;
diprg.lMax = +10000;
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
diprg.diph.dwObj = DIJOFS_Y;
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
diprg.diph.dwObj = DIJOFS_Z;
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
diprg.diph.dwObj = DIJOFS_RX;
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
diprg.diph.dwObj = DIJOFS_RY;
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
diprg.diph.dwObj = DIJOFS_RZ;
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
diprg.diph.dwObj = DIJOFS_SLIDER(0);
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
diprg.diph.dwObj = DIJOFS_SLIDER(1);
lpDIDev->SetProperty( DIPROP_RANGE, &diprg.diph );
// 名称の取得
DIDEVICEINSTANCE didins;
ZEROMEMORY( &didins, sizeof(didins) );
didins.dwSize = sizeof( didins );
lpDIDev->GetDeviceInfo( &didins );
m_JoyName[ nID ] = didins.tszInstanceName;
DEBUGOUT( "Instance Name:%s\n", didins.tszInstanceName );
//DEBUGOUT( "Product Name:%s\n", didins.tszProductName );
} else {
m_lpJoystick[ nID ] = NULL;
RELEASE( lpDIDev );
}
m_nJoystickNum++;
return TRUE;
}
// DirectInputオブジェクトデバイスオブジェクトの構築
BOOL CDirectInput::InitialDInput(HWND hWnd, HINSTANCE hInst)
{
try {
// CDirectInputオブジェクトの作成
#if !COMUSE
if( DirectInputCreateEx( hInst, DIRECTINPUT_VERSION, IID_IDirectInput7, (LPVOID*)&m_lpDI, NULL ) != DI_OK ) {
m_lpDI = NULL;
throw "CDirectInput:DirectInputCreateEx failed.";
}
#else
// COM的利用
// COM::AddRef();
if( FAILED(CoCreateInstance( CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER, IID_IDirectInput7, (VOID**)&m_lpDI )) ) {
m_lpDI = NULL;
throw "CDirectInput:CoCreateInstance failed.";
}
if( m_lpDI->Initialize( hInst, DIRECTINPUT_VERSION ) != DI_OK )
throw "CDirectInput:IDirectInput7->Initialize failed.";
#endif
if( m_lpDI->CreateDevice( GUID_SysKeyboard, &m_lpKeyboard, NULL ) != DI_OK )
throw "CDirectInput:CreateDevice failed.";
if( m_lpKeyboard ) {
if( m_lpKeyboard->SetDataFormat( &c_dfDIKeyboard ) != DI_OK )
throw "CDirectInput:SetDataFormat failed.";
if( m_lpKeyboard->SetCooperativeLevel( hWnd, DISCL_NONEXCLUSIVE|DISCL_BACKGROUND) != DI_OK )
throw "CDirectInput:SetCooperativeLevel failed.";
if( m_lpKeyboard->Acquire() != DI_OK ) {
// DEBUGOUT( "CDirectInput:Acquire failed.\n" );
}
}
m_nJoystickNum = 0;
if( m_lpDI->EnumDevices( DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesCallback,
(LPVOID)this, DIEDFL_ATTACHEDONLY ) != DI_OK ) {
DEBUGOUT( "CDirectInput:EnumDevices failed.\n" );
}
if( !m_nJoystickNum ) {
DEBUGOUT( "CDirectInput:No Joystick device available.\n" );
} else {
for( INT i = 0; i < DIJOYSTICK_MAX; i++ ) {
if( m_lpJoystick[i] ) {
if( m_lpJoystick[i]->SetCooperativeLevel( hWnd, DISCL_NONEXCLUSIVE|DISCL_BACKGROUND) != DI_OK ) {
DEBUGOUT( "CDirectInput:SetCooperativeLevel failed.\n" );
throw "CDirectInput:SetCooperativeLevel failed.";
}
}
}
DEBUGOUT( "CDirectInput:Can use %d Joystick(s)\n", m_nJoystickNum );
}
} catch( char *str ) {
ReleaseDInput();
MessageBox( hWnd, str, "ERROR", MB_ICONERROR|MB_OK );
return FALSE;
}
return TRUE;
}
void CDirectInput::ReleaseDInput()
{
for( INT i = 0; i < DIJOYSTICK_MAX; i++ ) {
RELEASE( m_lpJoystick[i] );
}
if( m_lpKeyboard ) {
// m_lpKeyboard->Unacquire();
RELEASE( m_lpKeyboard );
}
if( m_lpDI ) {
RELEASE( m_lpDI );
#if COMUSE
// COM::Release();
#endif
}
}
// 入力フォーカスを取得
void CDirectInput::Acquire()
{
if( !m_lpDI )
return;
if( m_lpKeyboard )
m_lpKeyboard->Acquire();
for( INT i = 0; i < DIJOYSTICK_MAX; i++ ) {
if( m_lpJoystick[i] ) {
m_lpJoystick[i]->Acquire();
}
}
}
// 入力フォーカスを開放
void CDirectInput::Unacquire()
{
if( !m_lpDI )
return;
if( m_lpKeyboard )
m_lpKeyboard->Unacquire();
for( INT i = 0; i < DIJOYSTICK_MAX; i++ ) {
if( m_lpJoystick[i] ) {
m_lpJoystick[i]->Unacquire();
}
}
}
// データポーリング
void CDirectInput::Poll()
{
DIJOYSTATE js;
ZEROMEMORY( m_Sw, sizeof(m_Sw) );
if( !m_lpDI ) {
return;
}
if( m_lpKeyboard ) {
if( m_lpKeyboard->GetDeviceState( 256, &m_Sw ) == DIERR_INPUTLOST ) {
m_lpKeyboard->Acquire();
m_lpKeyboard->GetDeviceState( 256, &m_Sw );
}
m_Sw[DIK_LCONTROL] =
m_Sw[DIK_RCONTROL] = (GetAsyncKeyState( VK_CONTROL ) < 0) ? 0x80 : 0;
}
INT idx;
for( INT i = 0; i < DIJOYSTICK_MAX; i++ ) {
if( !m_lpJoystick[i] )
continue;
idx = 256+i*64;
if( m_lpJoystick[i]->Poll() == DIERR_INPUTLOST ) {
m_lpJoystick[i]->Acquire();
m_lpJoystick[i]->Poll();
}
if( m_lpJoystick[i]->GetDeviceState( sizeof(DIJOYSTATE), &js ) != DI_OK ) {
ZEROMEMORY( &js, sizeof(DIJOYSTATE) );
}
m_JoyAxis[i][0] = js.lX;
m_JoyAxis[i][1] = js.lY;
m_JoyAxis[i][2] = js.lZ;
m_JoyAxis[i][3] = js.lRx;
m_JoyAxis[i][4] = js.lRy;
m_JoyAxis[i][5] = js.lRz;
if( !(m_JoyAxisMode[i] & (1<<0)) ) {
if( js.lX > 8000 ) m_Sw[idx + DI_XAXIS+0] = 0x80;
if( js.lX < -8000 ) m_Sw[idx + DI_XAXIS+1] = 0x80;
}
if( !(m_JoyAxisMode[i] & (1<<1)) ) {
if( js.lY > 8000 ) m_Sw[idx + DI_YAXIS+0] = 0x80;
if( js.lY < -8000 ) m_Sw[idx + DI_YAXIS+1] = 0x80;
}
if( !(m_JoyAxisMode[i] & (1<<2)) ) {
if( js.lZ > 8000 ) m_Sw[idx + DI_ZAXIS+0] = 0x80;
if( js.lZ < -8000 ) m_Sw[idx + DI_ZAXIS+1] = 0x80;
}
if( !(m_JoyAxisMode[i] & (1<<3)) ) {
if( js.lRx > 8000 ) m_Sw[idx + DI_RXAXIS+0] = 0x80;
if( js.lRx < -8000 ) m_Sw[idx + DI_RXAXIS+1] = 0x80;
}
if( !(m_JoyAxisMode[i] & (1<<4)) ) {
if( js.lRy > 8000 ) m_Sw[idx + DI_RYAXIS+0] = 0x80;
if( js.lRy < -8000 ) m_Sw[idx + DI_RYAXIS+1] = 0x80;
}
if( !(m_JoyAxisMode[i] & (1<<5)) ) {
if( js.lRz > 8000 ) m_Sw[idx + DI_RZAXIS+0] = 0x80;
if( js.lRz < -8000 ) m_Sw[idx + DI_RZAXIS+1] = 0x80;
}
#if 0
// 2003/11/3 とりあえず無効化
if( js.rglSlider[0] > 8000 ) m_Sw[idx + DI_SLIDER0+0] = 0x80;
if( js.rglSlider[0] < -8000 ) m_Sw[idx + DI_SLIDER0+1] = 0x80;
if( js.rglSlider[1] > 8000 ) m_Sw[idx + DI_SLIDER1+0] = 0x80;
if( js.rglSlider[1] < -8000 ) m_Sw[idx + DI_SLIDER1+1] = 0x80;
#endif
for( INT j = 0; j < 32; j++ ) {
m_Sw[idx + DI_BUTTON + j] = js.rgbButtons[j];
}
// POV
for( INT pov = 0; pov < 4; pov++ ) {
DWORD dwPOV = js.rgdwPOV[pov];
BOOL bPOVcenter = (LOWORD(dwPOV) == 0xFFFF);
BYTE data = 0;
if( !bPOVcenter ) {
static const BYTE dirtbl[] = {
(1<<0), (1<<0)|(1<<3), (1<<3), (1<<1)|(1<<3),
(1<<1), (1<<1)|(1<<2), (1<<2), (1<<0)|(1<<2),
};
data = dirtbl[ ((dwPOV+(DWORD)(22.5*DI_DEGREES)) % (360*DI_DEGREES))/(45*DI_DEGREES) ];
}
// Up/Down
if( data & (1<<0) ) m_Sw[idx + DI_POV0_UD+i*4+0] = 0x80;
if( data & (1<<1) ) m_Sw[idx + DI_POV0_UD+i*4+1] = 0x80;
// Left/Right
if( data & (1<<2) ) m_Sw[idx + DI_POV0_LR+i*4+0] = 0x80;
if( data & (1<<3) ) m_Sw[idx + DI_POV0_LR+i*4+1] = 0x80;
}
}
}
LPCSTR CDirectInput::SearchKeyName( INT key )
{
LPDIKEYTBL kt = DIKeyTable;
static CHAR KeyStr[256];
if( key == 0x00 )
return NULL;
if( key < 0x100 ) {
while( kt->name != NULL ) {
if( kt->key == key )
return kt->name;
kt++;
}
} else {
INT no = (key-256)>>6;
INT idx = key & 0x3F;
if( idx < DI_MAXAXIS ) {
::wsprintf( KeyStr, "J:%d %s", no, DIKeyDirTable[idx] );
return KeyStr;
} else if( idx >= DI_BUTTON && idx < DI_BUTTON_END ) {
::wsprintf( KeyStr, "J:%d B:%02d", no, idx-DI_BUTTON );
return KeyStr;
} else if( idx >= DI_EXT && idx < DI_EXT_END ) {
::wsprintf( KeyStr, "J:%d %s", no, DIKeyDirTable2[idx-DI_EXT] );
return KeyStr;
}
}
return NULL;
}