مقدمه
Direct Input 8 همانطور که از نامش مشخص است به شما اجازه می دهد که بتوانید برنامه هایی بنویسید که توسط هر نوع دستگاه ورودی کنترل شود .
Direct Input 8 دارای چندین مزیت نسبت به استفاده از کنترلهای ورودی خود ویژوال بیسیک دارد – کنترلهایی مثل Form_KeyUp, Form_KeyDown, Form_MouseMove – و همچنین قابلیت کنترل بیشتری نسبت به توابع استاندارد Win32 از قبیل GetCursorPos, GetKeyState دارد .
Direct Input 8 سریعتر ، کاراتر و قدرتمند تر بوده و برای ساخت بازیها طراحی شده بنابراین باعث کندی برنامه ها نخواهد شد .
چگونگی کار با Direct Input 8 برای گرفتن ورودی از کیبرد
دو روش برای استفاده از کیبرد در DirectX8 وجود دارد : روش polling و روش event-based که هر دو دارای مزایا و معایبی هستند .
بطور کلی در اغلب طراحیها از روش event-based استفاده می شود زیرا کار با آن راحت تر اسن . در این روش هر پیغام فرستاده شده ازطرف دستگاه ورودی log می شود و برنامه نیازی به هیچگونه پردازشی بمنظور منتظر ماندن برای یک پیغام از طرف ورودی ندارد ، بنابر این کاراتر است . در روش polling کنترل کمی دقیقتر و راحتر است .
اگر در مورد برنامه نویسی بر مبنای polling و بر مبنای event اطلاعات کافی ندارید می توانید از منابع موجود در سایتهایی چون
روش Polling
مراحل این روش عبارتند از :
۱ – تعریفات Declerations : یک فرم ایجاد کرده و یک TextBox به نام txtOutput با خصوصیات Multiline ، Locked و Vertical Scroll Bar در آن قرار دهید . کدهای زیر را در بخش کدنویسی این فرم بنویسید :
Private Const UsePollingMethod As Boolean = True
Private Const UseEventMethod As Boolean = False
‘نکته مهم اینست که تنها یکی از دو ثابت فوق بایستی True باشد .
Private bRunning As Boolean
‘این متغیر برای polling استفاده می شود
Private DX As DirectX8
Private DI As DirectInput8
‘تعریف شی اصلی DirectX و شی DirectInput
Private DIDevice As DirectInputDevice8
Private DIState As DIKEYBOARDSTATE
‘این دو شی برای دسترسی به دستگاه ورودی ( کیبرد ) استفاده می شوند
Private KeyState(0 To 255) As Boolean
‘آرایه ای برای تشخیص فشرده شدن کلید
Private Const BufferSize As Long = 10
‘ سایز بافر نگهدارنده event ها . در روش event-based این مقدار برابر یک و در روش polling برابر ۱۰ تا ۲۰ است ( بسته به سرعت حلقه بازی )
Private Declare Sub Sleep Lib “kernel32″ (ByVal dwMilliseconds As Long)x
‘ تابع Sleep برای متوقف کردن حلقه polling در صورت بالا بودن نرخ ورودی
۲- مقدار دهی اولیه Initialisation : این بخش سه مرحله دارد :
در مرحله اول اشیا و Device ها ساخته می شوند .
در مرحله دوم تنظیمات مربوط به Device انجام می شود .
در مرحله سوم به Device می گوئیم که می خواهیم شروع به استفاده از آن کنیم .
در Form_Load کدهای زیر را بنویسید :
Me.Show
Dim I As Long
Dim DevProp As DIPROPLONG
Dim DevInfo As DirectInputDeviceInstance8
Dim pBuffer(0 To BufferSize) As DIDEVICEOBJECTDATA
If UsePollingMethod And UseEventMethod Then
MsgBox “You must select only one of the constants before running”x
Unload Me
End
End If
If UsePollingMethod Then txtOutput.Text = “Using Polling Method” & vbCrLf
If UseEventMethod Then txtOutput.Text = “Using Event Based Method” & vbCrLf
‘مقداردهی اولیه روش انتخاب شده
Set DX = New DirectX8
Set DI = DX.DirectInputCreate
Set DIDevice = DI.CreateDevice(“GUID_SysKeyboard”)x
DIDevice.SetCommonDataFormat DIFORMAT_KEYBOARD
DIDevice.SetCooperativeLevel frmMain.hWnd, DISCL_BACKGROUND Or ISCL_NONEXCLUSIVE
‘برپاسازی بافر
DevProp.lHow = DIPH_DEVICE
DevProp.lData = BufferSize
DIDevice.SetProperty DIPROP_BUFFERSIZE, DevProp
‘ به دایرکت ایکس می گوئیم که می خواهیم از دستگاه ورودی استفاده کنیم
DIDevice.Acquire
‘استخراج اطلاعاتی در مورد دستگاه ورودی
Set DevInfo = DIDevice.GetDeviceInfo()x
txtOutput.Text = txtOutput.Text & “Product Name: ” & DevInfo.GetProductName & vbCrLf
txtOutput.Text = txtOutput.Text & “Device Type: ” & DevInfo.GetDevType & vbCrLf
txtOutput.Text = txtOutput.Text & “GUID: ” & DevInfo.GetGuidInstance & vbCrLf
‘در صورتی که بخواهیم به برنامه خاتمه بدهیم کدهای زیر را می نویسیم
DIDevice.Unacquire
Set DIDevice = Nothing
Set DI = Nothing
Set DX = Nothing
Unload Me
End
3 – گرفتن ورودی از کیبرد : در این بخش فرض کنید بخواهیم یک بازی را در یک حلقه Do-Loop شبیه سازی کنیم . در این حلقه هر بار فشرده شدن کلیدهای کیبرد را چک می کنیم :
If Not Err.Number Then bRunning = True
Do While bRunning
‘دریافت اطلاعات شامل خواندن وضعیت کیبرد ، خواندن اطلاعات بافر و سپس خطا
DIDevice.GetDeviceStateKeyboard DIState
DIDevice.GetDeviceData pBuffer, DIGDD_DEFAULT
If Err.Number = DI_BUFFEROVERFLOW Then
Msgbox(“BUFFER OVERFLOW (Compensating)…”)x
GoTo ENDOFLOOP:
End If
‘بررسی فشرده شدن کلیدها
For I = 0 To 255
If DIState.Key(I) = 128 And (Not KeyState(I) = True) Then
txtOutput.Text = txtOutput.Text & “{ DOWN } ” & KeyNames(CInt(I))& vbCrLf
txtOutput.SelStart = Len(txtOutput.Text)x
KeyState(I) = True
End If
Next I
‘بررسی رها شدن کلید
For I = 0 To BufferSize
If KeyState(pBuffer(I).lOfs) = True And pBuffer(I).lData = 0 Then
KeyState(pBuffer(I).lOfs) = False
txtOutput.Text = txtOutput.Text & “{ UP } ” & KeyNames(CInt(pBuffer(I).lOfs)) & vbCrLf
txtOutput.SelStart = Len(txtOutput.Text)x
End If
Next I
Sleep (50)x
DoEvents
ENDOFLOOP:
Loop
در کد فوق یک تابع KeyName وجود دارد که نام کلید فشارداده شده را بر می گرداند . بخشی از این تابع را در زیر می بینید :
Function KeyNames(iNum As Integer) As String
Dim aKeys(0 To 255) As String
aKeys(1) = “DIK_ESCAPE”
aKeys(2) = “DIK_1 On main keyboard”x
aKeys(3) = “DIK_2 On main keyboard”x
aKeys(4) = “DIK_3 On main keyboard”x
aKeys(5) = “DIK_4 On main keyboard”x
aKeys(6) = “DIK_5 On main keyboard”x
aKeys(7) = “DIK_6 On main keyboard”x
aKeys(8) = “DIK_7 On main keyboard”x
aKeys(9) = “DIK_8 On main keyboard”x
aKeys(10) = “DIK_9 On main keyboard”x
aKeys(11) = “DIK_0 On main keyboard”x
aKeys(12) = “DIK_MINUS On main keyboard”x
aKeys(13) = “DIK_EQUALS On main keyboard”x
aKeys(14) = “DIK_BACK BACKSPACE”x
aKeys(15) = “DIK_TAB”x
aKeys(16) = “DIK_Q”x
aKeys(17) = “DIK_W”x
aKeys(18) = “DIK_E”x
aKeys(19) = “DIK_R”x
aKeys(20) = “DIK_T”x
.
.
.
KeyNames = aKeys(iNum)x
End Function
=======================
موضوع : کنترل کیبرد با روش Event-Based
مقداردهی اولیه و مفاهیم اصلی در روش Event-Based مشابه روش Polling است و تنها بایستی ساختار بخش جمع آوری داده و حلقه پردازشی را تغییر دهیم . مراحل کار با روش Event-Based بصورت زیر می باشد :
۱ – تعاریف و مقداردهی اولیه : در بخش تعاریف دو تعریف جدید بصورت زیر داریم :
Dim hEvent As Long
Implements DirectXEvent8
hEvent یک پارامتر هندل برای یک می باشد .
نکته : زمانی که کلیدی فشرده یا رها می شود ، DirectX این امر با فراخوانی تابعی به اسم DirectXEvent8_DXCallback به برنامه شما اطلاع می دهد . ( این نوع توابع را Call Back Function گویند ) . این تابع به برنامه شما می گوید که یک رویداد اتفق افتاده است و بایستی بافرها را چک کند .
تنها تغییری که در بخش مقداردهی اولیه نیاز است ، برپاسازی یک event می باشد :
If UseEventMethod Then
hEvent = DX.CreateEvent(frmMain)x
DIDevice.SetEventNotification hEvent
End If
در انتهای برنامه نیز کد زیر را برای از بین بردن event اضافه کنید :
If hEvent <> 0 Then DX.DestroyEvent hEvent
۲ – استفاده از event : برای این بخش کدهایی را در داخل تابع DirectXEvent8_DXCallback می نویسیم :
Private Sub DirectXEvent8_DXCallback(ByVal eventid As Long)x
‘متغیرهای موردنیاز
Dim I As Long
Dim pBuffer(0 To BufferSize) As DIDEVICEOBJECTDATA
If eventid = hEvent Then
If DIDevice Is Nothing Then Exit Sub
‘درصورت رخ دادن event داده را از کیبرد می گیریم
DIDevice.GetDeviceStateKeyboard DIState
DIDevice.GetDeviceData pBuffer, DIGDD_DEFAULT
‘چک کردن تمام کلیدها برای اینکه متوجه شویم چه اتفاقی افتاده است
For I = 0 To 255
‘عدد ۱۲۸ نشان دهنده key_down event است .
If DIState.Key(I) = 128 Then
If pBuffer(0).lData = 128 Then
txtOutput.Text = txtOutput.Text & “{ DOWN } ” & KeyNames(CInt(I)) & vbCrLf
End If
End If
‘کد فوق برای بررسی فشرده شدن یک کلید بود . کد زیر رها شدن کلید را بررسی می کند
If (pBuffer(0).lData = 0 And pBuffer(0).lOfs = I) Then
txtOutput.Text = txtOutput.Text & “{ UP }” & KeyNames(CInt(I)) & vbCrLf
End If
txtOutput.SelStart = Len(txtOutput.Text)x
Next I
End If
End Sub
=====================
موضوع : کنترل ماوس با DirectX Input
مقدمه :
برای استفاده از ماوس در برنامه های مالتی مدیا و بازیها همانند کی برد می توانیم از امکانات دایرکت ایکس استفاده کنیم . روش کنترل ماوس توسط DirectX Input بسیار ساده بوده و مشابه کنترل کیبرد می باشد بنابراین درصورتی که دو درس گذشته را نخوانده این پیشنهاد می کنم ابتدا آنها را مطالعه کنید .
برپاسازی Device :
علاوه بر متغیرهایی که در بخش کنترل کیبرد تعریف شد بایستی متغیرهای جدید زیر را نیز در ابتدای برنامه تان تعریف کنید :
Private Const mSpeed As Single = 2
Private Const BufferSize As Long = 10
Private mPosition As Point
mSpeed مقدار سرعت حرکت کرسر ماوس را مشخص می کند .
BufferSize سایز بافر DI می باشد .
mPosition موقعیت جاری کرسر ماوس را نشان می دهد .
در مرحله بعدی بایستی مقداردهی های اولیه لازم را انجام دهید :
Set DIDevice = DI.CreateDevice(“guid_SysMouse”)x
Call DIDevice.SetCommonDataFormat(DIFORMAT_MOUSE)x
Call DIDevice.SetCooperativeLevel(frmMain.hWnd, DISCL_FOREGROUND Or DISCL_EXCLUSIVE)x
تفاوت عمده کدهای فوق با کدهای مقداردهی اولیه در بخش کی برد آنست که cooperativelevel تغییر کرده است . در اینجا گفته شده که ما می خواهیم از ماوس بصورت انحصاری در برنامه استفاده کنیم . این حالت برای برنامه های window-base مناسب نیست و بهترست از آن در بازیهایی که بصورت full screan هستند استفاده کنید .
خواندن ورودی از ماوس :
در این بخش می توانید هم از روش polling و هم event-based استفاده کنید . نکته مهمی که در اینجا وجود دارد آنست که Direct Input فقط حرکت داده شدن ماوس و کلیک شدن یک دکمه را به شما اطلاع می دهد و برای تشخیص حالتهای double click و single click خودتان بایستی کد بنویسید برای مثال اگر فاصله زمانی بین دو کلیک کمتر از ۴۰ میلی ثانیه باشد آنگاه این یک double click بوده است .
کد زیر حرکت داده شدن ماوس و کلیک یکی از سه دکمه آنرا اطلاع می دهد :
Dim DevData(1 To BufferSize) As DIDEVICEOBJECTDATA
Dim nEvents As Long
Dim I As Long
nEvents = DIDevice.GetDeviceData(DevData, DIGDD_DEFAULT)x
For I = 1 To nEvents
Select Case DevData(I).lOfs
Case DIMOFS_X
mPosition.x = mPosition.x + (DevData(I).lData * mSpeed)x
If mPosition.x < 0 Then mPosition.x = 0
If mPosition.x > frmMain.ScaleWidth Then mPosition.x = frmMain.ScaleWidth
imgCursor.Top = mPosition.y
imgCursor.Left = mPosition.x
lablel(1).Caption = “Mouse Coordinates: [" & mPosition.x & ", " & mPosition.y & "]“x
Case DIMOFS_Y
mPosition.y = mPosition.y + (DevData(I).lData * mSpeed)x
If mPosition.y < 0 Then mPosition.y = 0
If mPosition.y > frmMain.ScaleHeight Then mPosition.y = frmMain.ScaleHeight
imgCursor.Top = mPosition.y
imgCursor.Left = mPosition.x
lablel(1).Caption = “Mouse Coordinates: [" & mPosition.x & ", " & mPosition.y & "]“x
Case DIMOFS_BUTTON0
label(2).Caption = “Button 0 State: ” & IIf(DevData(I).lData = 0, “Up”, “Down”)x
Case DIMOFS_BUTTON1
label(3).Caption = “Button 1 State: ” & IIf(DevData(I).lData = 0, “Up”, “Down”)x
Case DIMOFS_BUTTON2
label(4).Caption = “Button 2 State: ” & IIf(DevData(I).lData = 0, “Up”, “Down”)x
Case DIMOFS_BUTTON3
label(5).Caption = “Button 3 State: ” & IIf(DevData(I).lData = 0, “Up”, “Down”)x
End Select
Next I
برای استفاده از کد فوق در روش Polling ، بایستی آنرا در یک حلقه Do while-Loop قرار دهید .
برای استفاده از کد فوق در روش Event-Based ، بایستی آنرا درون روتین DirectXEvent8_DXCallback قرار دهید .
دیدگاه خود را بیان کنید.
باید وارد سایت شده باشید برای دیدگاه دادن