Chapter 14 DirectInput의 전말
이 장에서는 - DirectDinput에 대해서 파악하기 - 키보드 장치 생성하고 사용하기 - 마우스 사용하기 - 조이스틱 설정하기
DirectX 가 지원하는 입력장치 키보드: 표준 QWERTY 키보드 마우스: 2버튼 그리고 3버튼 마우스 조이스틱과 비행 요크: 아날로그와 디지털 조이스틱/비행-요크는 6만큼의 자유도와 최대 32개의 버튼을 지원한다. 운전대 컨트롤: 아날로그 디지털 운전 시뮬레이션용 패들: 다양한 회전 장치 포스-피드백(force-feedback) 장치: 기계적인 액튜에이터(actuator)가 있어서, 컴퓨터가 진동시키거나 모양을 바꿀 수 있는 조이스틱 또는 다른 장치들. 가상현실 헤드기어 트래킹 시스템(virtual reality headgear tracking system): 가상현실 헤드기어의 위치와 회전을 지원. (착용자의 머리의 상태를 전송.)
DirectInput 인터페이스의 구조
DirectInput의 사용 DINPUT.LIB, DINPUT8.LIB, DINPUT.H
DirectInput 사용 순서 1. DirectInput8Create()으로 주요 DirectInput 객체를 생성한다. 2. CreateDevicde()으로 하나 혹은 그 이상의 입력 장치를 생성한다. 각각에 대해서 GUID가 필요하다. 따라서, DirectInput이 모든 입력 장치를 나열하도록 요청할 수도 있다. 3. SetCooperativeLevel()으로, 각 장치의 협력 수준을 설정한다. 4. SetDataFormat()으로 각장치의 데이터 형식을 설정하고, SetProperty()로 특별한 속성들을 설정한다. 5. Acquire()로 각 입력장치를 획득한다. 이 단계는 각 입력 장치를 주요 DirectInputDevice8에 추가한다. 6. GetDeviceState()로 입력을 받는다. 수동 폴링이 필요한 장치는 Poll()을 호출한다
DirectInput 생성 LPDIRECTINPUT8 lpdi; // main DirectInput object HRESULT WINAPI DirectInput8Create( HINSTANCE hinst, // instance of application DWORD dwVersion, // backward version compatibility REFIID riidltf, // interface id being requested LPVOID* ppvOut, // pointer to interface LPUNKNOWN punkOuter); // com stuff, null #include “DINPUT.H” LPDIRECTINPUT8 lpdi; // pointer to DirectInput object // create DirectInput object if (DirectInput8Create(main_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&lpdi,NULL)!=DI_OK) { /* error */ }
키보드 입력 1. 키보드 장치를 생성한다. 2. 키보드의 협력 수준을 설정한다. 3. 키보드 장치를 위한 데이터 형식을 설정한다. 4. 키보드 장치를 얻어온다(aquire).
여러 개의 device들이 하나의 DirectInput device를 구성할 수도 있다.
DirectInput Object (객체) 하나의 device에 여러 개의 object가 존재 가능
CreateDevice Function HRESULT CreateDevice( REFGUID rguid, // GUID of device to create LPDIRECTINPUTDEVICE *lplpDIDev,// ptr to device interface LPUNKNOWN pUnkOuter); // always NULL GUID_SysKeyboard: 기본 시스템 키보드 GUID_SysMouse: 기본 시스템 마우스 #define INITGUID 와 OBJBASE.H 필요
CreateDevice Example #define INITGUID // needed to get the GUIDS in here #include <OBJBASE.H> // COM stuff #include “DINPUT.H” // you need this! LPDIRECTINPUT8 lpdi; // main DirectInput object // create DirectInput object if (DirectInput8Create(main_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&lpdi,NULL)!=DI_OK) { /* error */ } LPDIRECTINPUTDEVICE8 lpdikey; // the keyboard device // create keyboard device if (lpdi->CreateDevice(GUID_SysKeyboard, &lpdikey,NULL)!=DI_OK) { /* error */ }
협력 수준의 설정 Value Meaning DISCL_BACKGROUND Your application can use a DirectInput device whether the application is idling in the background or active in the foreground. DISCL_FOREGROUND The application requires foreground access. If foreground access is granted, the device is automatically unacquired when the associated window moves to the background. DISCL_EXCLUSIVE After you acquire the device, no other application can request exclusive access to it; however, other applications can still request nonexclusive access. DISCL_NONEXCLUSIVE The application requires nonexclusive access. Access to the device does not interfere with other applications that are accessing the same device.
협력 수준의 설정 DISCL_BACKGROUND | DISCL_NONEXCLISIVE 를 협력 설정으로 사용해야 한다. if (lpdikey->SetCooperativeLevel(main_window_handle, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)!=DI_OK) { /* error */ }
데이터 형식의 설정 Custom-made Data formats c_dfDIKeyboard c_dfDIMouse DIDATAFORMAT df; SetDataFormat(&df); // ptr to data format structure Custom-made Data formats c_dfDIKeyboard c_dfDIMouse c_dfDIJoystick c_dfDIJoystick2 : for force feedback device if (FAILED(lpdikey->SetDataFormat(&c_dfDIKeyboard))) { … }
Acquire Device를 입력 스트림에 추가하고 데이터를 입수할 수 있도록 만드는 것이다. if (FAILED(lpdikey->Acquire())) { … }
Keyboard 읽어오기 키보드 상태는 256 BYTE 요소의 배열 int ship_x = 100, ship_y = 100; // initial ship position // storage for the keyboard data UCHAR keystate[256]; // in your main loop, you would do this if (lpdikey->GetDeviceState(256, keystate)!=DI_OK) { /* something’s amiss */ } // test whether the player is “moving” the ship if (keystate[DIK_RIGHT] & 0x80) ship_x++; if (keystate[DIK_LEFT] & 0x80) ship_x--; if (keystate[DIK_DOWN] & 0x80) ship_y++; if (keystate[DIK_UP] & 0x80) ship_y--; 키보드 상태는 256 BYTE 요소의 배열
DirectInput 키보드 가상 키 코드 DIK_ESCAPE ESC키 DIK_0 - DIK_9 메인 키보드의 0-9 DIK_A - DIK_Z A-Z DIK_RETURN 메인 키보드의 엔터키 DIK_LCONTROL 왼쪽 Ctrl키 DIK_RCONTROL 오른쪽 Ctrl키 DIK_SPACE 스페이스바 DIK_F1 - DIK_F12 펑션키 F1-F12 DIK_UP (위)화살표 DIK_DOWN (아래)화살표 DIK_LEFT (왼쪽)화살표 DIK_RIGHT (오른쪽)화살표 DIK_PRIOR Page Up DIK_NEXT Page Down
Unacquire lpdikey->Unacquire( ) Temporarily stop to get the device input By Acquire( ) the input can be reactivated.
DEMO 14_1
마우스 입력 LPDIRECTINPUTDEVICE8 lpdimouse; // the mouse device // create mouse device if (lpdi->CreateDevice(GUID_SysMouse, &lpdimouse,NULL)!=DI_OK) { } if (lpdimouse->SetCooperativeLevel(main_window_handle, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)!=DI_OK) { } // set data format, notice the use of the address operator if (lpdikey->SetDataFormat(&c_dfDIMouse)!=DI_OK) { /* error */ } // acquire the mouse if (lpdimouse->Acquire()!=DI_OK) { /* error */ }
Mouse – Relative Mode
마우스 입력 typedef struct { LONG lX; // x-axis of mouse LONG lY; // y-axis of mouse LONG lZ; // z-axis of mouse, typically a wheel or dial BYTE rgbButtons[4]; // buttons of the mouse, high bit means pressed } DIMOUSESTATE, *LPDIMOUSESTATE; // this holds the mouse data DIMOUSESTATE mouse_state; // get mouse data if (lpdimouse->GetDeviceState(sizeof(DIMOUSESTATE) (LPVOID)&mouse_state)!=DI_OK) { /* problem */ } // test left button if (mouse_state.rgbButtons[0]) { /* do whatever */ } else if (mouse_state.rgbButtons[1]) { /* do whatever */ }
마우스 입력 // is the mouse moving right if (mouse_state.lX > 0 ) else // check for left motion if (mouse_state.lX < 0) { /* left */ } // is the mouse moving down if (mouse_state.lY > 0 ) { /* down *} else // check for upward motion if (mouse_state.lY < 0) { /* up */ }
DEMO14_2