Saman_12
دوشنبه 30 اردیبهشت 1392, 14:21 عصر
سلام.
چند روز پیش بدنبال این بودم که کاربر بتونه با چند کلید (مثلا ctrl + shift + D + D0) برنامه رو فعال کنه یا حالا هر کار دیگه ای (پس میشه خارج از فرم هم استفاده کرد!)...
Imports System.Threading
Public Class ClsGKS
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Integer
Public Event Pressed(timeout As Int32, redo As Boolean, oncepress As Boolean)
Public Property Keyslist As Keys()
Public Sub New(Optional Keys() As Keys = Nothing)
Keyslist = Keys
End Sub
Public Sub StartCapture(Optional timeout As Int32 = 0, Optional redo As Boolean = True, Optional oncepress As Boolean = True)
Dim TGetKS As New Thread(AddressOf GetKS)
TGetKS.IsBackground = True
TGetKS.Start({timeout, oncepress, redo})
End Sub
Private Sub WaitOn()
For i As Int32 = 0 To Keyslist.Length - 1
Thread.Sleep(1)
If GetAsyncKeyState(Keyslist(i)) Then i = 0
Next
End Sub
Private Sub GetKS(args As Object)
Dim timeout As Int32 = args(0)
Dim oncepress As Boolean = args(1)
Dim redo As Boolean = args(2)
Dim IsKeyspress As New Boolean
Dim Pressedlist As New ArrayList
Dim Starttime As Date = Nothing
Dim Endtime As Date = Nothing
Do Until IsKeyspress
Thread.Sleep(1)
Starttime.AddMilliseconds(1)
For i As Int32 = 0 To Keyslist.Length - 1
If GetAsyncKeyState(Keyslist(i)) AndAlso Not Pressedlist.Contains(i) Then
Pressedlist.Add(i)
If Pressedlist.Count = 1 Then Starttime = Date.Now
End If
Next
If Pressedlist.Count = Keyslist.Length Then
Endtime = Date.Now
If timeout = 0 Then Starttime = Endtime
If Not (Endtime - Starttime).TotalMilliseconds > timeout Then
IsKeyspress = True : RaiseEvent Pressed(timeout, redo, oncepress)
If oncepress Then WaitOn()
If redo Then StartCapture(timeout, redo, oncepress)
Else
WaitOn()
Pressedlist.Clear()
End If
End If
Loop
End Sub
End Class
اینم همون بالایی هست یه نمور تغییرش دادم :
Imports System.Threading
Public Class GKS
Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Keys) As Boolean
Private _keyspresscallback As ContextCallback
Public Sub New(ByVal KeysPressCallback As ContextCallback)
_keyspresscallback = KeysPressCallback
End Sub
Public Event KeysPress(keysl As List(Of Keys))
<MTAThread()> _
Public Sub CaptureKeys(keys As List(Of Keys), Optional oncepress As Boolean = False, Optional timeout As Int32 = 1500, Optional checktime As Int32 = 250)
Dim KeysListed As New List(Of Keys)
Dim StWatch As New Stopwatch
Dim TimerCallback As New TimerCallback(AddressOf _capturekayes)
Dim NewTimer As New Timer(TimerCallback, {keys, oncepress, timeout, StWatch, KeysListed}, 0, checktime)
End Sub
Private Sub _capturekayes(args As Object)
Dim keysl As List(Of Keys) = args(0)
Dim oncepress As Boolean = args(1)
Dim timeout As Int32 = args(2)
Dim StWatch As Stopwatch = args(3)
Dim keyslisted As List(Of Keys) = args(4)
If StWatch.ElapsedMilliseconds >= timeout And Not timeout = 0 Then keyslisted.Clear() : StWatch.Reset()
If keyslisted.Count < keysl.Count Then
For Each key As Keys In keysl
If GetAsyncKeyState(key) And Not keyslisted.Contains(key) Then
keyslisted.Add(key)
If keyslisted.Count = 1 Then StWatch.Start()
End If
Next
ElseIf keyslisted.Count = keysl.Count Then
_keyspresscallback.Invoke(keyslisted)
keyslisted.Clear()
If oncepress Then
For i = 0 To keysl.Count - 1
If GetAsyncKeyState(keysl(i)) Then i = 0 : keyslisted.Clear() : StWatch.Reset()
Next
End If
StWatch.Reset()
End If
End Sub
End Class
حاصلش شد کد بالا. گفتم دوستان بی بهره نمانند...(البته استاید دیگه جسارت رو ببخشید. باید از شما بهره برد...)
طریقه استفاده اش هم که کاملا واضح (و بسی ضایع) است وبه نظر نمیاد مشکل خاصی باشه!
در جهت رفع ابهام :
کافیه در ابتدا یه کلاس به پروژه اظافه کنید و اینا رو کپی کنید.
حالا هر جا که دوست دارید یه نمونه از کلاس تعریف کنید و کلید ها رو هم زمان یا بعدا بهش بدید :
Dim gks As New ClsGKS({Keys.ControlKey, Keys.ShiftKey, Keys.D, Keys.D0})
توجه کنید که میتونید هر چقدر کلید دوست دارین تعریف کنید ولی به نظرم از چهار تا بیشتر اذیت کردنه!
حالا یه ساب تعریف کنید که وقتی کلید ها فشرده شدن کد دلخواه شما رو اجرا کنه.(توجه کنید این ساب با یه ترد دیگه اجرا میشه پس هواستون به Invoke کردن باشه!) :
Private Sub pressed()
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf pressed))
Else
Me.Show()
Me.Focus()
End If
End Sub
و در آخر هم هندل این ساب رو بدین دست کلاس :
AddHandler gks.Pressed, AddressOf pressed
رسیدیم سر اصل مطلب اینجا شما ساب کپچر رو صدا میکنید .
این ساب سه تا ارگامنت داره که آشنایید با هاشون (نیستید هم میشید!)
1. timeout : مدت زمانی که میخواید کاربر بعد از فشردن اولین کلید وقت داشته باشه تا بقیه رو وارد کنه که عادیش صفر هست یعنی فرقی نمیکنه تو چه فاصله زمانی باشه.
2.redo : اگه true باشه تشیخص دوباره هم اتفاق میفته یعنی فقط برای اولین بار کلید ها کار میکنن اگه false باشه.
3.oncepress: این هم اگر true باشه کاربر تا وقتی دستش رو اون کلید هاست فقط یک بار کار میکنن یعنی اگر کلید های ترکیبی رو نگه داره و تشیخص داده بشن باید کلید هارو رها کنه واسه دفعی بعد ,که تنها وقتی redo=true باشه کار میکنه.اگه هم false باشه که تا وقتی کاربر دستش رو کلید هاست اون سابی که تعریف کردین مدام اجرا میشه.
(4.) توی اون یه نمور تغییر یه checktime اظافه شده که فاصله زمانی چک کردن کلید هاست مث یه تایمر(البته خود تایمره!) :
gks.StartCapture(3000)
چند روز پیش بدنبال این بودم که کاربر بتونه با چند کلید (مثلا ctrl + shift + D + D0) برنامه رو فعال کنه یا حالا هر کار دیگه ای (پس میشه خارج از فرم هم استفاده کرد!)...
Imports System.Threading
Public Class ClsGKS
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Integer
Public Event Pressed(timeout As Int32, redo As Boolean, oncepress As Boolean)
Public Property Keyslist As Keys()
Public Sub New(Optional Keys() As Keys = Nothing)
Keyslist = Keys
End Sub
Public Sub StartCapture(Optional timeout As Int32 = 0, Optional redo As Boolean = True, Optional oncepress As Boolean = True)
Dim TGetKS As New Thread(AddressOf GetKS)
TGetKS.IsBackground = True
TGetKS.Start({timeout, oncepress, redo})
End Sub
Private Sub WaitOn()
For i As Int32 = 0 To Keyslist.Length - 1
Thread.Sleep(1)
If GetAsyncKeyState(Keyslist(i)) Then i = 0
Next
End Sub
Private Sub GetKS(args As Object)
Dim timeout As Int32 = args(0)
Dim oncepress As Boolean = args(1)
Dim redo As Boolean = args(2)
Dim IsKeyspress As New Boolean
Dim Pressedlist As New ArrayList
Dim Starttime As Date = Nothing
Dim Endtime As Date = Nothing
Do Until IsKeyspress
Thread.Sleep(1)
Starttime.AddMilliseconds(1)
For i As Int32 = 0 To Keyslist.Length - 1
If GetAsyncKeyState(Keyslist(i)) AndAlso Not Pressedlist.Contains(i) Then
Pressedlist.Add(i)
If Pressedlist.Count = 1 Then Starttime = Date.Now
End If
Next
If Pressedlist.Count = Keyslist.Length Then
Endtime = Date.Now
If timeout = 0 Then Starttime = Endtime
If Not (Endtime - Starttime).TotalMilliseconds > timeout Then
IsKeyspress = True : RaiseEvent Pressed(timeout, redo, oncepress)
If oncepress Then WaitOn()
If redo Then StartCapture(timeout, redo, oncepress)
Else
WaitOn()
Pressedlist.Clear()
End If
End If
Loop
End Sub
End Class
اینم همون بالایی هست یه نمور تغییرش دادم :
Imports System.Threading
Public Class GKS
Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Keys) As Boolean
Private _keyspresscallback As ContextCallback
Public Sub New(ByVal KeysPressCallback As ContextCallback)
_keyspresscallback = KeysPressCallback
End Sub
Public Event KeysPress(keysl As List(Of Keys))
<MTAThread()> _
Public Sub CaptureKeys(keys As List(Of Keys), Optional oncepress As Boolean = False, Optional timeout As Int32 = 1500, Optional checktime As Int32 = 250)
Dim KeysListed As New List(Of Keys)
Dim StWatch As New Stopwatch
Dim TimerCallback As New TimerCallback(AddressOf _capturekayes)
Dim NewTimer As New Timer(TimerCallback, {keys, oncepress, timeout, StWatch, KeysListed}, 0, checktime)
End Sub
Private Sub _capturekayes(args As Object)
Dim keysl As List(Of Keys) = args(0)
Dim oncepress As Boolean = args(1)
Dim timeout As Int32 = args(2)
Dim StWatch As Stopwatch = args(3)
Dim keyslisted As List(Of Keys) = args(4)
If StWatch.ElapsedMilliseconds >= timeout And Not timeout = 0 Then keyslisted.Clear() : StWatch.Reset()
If keyslisted.Count < keysl.Count Then
For Each key As Keys In keysl
If GetAsyncKeyState(key) And Not keyslisted.Contains(key) Then
keyslisted.Add(key)
If keyslisted.Count = 1 Then StWatch.Start()
End If
Next
ElseIf keyslisted.Count = keysl.Count Then
_keyspresscallback.Invoke(keyslisted)
keyslisted.Clear()
If oncepress Then
For i = 0 To keysl.Count - 1
If GetAsyncKeyState(keysl(i)) Then i = 0 : keyslisted.Clear() : StWatch.Reset()
Next
End If
StWatch.Reset()
End If
End Sub
End Class
حاصلش شد کد بالا. گفتم دوستان بی بهره نمانند...(البته استاید دیگه جسارت رو ببخشید. باید از شما بهره برد...)
طریقه استفاده اش هم که کاملا واضح (و بسی ضایع) است وبه نظر نمیاد مشکل خاصی باشه!
در جهت رفع ابهام :
کافیه در ابتدا یه کلاس به پروژه اظافه کنید و اینا رو کپی کنید.
حالا هر جا که دوست دارید یه نمونه از کلاس تعریف کنید و کلید ها رو هم زمان یا بعدا بهش بدید :
Dim gks As New ClsGKS({Keys.ControlKey, Keys.ShiftKey, Keys.D, Keys.D0})
توجه کنید که میتونید هر چقدر کلید دوست دارین تعریف کنید ولی به نظرم از چهار تا بیشتر اذیت کردنه!
حالا یه ساب تعریف کنید که وقتی کلید ها فشرده شدن کد دلخواه شما رو اجرا کنه.(توجه کنید این ساب با یه ترد دیگه اجرا میشه پس هواستون به Invoke کردن باشه!) :
Private Sub pressed()
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf pressed))
Else
Me.Show()
Me.Focus()
End If
End Sub
و در آخر هم هندل این ساب رو بدین دست کلاس :
AddHandler gks.Pressed, AddressOf pressed
رسیدیم سر اصل مطلب اینجا شما ساب کپچر رو صدا میکنید .
این ساب سه تا ارگامنت داره که آشنایید با هاشون (نیستید هم میشید!)
1. timeout : مدت زمانی که میخواید کاربر بعد از فشردن اولین کلید وقت داشته باشه تا بقیه رو وارد کنه که عادیش صفر هست یعنی فرقی نمیکنه تو چه فاصله زمانی باشه.
2.redo : اگه true باشه تشیخص دوباره هم اتفاق میفته یعنی فقط برای اولین بار کلید ها کار میکنن اگه false باشه.
3.oncepress: این هم اگر true باشه کاربر تا وقتی دستش رو اون کلید هاست فقط یک بار کار میکنن یعنی اگر کلید های ترکیبی رو نگه داره و تشیخص داده بشن باید کلید هارو رها کنه واسه دفعی بعد ,که تنها وقتی redo=true باشه کار میکنه.اگه هم false باشه که تا وقتی کاربر دستش رو کلید هاست اون سابی که تعریف کردین مدام اجرا میشه.
(4.) توی اون یه نمور تغییر یه checktime اظافه شده که فاصله زمانی چک کردن کلید هاست مث یه تایمر(البته خود تایمره!) :
gks.StartCapture(3000)