DX관련 입력중 창이 비활성화될때 입력이 되지않았던 문제를 해결코자 검색중 찾아낸방법....
간단하게 init에서 설정할때 관련인자만 살짝바꿔주면된다. 본 설명에서 검색하면 쉽게 찾아볼수있다.
참고 >
여기에서 언급하는 Direct X 의 델파이용 헤더는 GMA나 VTOOL에서 구할 수
있다.
------------------------------------------------------------------------
### 델파이로 하는 Direct X - Direct Input (1/2)
------------------------------------------------------------------------
작성자 : 안영기 ( HiTEL ID : SMgal )
Direct Input 이란 무엇인가 ? Direct X 의 구성 요소 중에서 Direct Setup
다음으로 쉬운 요소이다.
Direct Input은 입력 장치에 대한 모든 정보를 제어하기 위한 Direct X의 구
성요소인데, 주로 관리하는 쪽이 키보드, 마우스, 조이스틱이다.
마우스로는 3차원 마우스까지 지원하고, 조이스틱으로는 일반적인 2축 4버튼
뿐만 아니라 사이더와인더같은 비행기 조종간이나 스티어링 기능이 있는 레이
스용 조이스틱까지 지원한다. ( 하지만 필자가 3차원 마우스나 조이스틱을 가
지고있지 않기 때문에 강좌에서는 언급하지 않겠다. )
Direct Input 강좌는 총 2 편으로 구성될 예정인데, 1편은 키보드 관리고 2편
은 마우스 관리로 할 예정이다.
------------------------------------------------------------------------
(1) Direct Input 의 Keyboard 를 왜 사용하는가 ?
윈도우즈에는 키보드를 감지하기 위한 좋은 API 함수가 이미 있다.
GetAsyncKeyState() 라는 함수인데 이 함수만 사용해도 현재의 키가 눌러져
있는지.. 아니면 이 함수를 호출하기 전에 특정 키가 눌러진 적이 있는지를
알 수 있다.
일반적인 게임( 윈도우 기반의 게임 )에서는 이 함수만으로도 충분히 키보드
관리를 할 수 있고 Direct X 기반의 게임이라고 하더라도 이 함수로도 충분히
키보드 입력에 무리없이 사용할 수 있다.
그렇다면 Direct Input 의 Keyboard 를 왜 사용하는가 ?
필자가 생각하는 이유는 이렇다... Direct Input 의 Keyboard 는 DOS 시절에
게임 프로그래머가 키보드 인터럽트를 가로채서 만든 Multi Key 라는 기법에
가장 가까운 용법으로 쓰이기 때문에 게임 프로그래머들에게 익숙한 사용법을
제공한다. 그리고 키 조합이 많은 아케이드나 액션 게임등에서 키조합이 간단
하고 그 속도가 빠르다.
이 정도면 충분한 이유가 되었다고 생각하고 구현으로 들어가겠다.
------------------------------------------------------------------------
(2) Direct Input 의 Keyboard 객체 구현
| type
|
| TKeyState = array[0..255] of Byte;
|
| TDxInput = class
| constructor Create(hInstance : integer; Handle : integer);
| procedure Free;
| private
| public
| DirectInput : IDirectInput;
| DirectInputKeyboard : IDirectInputDevice;
| procedure GetKeyState(var KeyState : TKeyState);
| end;
이렇게 간단한 객체로 Direct Input 의 Keyboard 객체가 만들어진다.
생성자, 소멸자, 그리고 변수 2 개와 함수하나...
우리는 항상 그렇듯 10줄의 설명 보다는 10줄의 코드를 더 빨리 이해하기 때
문에 implementation에 구현되어 있는 객체 메소드를 직접 보면서 설명하겠다.
아래에 보이는 것이 생성자다.
파라메터는 Instance와 Handle을 받는다.
| constructor TDxInput.Create(hInstance : integer; Handle : integer);
| var
| HR : HResult;
| begin
| // 선조의 Create를 실행한다.
| Inherited Create;
|
| // Direct Input 객체를 만든다.
| HR := DirectInputCreate(hInstance,DIRECTINPUT_VERSION,
| DirectInput,nil);
| if HR <> DI_OK then exit;
|
| // 키보드 디바이스를 생성한다.
| HR := DirectInput.CreateDevice(GUID_SysKeyboard,
| DirectInputKeyboard,nil);
| if HR <> DI_OK then exit;
|
| // 키보드에 대한 데이터 포맷을 설정한다.
| HR := DirectInputKeyboard.SetDataFormat(c_dfDIKeyboard);
| if HR <> DI_OK then exit;
|
| // 상호 협력 레벨을 설정한다.
| HR := DirectInputKeyboard.SetCooperativeLevel(Handle,
| DISCL_NONEXCLUSIVE or DISCL_FOREGROUND);
| if HR <> DI_OK then exit;
|
| // 키보드의 접근 권한을 얻는다.
| HR := DirectInputKeyboard.Acquire;
| if (HR <> DI_OK) and (HR <> DI_NOEFFECT) then begin
| // 실패했을 때 그 원인을 알아 본다.
| case HR of
| DIERR_NOTINITIALIZED :
| ShowMessage('Direct Input Error : NOTINITIALIZED');
| DIERR_INVALIDPARAM :
| ShowMessage('Direct Input Error : INVALIDPARAM');
| DIERR_OTHERAPPHASPRIO :
| ShowMessage('Direct Input Error : OTHERAPPHASPRIO');
| else
| ShowMessage('Direct Input Error');
| end;
| end;
| end;
이걸로 Direct Input의 Keyboard에 대한 초기화가 모두 끝났다. 그럼 순차적
으로 다시 자세하게 설명해 보면.....
1) DirectInputCreate(hInstance,DIRECTINPUT_VERSION,DirectInput,nil);
Direct Input 객체를 생성하는 함수다.
첫번째 파라메터 : 이 객체를 생성하려는 프로그램의 인스턴스
두번째 파라메터 : Direct Input 의 버전 넘버, 아래처럼 정의되어 있다.
{$IFDEF DIRECTX3}
DIRECTINPUT_VERSION = $0300;
{$ELSE}
DIRECTINPUT_VERSION = $0500;
{$ENDIF}
세번째 파라메터 : Direct Input 의 주 객체인 IDirectInput 로 선언된 변
수가 var 로 들어가게 된다. 성공하면 nil이 아닌 값이
들어온다.
네번째 파라메터 : 무조건 nil을 쓴다.
2) DirectInput.CreateDevice(GUID_SysKeyboard,DirectInputKeyboard,nil);
사용할 디바이스를 생성한다.
첫번째 파라메터 : 사용할 디바이스의 GUID를 넣는다. 이미 정의되어 있는
'시스템 키보드'에 대한 GUID인 GUID_SysKeyboard를 넣
으면 된다. 참고로 강좌 2편에 나올 '마우스' 에 대한
GUID는 GUID_SysMouse 이다.
두번째 파라메터 : IDirectInputDevice 로 선언된 변수가 var 로 들어간다.
역시 성공하면 nil이 아닌 값이 들어 온다.
세번째 파라메터 : 무조건 nil을 쓴다.
3) DirectInputKeyboard.SetDataFormat(c_dfDIKeyboard);
디바이스에 대한 데이터 포맷을 설정한다.
현재는 키보드 디바이스이므로 키보드에 대한 데이터 정보를 보냈다.
첫번째 파라메터 : 나중에 Direct Input으로부터 돌려 받을 데이터의 형의
구조체를 넣는다. 이미 c_dfDIKeyboard, c_dfDIMouse,
c_dfDIJoystick, c_dfDIJoystick2 등이 정의되어 있으
며 자신만의 데이터 형도 정의할 수 있다.
4) DirectInputKeyboard.SetCooperativeLevel(Handle,
DISCL_NONEXCLUSIVE or DISCL_FOREGROUND);
상호 협력 레벨을 설정한다. 이것은 디바이스를 자신이 독점할 것인가? 아
니면 다른 프로그램도 동시에 사용할 수 있게 하느냐에 대한 것을 정의 한
다. 파라메터 이름을 보면 알겠지만 NONEXCLUSIVE 하면서 FOREGROUND 에서
만 동작하도록 했다. ( 쉽게 말하면 딴 프로그램도 키보드 쓸 수있고 현재
Handle을 보낸 윈도우에 Focus 가 있을 때만 키보드 정보를 받을 수 있게
설정했다. )
첫번째 파라메터 : 키보드 정보를 받을 윈도우의 핸들
두번째 파라메터 : 협력 레벨에 대한 플래그가 들어간다.
DISCL_EXCLUSIVE - 딴 프로그램에서는 Aquire() 하고 있는 동안에
키보드를 사용할 수가 없다.
DISCL_NONEXCLUSIVE - 딴 프로그램과 킵드 정보를 공유한다.
DISCL_FOREGROUND - 윈도우에 Focus가 있을 때만 키보드 정보를 받
을 수 있다.
DISCL_BACKGROUND - 윈도우가 비활성되어도 키보드 정보를 받을 수
가 있다.
( DISCL_EXCLUSIVE 와 DISCL_NONEXCLUSIVE 는 동시에 사용할 수 없고
DISCL_FOREGROUND 와 DISCL_BACKGROUND 도 마찬가지다. )
5) DirectInputKeyboard.Acquire;
디바이스의 접근 권한을 얻는다. 현재는 키보드로 정의되어 있으므로 키보
드에 대한 접근 권한이다. Acquire를 호출 하지 않으면 키보드의 데이터를
가져 올 수 없다.
그리고 리턴 값이 위의 다른 함수와는 좀 다르다는 것을 느꼈을 것이다.
if (HR <> DI_OK) and (HR <> DI_NOEFFECT) then
이런 식으로 성공했을 때의 값은 DI_OK 뿐만 아니라 S_FALSE 라는 값일 수
도 있다. DI_OK 는 Direct Input이 성공했을 때 항상 돌려주는 HResult 값
이며, DI_NOEFFECT는 이미 Acquire를 이미 호출 한 상태일 때의 리턴 값이
다.
이렇게 생성자에 대한 부분이 구성된다.
그러면 이번에는 소멸자에 대해서 알아 보자.
| procedure TDxInput.Free;
| begin
| // 키보드 접근 권한 해제
| DirectInputKeyboard.Unacquire;
|
| // Direct Input 디바이스 객체 해제
| DirectInputKeyboard._Release;
| Pointer(DirectInputKeyboard) := nil;
|
| // Direct Input 객체 해제
| DirectInput._Release;
| Pointer(DirectInput) := nil;
|
| // 선조의 Free를 실행한다.
| Inherited;
| end;
생성자에 비해서는 비교적 간단하다. 그럼 설명 하자면...
1) DirectInputKeyboard.Unacquire;
Aquire 메소드에 의해 얻어진 접근 권한을 해제한다.
2) DirectInputKeyboard._Release;
Pointer(DirectInputKeyboard) := nil;
Direct Input 디바이스 객체를 해제한다. COM 에서는 그냥 Release를 사용
하는데 _Release 사용하는 이유는, 델파이 2 의 OLE2 와는 다른, 델파이 3
의 이상에서 지원하는 IUnknown 인터페이스를 사용하기 때문이다.
3) DirectInput._Release;
Pointer(DirectInput) := nil;
Direct Input 객체를 해제한다. 왜 Release라는 과정이 필요한지는 COM 에
관련된 책자를 읽어 보기 바란다. 참고로 Direct X 는 모두 COM 기반이다.
그럼 이제 딱 하나의 함수만 남았다.
| procedure TDxInput.GetKeyState(var KeyState : TKeyState);
| var
| HR : HResult;
| begin
| // 키보드의 상태를 읽는다.
| HR := DirectInputKeyboard.GetDeviceState(SizeOf(KeyState),@KeyState);
| // 만약 입력 장치에 대한 정보를 읽어 버렸으면 다시 Aquire 한다.
| if HR = DIERR_INPUTLOST then DirectInputKeyboard.Acquire;
| end;
1) DirectInputKeyboard.GetDeviceState(SizeOf(KeyState),@KeyState);
디바이스의 상태를 읽는다. 현재는 DirectInputKeyboard 가 키보드로 정의
되었으므로 키보드에 대한 정보를 읽어 온다.
첫번째 파라메터 : 두번째 파라메터에 들어가는 버퍼의 사이즈를 넣는다.
두번째 파라메터 : 입력 장치의 정보를 가져오는 버퍼의 포인터를 넣는다.
물론 그 구조는 SetDataFormat() 에서 이미 정의했다.
------------------------------------------------------------------------
(3) Direct Input 의 Keyboard 객체 용법
객체를 구현했으니 이제는 사용하는 방법만 남았다.
일단 객체의 선언은 다음처럼 하면 된다.
DxInput : TDxInput;
그리고 생성은
DxInput := TDxInput.Create(hInstance,Handle);
소멸은
DxInput.Free;
DxInput := nil;
이렇게 사용한다.
그렇다면 용법을 보자...
| var
| KeyState : TKeyState;
|
| begin
| // KeyState 에 키보드 상태를 가져온다.
| DxInput.GetKeyState(KeyState);
|
| // 오른쪽 화살표키가 눌러져 있는 상태인가 ?
| if KeyState[DIK_RIGHT] and $80 > 0 then
| // 왼쪽 화살표키가 눌러져 있는 상태인가 ?
| if KeyState[DIK_LEFT ] and $80 > 0 then
| // 위쪽 화살표키가 눌러져 있는 상태인가 ?
| if KeyState[DIK_UP ] and $80 > 0 then
| // 아래쪽 화살표키가 눌러져 있는 상태인가 ?
| if KeyState[DIK_DOWN ] and $80 > 0 then
| end;
KeyState 에 되돌아 오는 값은 TKeyState 에 선언된 대로 256 개의 byte 배열
이다. 그리고 그 배열들은 Direct Input 헤더에 정의된 DIK_RIGHT 와 같은 상
수에 의해 특정 정보를 가져올 수가 있다. DOS 때의 스캔코드와 유사하게 키
보드의 실제 물리적인 버튼에 바로 대응한다. 즉 'a' 키를 누르면 무조건 'a'
키로 인식한다. ( 일반적인 키보드라면 Sfhit - 'a' 가 되면 'A' 로 인식하지
만 여기에서는 '왼쪽 Shift' 와 'a'로 따로 인식한다. )
그 배열들에 저장된 값의 MSB(최상위비트)가 1이면 현재 그 키가 눌러진 것이
고 0 이라면 키가 떼어진 것이다. 이 정보를 가지고 DOS 때의 Multi-Key 처럼
핸들링하면 이전에 눌러졌었는지.. 또는 현재 몇개의 키가 조합되었는지 등을
알수가있다. ( BM98 이라는 음악 게임에 보면 동시에 6키를 눌러도 동시에 모
두 인식을 해 내는 것을 볼 수 있을것이다. )
------------------------------------------------------------------------
(4) Direct Input 의 Keyboard 객체 사용 예제
그럼 실제로 사용을 해보자면....
1. 위에서 만든 Direct Input 객체를 따로 Unit 로 저장한다.
2. 새로운 프로젝트를 만들고, Unit1 에는 방금 만든 Direct Input 객체가 있
는 unit를 uses한다. 그리고 Direct Input 헤더인 DInput.Pas 도 uses한다.
3. 폼에는 타이머, 라벨, 버튼을 만든다.
4. TForm1 의 public 에 'DxInput : TDxInput;' 을 추가한다.
5. 버튼의 클릭 이벤트에 다음과 같이 입력한다.
DxInput := TDxInput.Create(hInstance,Handle);
Timer1.Enabled := TRUE;
6. Form 의 Close 이벤트에 다음과 같이 입력한다.
Timer1.Enabled := FALSE;
DxInput.Free;
DxInput := nil;
7. 타이머 이벤트의 Interval을 1로 하고 이벤트에는 다음과 같이 입력한다.
var
KeyState : TKeyState;
s : string;
begin
DxInput.GetKeyState(KeyState);
s := '';
if KeyState[DIK_RIGHT] and $80 > 0 then s := s + 'Right ';
if KeyState[DIK_LEFT ] and $80 > 0 then s := s + 'Left ';
if KeyState[DIK_UP ] and $80 > 0 then s := s + 'Up ';
if KeyState[DIK_DOWN ] and $80 > 0 then s := s + 'Down ';
Label1.Caption := s;
end;
8. 실행한다.
9. 버튼을 누르면 Direct Input 의 키보드 핸들링이 시작되는데... 현재는 화
살표 키에만 반응한다. 동시에 화살표키를 여러개 누르거나 동시에 4개를
눌러도 모두 반응한다.
나머지 키에 대한 상수 값은 델파이용 Direct X 의 DInput.Pas 에 보면 잘 나
와 있다.
------------------------------------------------------------------------
1999 / 10 / 31
참고 >
여기에서 언급하는 Direct X 의 델파이용 헤더는 GMA나 VTOOL에서 구할 수
있다.
------------------------------------------------------------------------
### 델파이로 하는 Direct X - Direct Input (2/2)
------------------------------------------------------------------------
작성자 : 안영기 ( HiTEL ID : SMgal )
앞 장에서 우리는 Direct Input 에 의한 키보드 상태 읽기를 했었다.
그렇다면 이제는 마우스에 대한 상태를 읽어야 할 차례인데.... 앞 장에서도
간략하게 언급했듯이 키보드에서 했던 방식으로 쉽게 접근 할 수가 있다.
------------------------------------------------------------------------
(1) Direct Input 의 Mouse 를 왜 사용하는가 ?
윈도우즈에는 마우스 위치를 감지하기 위한 좋은 API 함수가 이미 있다.
GetCursorPos() 라는 함수인데 이 함수만 사용해도 현재의 마우스의 위치를
알 수가 있고, 앞에서 언급한 GetAsyncKeyState() 함수에서 VK_LBUTTON 등을
사용하면 현재의 마우스 버튼 상태도 알 수가 있다.
일반적인 게임( 윈도우 기반의 게임 )에서는 이 함수만으로도 충분히 마우스
관리를 할 수 있고 Direct X 기반의 게임이라고 하더라도 이 함수로도 충분히
마우스 상태 정보 얻는데 무리없이 사용할 수 있다.
그렇다면 Direct Input 의 Mouse 를 왜 사용하는가 ?
실제로 마우스 버튼의 상태를 얻기 위해서는 GetAsyncKeyState() 를 사용하
나 Direct Input 를 사용하나 똑같다. 하지만 Direct Input 를 사용하면 동
시에 마우스 버튼들의 상태와 마우스 위치 정보를 얻어 오기 때문에 속도가
빨라진다. 그리고 GetCursorPos() 라는 함수는 단지 윈도우 바탕화면에서의
절대적인 위치만을 돌려주지만 Direct Input 에서는 X, Y 축에 대한 이동 변
량(Delta)을 기준으로 하기 때문에 마우스의 위치를 잡는 것 뿐아니라 마우
스가 단위 시간에 얼마만큼의 속도로 움직였는지까지도 알아 낼 수가 있다.
예를들어 당구 게임을 만드는데 마우스를 밀어서 큐대를 조종한다고 하면
공을 칠 때 순간적인 y 변량으로 힘의 세기를 측정하고 x 의 변량으로 빗나
간 정도를 알 수 있을 것이다.
이 정도면 충분한 이유가 되었다고 생각하고 구현으로 들어가겠다.
------------------------------------------------------------------------
(2) Direct Input 의 Mouse 객체 구현
| type
| TMouseState = TDIMouseState;
|
| TDxInput = class
| constructor Create(hInstance : integer; Handle : integer);
| procedure Free;
| private
| public
| DirectInput : IDirectInput;
| DirectInputMouse : IDirectInputDevice;
| procedure GetMouseState(var MouseState : TMouseState);
| end;
이렇게 간단한 객체로 Direct Input 의 Mouse 객체가 만들어진다.
생성자, 소멸자, 그리고 변수 2 개와 함수하나...
우리는 항상 그렇듯 10줄의 설명 보다는 10줄의 코드를 더 빨리 이해하기 때
문에 implementation에 구현되어 있는 객체 메소드를 직접 보면서 설명하겠다.
아래에 보이는 것이 생성자다.
파라메터는 Instance와 Handle을 받는다.
| constructor TDxInput.Create(hInstance : integer; Handle : integer);
| var
| HR : HResult;
| begin
| // 선조의 Create를 실행한다.
| Inherited Create;
|
| // Direct Input 객체를 만든다.
| HR := DirectInputCreate(hInstance,DIRECTINPUT_VERSION,
| DirectInput,nil);
| if HR <> DI_OK then exit;
|
| // 마우스 디바이스를 생성한다.
| HR := DirectInput.CreateDevice(GUID_SysMouse,DirectInputMouse,nil);
| if HR <> DI_OK then exit;
|
| // 마우스에 대한 데이터 포맷을 설정한다.
| HR := DirectInputMouse.SetDataFormat(c_dfDIMouse);
| if HR <> DI_OK then exit;
|
| // 상호 협력 레벨을 설정한다.
| HR := DirectInputMouse.SetCooperativeLevel(Handle,
| DISCL_EXCLUSIVE or DISCL_FOREGROUND);
| if HR <> DI_OK then exit;
|
| // 마우스의 접근 권한을 얻는다.
| HR := DirectInputMouse.Acquire;
| if (HR <> DI_OK) and (HR <> DI_NOEFFECT) then begin
| // 실패했을 때 그 원인을 알아 본다.
| case HR of
| DIERR_NOTINITIALIZED :
| ShowMessage('Direct Input Error : NOTINITIALIZED');
| DIERR_INVALIDPARAM :
| ShowMessage('Direct Input Error : INVALIDPARAM');
| DIERR_OTHERAPPHASPRIO :
| ShowMessage('Direct Input Error : OTHERAPPHASPRIO');
| else
| ShowMessage('Direct Input Error');
| end;
| end;
이걸로 Direct Input의 Mouse에 대한 초기화가 모두 끝났다. 그럼 순차적으
로 다시 대충 설명해 보면..... ( 1 편에서 자세하게 했기 때문에.. )
1) DirectInputCreate(hInstance,DIRECTINPUT_VERSION,DirectInput,nil);
Direct Input 객체를 생성하는 함수다.
Keyboard 일 때와 같은 명령어다.
2) DirectInput.CreateDevice(GUID_SysMouse,DirectInputMouse,nil);
사용할 디바이스를 생성한다.
GUID_SysMouse가 첫번째 파라메터로 들어 갔기 때문에 IDirectInputDevice
로 선언된 변수인 DirectInputMouse은 마우스 디바이스로 생성된다.
3) DirectInputMouse.SetDataFormat(c_dfDIMouse);
디바이스에 대한 데이터 포맷을 설정한다.
현재는 마우스 디바이스이므로, 마우스 정보를 위한 구조체 포맷이라는 것
을 디바이스에게 알려준다.
4) DirectInputMouse.SetCooperativeLevel(Handle,
DISCL_EXCLUSIVE or DISCL_FOREGROUND);
상호 협력 레벨을 설정한다. 키보드 디바이스일 때와는 달리 EXCLUSIVE 로
설정을 한 것을 눈여겨 보기 바란다. DISCL_EXCLUSIVE 로 설정을 하면 다
른 프로그램에 대해서는 배타적으로 마우스 정보를 독점할 수가 있으며 마
우스 커서는 GDI 환경에서 사라지게 된다. 즉 마우스 커서는 자신이 직접
그려주어야 하는데... 모든 게임이 그렇듯 디폴트 마우스는 사라지고 자신
의 게임에 맞는 마우스 커서가 떠야 할 것이다.
물론 DISCL_NONEXCLUSIVE 로도 설정해도 된다. 그렇게 하면 마우스 커서가
눈에 보이게 된다. 하지만 마우스를 잡고 난동을 부리면서 아래 위로 커서
를 움직여 보면 원래 원했던 좌표로부터 자꾸 벗어난다(오차가 난다)는 것
을 알 수 있을 것이다. ( 여기서 좌표란 논리적으로 변량을 계산해서 나타
내는 마우스 위치를 말한다. )
그리고 키보드 할 때 빼 먹은 부분이 있는데, 키보드는 기본적으로 배타적
으로 사용되어 질수가 없다. 하지만 Direct X 7.0 에서는 키보드도 배타
적으로 사용될 수 있다고 하니 참고로 알아 두자.
5) DirectInputMouse.Acquire;
디바이스의 접근 권한을 얻는다. 현재는 마우스로 정의되어 있으므로 마우
스에 대한 접근 권한이다. Acquire를 호출 하지 않으면 마우스의 데이터를
가져 올 수 없다. 나머지는 키보드일 때와 같다.
그러면 이번에는 소멸자에 대해서 알아 보자.
| procedure TDxInput.Free;
| begin
| // 마우스 접근 권한 해제
| DirectInputMouse.Unacquire;
|
| // Direct Input 디바이스 객체 해제
| DirectInputMouse._Release;
| Pointer(DirectInputMouse) := nil;
|
| // Direct Input 객체 해제
| DirectInput._Release;
| Pointer(DirectInput) := nil;
|
| // 선조의 Free를 실행한다.
| Inherited;
| end;
내용은 키보드 일때와 완전히 같다.
그럼 이제 딱 하나 남은 가장 중요한 함수를 보자.
역시 키보드일 때와 용법은 같다.
| procedure TDxInput.GetMouseState(var MouseState : TMouseState);
| var
| HR : HResult;
| begin
| HR := DirectInputmouse.GetDeviceState(SizeOf(MouseState),@MouseState);
| if HR = DIERR_INPUTLOST then DirectInputMouse.Acquire;
| end;
1) DirectInputMouse.GetDeviceState(SizeOf(KeyState),@KeyState);
디바이스의 상태를 읽는다. 현재는 DirectInputMouse가 마우스로 정의되었
으므로 마우스에 대한 정보를 읽어 온다.
키보드일 때와 다른 점은 TMouseState 라는 구조체이다..
| type
| TMouseState = TDIMouseState;
위의 소스에 보면 이런 부분이 있다. DInput 헤더에 있는 TDIMouseState를
그대로 사용한 것인데 TDIMouseState 의 구조는 다음과 같다.
TDIMouseState = packed record
lX: Longint;
lY: Longint;
lZ: Longint;
rgbButtons: Array [0..3] of BYTE;
end;
IX - 마우스가 X 축으로 이동한 변량
IY - 마우스가 Y 축으로 이동한 변량
IZ - 마우스가 Z 축으로 이동한 변량 ( 3 차원 마우스 지원용이다. )
rgbButtons[0] - 왼쪽 마우스 버튼이 눌러지면 MSB가 1 그렇지 않으면 0
rgbButtons[1] - 오른쪽 마우스 버튼이 눌러지면 MSB가 1 그렇지 않으면 0
rgbButtons[2] - 2 버튼 이상의 마우스 지원용
rgbButtons[3] - 2 버튼 이상의 마우스 지원용
이렇게 이루어져 있다.
------------------------------------------------------------------------
(3) Direct Input 의 Mouse 객체 용법
객체를 구현했으니 이제는 사용하는 방법만 남았다.
일단 객체의 선언은 다음처럼 하면 된다.
DxInput : TDxInput;
그리고 생성은
DxInput := TDxInput.Create(hInstance,Handle);
소멸은
DxInput.Free;
DxInput := nil;
이렇게 사용한다.
그렇다면 용법을 보자...
| var
| MouseState : TMouseState;
|
| begin
| // MouseState 에 마우스 상태를 가져온다.
| DxInput.GetMouseState(MouseState);
|
| // 현재의 x, y 변량을 더한다.
| Inc(MousePos.X,MouseState.lX);
| Inc(MousePos.Y,MouseState.lY);
| // 마우스 버튼이 눌려졌는지의 여부를 알아 본다.
| if MouseState.rgbButtons[0] and $80 > 0 then
| if MouseState.rgbButtons[1] and $80 > 0 then
보다시피 한 번에 마우스 위치 정보와 마우스 버튼 정보를 얻어 오기 때문에
빠를수 밖에 없다. 그리고 윈도우의 메세지등을 거치지 않기고 바로 하드웨어
인터럽트에서 얻어 오기 때문에 부하도 적다.
------------------------------------------------------------------------
(4) Direct Input 의 Mouse 객체 사용 예제
그럼 실제로 사용을 해보자면....
1. 위에서 만든 Direct Input 객체를 따로 Unit 로 저장한다.
2. 새로운 프로젝트를 만들고, Unit1 에는 방금 만든 Direct Input 객체가 있
는 unit를 uses한다. 그리고 Direct Input 헤더인 DInput.Pas 도 uses한다.
3. 폼에는 타이머, 라벨, 버튼을 만든다.
4. TForm1 의 public 에 'DxInput : TDxInput;' 을 추가한다.
그리고 'MousePos : TPoint;' 도 추가한다. 이것은 마우스 커서의 현위치
를 기억해 두기 위해서 필요하다.
5. 버튼의 클릭 이벤트에 다음과 같이 입력한다.
DxInput := TDxInput.Create(hInstance,Handle);
MousePos := Point(0,0);
Timer1.Enabled := TRUE;
6. Form 의 Close 이벤트에 다음과 같이 입력한다.
Timer1.Enabled := FALSE;
DxInput.Free;
DxInput := nil;
7. 타이머 이벤트의 Interval을 1로 하고 이벤트에는 다음과 같이 입력한다.
var
MouseState : TMouseState;
s : string;
begin
DxInput.GetMouseState(MouseState);
Inc(MousePos.X,MouseState.lX);
Inc(MousePos.Y,MouseState.lY);
s := Format('(%4d,%4d) ',[MousePos.X,MousePos.Y]);
if MouseState.rgbButtons[0] and $80 > 0 then s := s + 'Left Button ';
if MouseState.rgbButtons[1] and $80 > 0 then s := s + 'Right Button ';
Label1.Caption := s;
end;
8. 실행한다.
9. 버튼을 누르면 Direct Input 의 마우스 핸들링이 시작되는데... 마우스의
움직임이나 버튼의 누름을 표시해 준다. 동시에 버튼을 눌러도 역시 결과
는 같다. ( 마우스 좌표의 기준은 Direct Input이 시작할때의 마우스 위치
가 (0,0) 으로 설정된다. )
------------------------------------------------------------------------
<< 에필로그 >>
지금까지 설명한 것은 Direct X 의 입력 디바이스 부분인 Direct Input 부분
이었습니다. 델파이로 게임 만드시려는 분들께 조금이나마 도움이 되었으면
좋겠습니다.
지금까지 델파이로 Direct Draw, 멀티미디어 타이머, DIB, Direct Input 에
대한 강좌를 했는데..... 앞으로 델파이로 하는 Direct Sound, Direct Music,
Direct Play 에 대한 강좌를 더 하고 싶습니다..
일요일 하루를 투자해서 2편 분량의 강좌를 했으니, 앞으로도 일요일마다 이
정도 분량의 강좌를 해 나가고 싶습니다. 그럼 관심 있으신 분들은 많이 기대
해 주세요..
그럼 마지막으로 한마디 남기겠습니다.
" A mountain is a mountain, Water is water. "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1999 / 10 / 31
'프로그래밍 > 공부관련' 카테고리의 다른 글
CString -> LPTSTR (0) | 2010.05.09 |
---|---|
ShellExecute Function (1) | 2010.05.09 |
CString 에서 Char* (0) | 2010.05.08 |
CIPAddressCtrl 의 ip주소를 cstring으로 받기 (0) | 2010.05.07 |
ShellExecute() 함수는 프로그램을 실행시킬 수 있는 함수이다 (0) | 2010.05.07 |