www.gusucode.com > VC++游戏圣剑英雄传2双刃剑源程序+开发文档-源码程序 > VC++游戏圣剑英雄传2双刃剑源程序+开发文档-源码程序\code\source\GAMELIB\Gp_input.cpp
//Download by http://www.NewXing.com //******************************************** // DirectInput 相关处理函数 //******************************************** #include <windows.h> #include <stdio.h> #include <dinput.h> #include "gp_other.h" #include "gp_init.h" #include "gp_input.h" //全局通用对象 CMouse Mouse; //鼠标 CKey Key; //键盘 CJoystick g_Joystick; //手柄 extern HWND hWnd; extern HINSTANCE hInst; extern BOOL bActive; #if USE_DX8 LPDIRECTINPUT8 lpDI; //DINPUT设备 #else LPDIRECTINPUT lpDI; //DINPUT设备 #endif ///////////////////////////////////////////////////////////////// //INPUT ///////////////////////////////////////////////////////////////// //初始化DIRECTINPUT bool WINAPI InitInput() { HRESULT hr; #if USE_DX8 hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8,(void**)&lpDI, NULL ); #else hr = DirectInputCreate( hInst, DIRECTINPUT_VERSION, &lpDI, NULL ); #endif if ( FAILED(hr) ) { MessageBox(hWnd,"Create DirectInput","Failed",MB_OK); return false; } return true; } //释放DIRECTINPUT void WINAPI FreeInput() { _RELEASE( lpDI ); } ///////////////////////////////////////////////////////////////// //MOUSE ///////////////////////////////////////////////////////////////// //初始化鼠标 HRESULT WINAPI CMouse::InitInput_Mouse( HWND hDlg ) { HRESULT hr; //创建设备 hr = lpDI->CreateDevice( GUID_SysMouse, &g_pMouse, NULL ); if ( FAILED(hr) ) { MessageBox(hWnd,"Create Mouse Device","Failed",MB_OK); return hr; } //数据格式 hr = g_pMouse->SetDataFormat( &c_dfDIMouse ); if ( FAILED(hr) ) { MessageBox(hWnd,"Set Mouse Data Format","Failed",MB_OK); return hr; } //协作级 hr = g_pMouse->SetCooperativeLevel( hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); if ( FAILED(hr) ) { MessageBox(hWnd,"Set Mouse Cooperative Level","Failed",MB_OK); return hr; } //属性 DIPROPDWORD property; property.diph.dwSize=sizeof(DIPROPDWORD); property.diph.dwHeaderSize=sizeof(DIPROPHEADER); property.diph.dwObj=0; property.diph.dwHow=DIPH_DEVICE; property.dwData=16; hr = g_pMouse->SetProperty(DIPROP_BUFFERSIZE, &property.diph); if (FAILED(hr)) { MessageBox(hWnd,"Set Mouse Property","Failed",MB_OK); return hr; } //获取 hr = g_pMouse->Acquire(); if FAILED(hr) { return hr; } return true; } //获取设备 HRESULT WINAPI CMouse::SetAcquire( HWND hDlg ) { if (NULL == g_pMouse) return S_FALSE; if (bActive) { g_pMouse->Acquire(); } else { g_pMouse->Unacquire(); } return S_OK; } //释放DIRECTINPUT设备MOUSE void WINAPI CMouse::FreeInput_Mouse() { if( g_pMouse ) { g_pMouse->Unacquire(); g_pMouse->Release(); g_pMouse=NULL; } } //获取缓冲区数据 unsigned char WINAPI CMouse::GetMouseData() { if( g_pMouse ) { _Begin: DIDEVICEOBJECTDATA data; DWORD elements=1; //一个元素 HRESULT hr = g_pMouse->GetDeviceData(sizeof(data), &data, &elements, 0); if FAILED(hr) { if(hr == DIERR_INPUTLOST) { hr = g_pMouse->Acquire(); } } else { if(elements == 1) { switch(data.dwOfs) { case DIMOFS_X: //忽略移动数据 case DIMOFS_Y: goto _Begin; break; case DIMOFS_BUTTON0: if( data.dwData & 0x80 ) //高位为1:按下 return LB_DOWN; return LB_UP; //否则释放 break; case DIMOFS_BUTTON1: if( data.dwData & 0x80 ) return RB_DOWN; return RB_UP; break; } } else if(elements==0) return 0; } } return 0; } //清空鼠标缓冲区 void WINAPI CMouse::ReleaseMouseBuffer() { while(1) { if( GetMouseData()== 0 ) break; } } //************************** //获取鼠标当前状态(经新浪网友wing_of_dream改进) //没有太多改进,仅仅测试一下是否没有获取过鼠标设备 void WINAPI CMouse::GetMouseState() { if (g_pMouse) { DIMOUSESTATE dims; HRESULT hr; _again: hr = g_pMouse->GetDeviceState(sizeof(DIMOUSESTATE), &dims);//得到当前状态 if( FAILED(hr) ) { hr = g_pMouse->Acquire(); //重新获取 if(!( hr== DI_OK)) { for (int i=0;i<50;i++) { if ((hr = g_pMouse->Acquire()) == DI_OK) break; } } if (SUCCEEDED(hr)) { goto _again; } } if( hr == DIERR_NOTACQUIRED ) { return; } //获取鼠标按键信息 if( SUCCEEDED( hr )) { if( dims.rgbButtons[0] & 0x80 ) //按下 MouseButton[0]=1; else MouseButton[0]=0; //没有按下 if( dims.rgbButtons[1] & 0x80 ) MouseButton[1]=1; else MouseButton[1]=0; } } } //等待鼠标输入,程序中断 bool WINAPI CMouse::WaitMouse(char act) { char Button=GetMouseData(); while( Button != act ) { Button=GetMouseData(); } return true; } //某键当前是否按下 0=左 1=右 2=中 4=左右 bool WINAPI CMouse::IsButton( char Button ) { GetMouseState(); if( Button==4 ) { if( MouseButton[0] && MouseButton[1] ) //按下 while(1) { GetMouseState(); if( GetAsyncKeyState( VK_RETURN ) ) break; if( !MouseButton[0] || !MouseButton[1] ) //松开 return true; } } else if( MouseButton[Button] ) //按下 while(1) { GetMouseState(); if( GetAsyncKeyState( VK_RETURN ) ) break; if( !MouseButton[Button] ) //松开 return true; } return false; } //返回当前按下某键 0=左 1=右 2=中 4=左右 -1=无 char WINAPI CMouse::DownButton() { GetMouseState(); if( MouseButton[0] && MouseButton[1] ) //左右 return 4; if( MouseButton[0] ) //左 return 0; if( MouseButton[1] ) //右 return 1; return -1; } ///////////////////////////////////////////////////////////////// //KEYBOARD ///////////////////////////////////////////////////////////////// CKey::CKey() { memset( KeyState, 0, 256); memset( KeyBuffer, 0, KEYBUFFERSIZE ); KeyBuffer_Start = KeyBuffer_End = 0; } CKey::~CKey() { } //初始化DIRECTINPUT设备 bool WINAPI CKey::InitInput_Key(HWND hWnd) { HRESULT hr; //返回一个DIRECTINPUT设备的指针 hr=lpDI->CreateDevice(GUID_SysKeyboard, &lpDIKey, NULL); if( FAILED(hr) ) { FreeInput_Key(); return false; } //设置数据格式 hr=lpDIKey->SetDataFormat(&c_dfDIKeyboard); if( FAILED(hr) ) { FreeInput_Key(); return false; } //设置协作层 hr=lpDIKey->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); if( FAILED(hr) ) { FreeInput_Key(); return false; } //设置属性 DIPROPDWORD property; property.diph.dwSize=sizeof(DIPROPDWORD); property.diph.dwHeaderSize=sizeof(DIPROPHEADER); property.diph.dwObj=0; property.diph.dwHow=DIPH_DEVICE; property.dwData=KEYBUFFERSIZE; hr = lpDIKey->SetProperty(DIPROP_BUFFERSIZE, &property.diph); if FAILED(hr) { // 设置缓冲区失败 MessageBox(hWnd, "error on set Key Buffer size", "error", MB_OK); return FALSE; } //得到设备通道 hr=lpDIKey->Acquire(); if( FAILED(hr) ) { FreeInput_Key(); return false; } return true; } //获取设备 HRESULT WINAPI CKey::SetAcquire( HWND hDlg ) { if ( NULL == lpDIKey ) return S_FALSE; if (bActive) { lpDIKey->Acquire(); } else { lpDIKey->Unacquire(); } return S_OK; } //释放DIRECTINPUT设备KEY void WINAPI CKey::FreeInput_Key() { if( lpDIKey ) { lpDIKey->Unacquire(); lpDIKey->Release(); lpDIKey=NULL; } } //获取键盘即时数据 void WINAPI CKey::GetKeyState() { HRESULT hr; hr=lpDIKey->GetDeviceState(256, (LPVOID)&KeyState); if( FAILED(hr) ) { lpDIKey->Acquire(); hr=lpDIKey->GetDeviceState(256, (LPVOID)&KeyState); } } //检测一个键当前是否按下 bool WINAPI CKey::KeyDown(unsigned char Key) { GetKeyState(); if( KEYDOWN(KeyState, Key)) { return true; } return false; } //返回一个键是否按下 bool WINAPI CKey::GetState(unsigned char Key) { if( KEYDOWN(KeyState, Key)) { return true; } return false; } //*************************** //返回键盘缓冲区数据(附带即时数据) void WINAPI CKey::GetKeyData() { DIDEVICEOBJECTDATA rgdod[KEYBUFFERSIZE]; DWORD dwItems = KEYBUFFERSIZE; _again: HRESULT hr = lpDIKey->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0); if(hr != DI_OK) { for(int i=0; i<256; i++) //清0 KeyState[i] = 0; if( FAILED(hr) ) { hr = lpDIKey->Acquire(); if FAILED(hr) { return; } if SUCCEEDED(hr) { goto _again; } } } if( SUCCEEDED(hr) && dwItems>0 ) { for(DWORD i=0; i<dwItems; i++) { //缓冲数据 if((rgdod[i].dwData & 0x80)) //按下 { KeyBuffer[KeyBuffer_End] = (BYTE)(rgdod[i].dwOfs); KeyBuffer_End ++; if( KeyBuffer_End >= KEYBUFFERSIZE ) //循环 KeyBuffer_End = 0; } else //释放+128 { KeyBuffer[KeyBuffer_End] = (BYTE)(rgdod[i].dwOfs+128); KeyBuffer_End ++; if( KeyBuffer_End >= KEYBUFFERSIZE ) KeyBuffer_End = 0; } //即时数据 KeyState[rgdod[i].dwOfs] = (BYTE)(rgdod[i].dwData & 0x80); } } } //从缓冲区取一个值(0=无) unsigned char WINAPI CKey::GetKey() { //缓冲区为空 if( KeyBuffer_Start == KeyBuffer_End ) return 0; byte ret=KeyBuffer_Start; KeyBuffer_Start++; if( KeyBuffer_Start >= KEYBUFFERSIZE ) KeyBuffer_Start = 0; return KeyBuffer[ret]; } //清空键盘缓冲区 void WINAPI CKey::ReleaseKeyBuffer() { while(1) { GetKeyData(); if( GetKey()== 0 ) break; } } ////////////////////////////////////////////////////////////////////////// // Joystick ////////////////////////////////////////////////////////////////////////// #if USE_DX8 LPDIRECTINPUT8 CJoystick::g_pDI=NULL; LPDIRECTINPUTDEVICE8 CJoystick::m_pJoystick=NULL; #else LPDIRECTINPUT7 CJoystick::g_pDI=NULL; LPDIRECTINPUTDEVICE2 CJoystick::m_pJoystick=NULL; #endif DIDEVCAPS CJoystick::m_diDevCaps; CJoystick::CJoystick() { memset( State, 0, MAXKEY ); memset( Buffer, 0, BUFFERSIZE ); Buffer_Start = Buffer_End = 0; } CJoystick::~CJoystick() { } //媒举手柄的回调函数 BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) { HRESULT hr; // 得到一个被媒举的手柄的接口 #if USE_DX8 hr = CJoystick::g_pDI->CreateDevice( pdidInstance->guidInstance,&CJoystick::m_pJoystick, NULL ); #else hr = CJoystick::g_pDI->CreateDeviceEx( pdidInstance->guidInstance, IID_IDirectInputDevice2, (VOID**)&CJoystick::m_pJoystick, NULL ); #endif // 失败了,我们就不能使用这个手柄,那么接着媒举 if( FAILED(hr) ) return DIENUM_CONTINUE; // 成功了,那么就停止媒举,我们只使用第一个手柄 return DIENUM_STOP; } //媒举手柄的方向轴的回调函数 BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext ) { HWND hDlg = (HWND)pContext; //pContext放的是窗口句柄 DIPROPRANGE diprg; diprg.diph.dwSize = sizeof(DIPROPRANGE); diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); diprg.diph.dwHow = DIPH_BYOFFSET; diprg.diph.dwObj = pdidoi->dwOfs; // 媒举方向轴 diprg.lMin = -1000; diprg.lMax = +1000; //设置方向轴的范围 if( FAILED( CJoystick::m_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) return DIENUM_STOP; //失败了,就不继续了 DIPROPDWORD property; property.diph.dwSize=sizeof(DIPROPDWORD); property.diph.dwHeaderSize=sizeof(DIPROPHEADER); property.diph.dwHow = DIPH_BYOFFSET; property.diph.dwObj = pdidoi->dwOfs; property.dwData = 5000; HRESULT hr = CJoystick::m_pJoystick->SetProperty(DIPROP_DEADZONE,&property.diph); if(FAILED(hr)) { // 设置死区失败 MessageBox(hDlg, "error on set Joystick deadzone size", "error", MB_OK); return FALSE; } // 让我们的应用程序根据方向轴所支持的方式做出不同的响应 // 配合传进来的窗口句柄可以做很多的事情………… switch( pdidoi->dwOfs ) { case DIJOFS_X: break; case DIJOFS_Y: break; case DIJOFS_Z: break; case DIJOFS_RX: break; case DIJOFS_RY: break; case DIJOFS_RZ: break; case DIJOFS_SLIDER(0): break; case DIJOFS_SLIDER(1): break; } return DIENUM_CONTINUE; //继续媒举下一个方向 } //初始化 HRESULT CJoystick::InitInput_Joystick( HWND hDlg ) { HRESULT hr; //创建DirectInput #if USE_DX8 hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION,IID_IDirectInput8, (LPVOID*)&g_pDI, NULL ); #else hr = DirectInputCreateEx( hInst, DIRECTINPUT_VERSION,IID_IDirectInput7, (LPVOID*)&g_pDI, NULL ); #endif if( FAILED(hr) ) return hr; // 媒举一个手柄 #if USE_DX8 #define JOY DI8DEVCLASS_GAMECTRL #else #define JOY DIDEVTYPE_JOYSTICK #endif hr = g_pDI->EnumDevices( JOY, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY ); if( FAILED(hr) ) return hr; // 确认得到了一个手柄,上一个函数只保证它自己调用成功,不保证得到了一个可以用的手柄 if( NULL == m_pJoystick ) { return E_FAIL; } //设置数据格式 hr = m_pJoystick->SetDataFormat( &c_dfDIJoystick ); if( FAILED(hr) ) return hr; //设置协作级 hr = m_pJoystick->SetCooperativeLevel( hDlg, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND ); if( FAILED(hr) ) return hr; m_diDevCaps.dwSize = sizeof(DIDEVCAPS); hr = m_pJoystick->GetCapabilities(&m_diDevCaps); if ( FAILED(hr) ) return hr; //媒举方向轴 m_pJoystick->EnumObjects( EnumAxesCallback, (VOID*)hDlg, DIDFT_AXIS ); //设置属性 DIPROPDWORD property; property.diph.dwSize=sizeof(DIPROPDWORD); property.diph.dwHeaderSize=sizeof(DIPROPHEADER); property.diph.dwObj=0; property.diph.dwHow=DIPH_DEVICE; property.dwData=32; hr = m_pJoystick->SetProperty(DIPROP_BUFFERSIZE, &property.diph); if FAILED(hr) { // 设置缓冲区失败 MessageBox(hDlg, "error on set Joystick Buffer size", "error", MB_OK); return FALSE; } //得到设备 SetAcquire(hWnd); return true; } //获取设备 HRESULT CJoystick::SetAcquire( HWND hWnd ) { if( m_pJoystick ) { if( bActive ) m_pJoystick->Acquire(); else m_pJoystick->Unacquire(); } return S_OK; } //得到手柄的当前状态 HRESULT CJoystick::GetJoystickState() { HRESULT hr; DIJOYSTATE js; static DIJOYSTATE oldjs; //上一个状态 if( m_pJoystick ) { do { //Poll hr = m_pJoystick->Poll(); if( FAILED(hr) ) return hr; //得到当前状态 hr = m_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js ); if( hr == DIERR_INPUTLOST ) { hr = m_pJoystick->Acquire(); if( FAILED(hr) ) return hr; } } while( DIERR_INPUTLOST == hr ); if( FAILED(hr) ) return hr; //清0 for(int i =0;i<MAXKEY;i++) State[i] =0; //我们只是关心这几个的值 //先是上下方向的 if(js.lY<0&&abs(oldjs.lY-js.lY)<10) State[DIJ_UP] = DIJ_UP+128; if(js.lY>0&&abs(oldjs.lY-js.lY)<10) State[DIJ_DOWN] = DIJ_DOWN+128; if(js.lY>0&&abs(oldjs.lY)<10) State[DIJ_DOWN] = DIJ_DOWN; if(js.lY<0&&abs(oldjs.lY)<10) State[DIJ_UP] = DIJ_UP; //然后是左右方向的 if(js.lX<0&&abs(oldjs.lX-js.lX)<10) State[DIJ_LEFT] = DIJ_LEFT+128; if(js.lX>0&&abs(oldjs.lX-js.lX)<10) State[DIJ_RIGHT] = DIJ_RIGHT+128; if(js.lX>0&&abs(oldjs.lX)<10) State[DIJ_RIGHT] = DIJ_RIGHT; if(js.lX<0&&abs(oldjs.lX)<10) State[DIJ_LEFT] = DIJ_LEFT; //最后是按纽 State[DIJ_3] = (js.rgbButtons[0]&0x80?DIJ_3+48:0); //按下或者是放开 State[DIJ_4] = (js.rgbButtons[1]&0x80?DIJ_4+48:0); State[DIJ_2] = (js.rgbButtons[2]&0x80?DIJ_2+48:0); State[DIJ_1] = (js.rgbButtons[3]&0x80?DIJ_1+48:0); memcpy(&oldjs,&js,sizeof(js)); } return S_OK; } //返回一个键当前是否按下 unsigned char CJoystick::GetState(unsigned char Key) { return State[Key]; } //*************************** //返回缓冲区数据 void WINAPI CJoystick::GetJoystickData() { DIDEVICEOBJECTDATA rgdod[BUFFERSIZE]; DWORD dwItems = BUFFERSIZE; if( m_pJoystick ) { _again: // Poll HRESULT hr = m_pJoystick->Poll(); if( FAILED(hr) ) return; hr = m_pJoystick->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0); if(hr != DI_OK) { if( FAILED(hr) ) { hr = m_pJoystick->Acquire(); if FAILED(hr) { return; } if SUCCEEDED(hr) { goto _again; } } } if( SUCCEEDED(hr) && dwItems>0 ) { DWORD i; for(i=0; i<dwItems; i++) { //缓冲数据,两个按纽的数据 if(rgdod[i].dwOfs == DIJOFS_BUTTON0) { if((rgdod[i].dwData & 0x80) ) //按下 { Buffer[Buffer_End] = (BYTE)(DIJ_3); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } else //释放 { Buffer[Buffer_End] = (BYTE)(DIJ_3+48); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } } if(rgdod[i].dwOfs == DIJOFS_BUTTON1) { if((rgdod[i].dwData & 0x80) ) //按下 { Buffer[Buffer_End] = (BYTE)(DIJ_4); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } else //释放 { Buffer[Buffer_End] = (BYTE)(DIJ_4+48); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } } if(rgdod[i].dwOfs == DIJOFS_BUTTON2) { if((rgdod[i].dwData & 0x80) ) //按下 { Buffer[Buffer_End] = (BYTE)(DIJ_2); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } else //释放 { Buffer[Buffer_End] = (BYTE)(DIJ_2+48); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } } if(rgdod[i].dwOfs == DIJOFS_BUTTON3) { if((rgdod[i].dwData & 0x80) ) //按下 { Buffer[Buffer_End] = (BYTE)(DIJ_1); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } else //释放 { Buffer[Buffer_End] = (BYTE)(DIJ_1+48); Buffer_End ++; if( Buffer_End >= BUFFERSIZE ) Buffer_End = 0; } } } } } } //从缓冲区取一个值(0=无) unsigned char WINAPI CJoystick::GetKey() { if( m_pJoystick ) { //缓冲区为空 if( Buffer_Start == Buffer_End ) return 0; byte ret=Buffer_Start; Buffer_Start++; if( Buffer_Start >= BUFFERSIZE ) Buffer_Start = 0; return Buffer[ret]; } return 0; } //清空缓冲区 void WINAPI CJoystick::ReleaseBuffer() { if( m_pJoystick ) { while(1) { GetJoystickData(); if( GetKey()== 0 ) break; } } } //释放手柄 HRESULT CJoystick::FreeInput_Joystick() { if( m_pJoystick != NULL ) { m_pJoystick->Unacquire(); m_pJoystick->Release(); m_pJoystick = NULL; } if( lpDI ) { lpDI->Release(); lpDI = NULL; } return S_OK; }