Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsVB SyntaxEnterprise DevelopmentDatabase AccessControlsCOMWin APICrystal ReportDeploymentGeneralGeneral 2
Related Topics
VB.NET / ASP.NETMS SQL ServerMS AccessOther Database ProductsMore Topics ...

VB Forum / General / June 2007



Tip: Looking for answers? Try searching our database.

GetAsyncKeyState not working with Right Click

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
MP - 28 Jun 2007 22:22 GMT
I thought this used to work
Now it doesn't seem to
What am I forgetting?

'(in AutoCad vba) but I should think vb would be similar except for the
KeyCodeConstants.vbKeyRButton reference ( = 2)

Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As
Integer
Private Const VK_RMC = KeyCodeConstants.vbKeyRButton

Public Function UserRightClicked() As Boolean
 If (0 > GetAsyncKeyState(VK_RMC)) Then UserRightClicked = True
End Function

by doesn't seem to work, I mean when used in an error trap it says I didn't
hit right click when I did!
eg

On Error GoTo ErrCtl
....ask for selection from user
   oDoc.Utility.GetEntity oEnt, vpt, "Pick text or block  "

... if user hits right click selection fails with error sending us to ErrCtl
... I should get msgBox "right" but I don't....

ErrCtl:
If UserRightClicked Then
   MsgBox"Right"
   Else
   MsgBox"Nope"
End if
MP - 28 Jun 2007 23:05 GMT
>I thought this used to work
> Now it doesn't seem to
> What am I forgetting?
>
> '(in AutoCad vba) but I should think vb would be similar except for the
> KeyCodeConstants.vbKeyRButton reference ( = 2)

'ok this seems to work in limited testing
'in the calling sub I need to hit GetAsyncKeyState to clear the value before
trying the line that could throw the error I'm trying to catch
'but that means I need to define GetAsyncKeyState in every scope I want to
use the test, or make it public in the .bas mod???
'is there a right way to do this?
:-)

'------------
Sub Main()
'initialize GetAsyncKeyState
Call GetAsyncKeyState(anyInteger)

On Error Resume Next' just for this example
oDoc.Utility.GetEntity oEnt, vpt, "Pick text or block"
If Err Then
  If UserRightClicked Then
       MsgBox "Right"
etc
'--------------

'in .Bas mod
Private Const VK_RBUTTON As Long = &H2&
Public Function UserRightClicked() As Boolean
 If GetAsyncKeyState(VK_RBUTTON) = 1 Then UserRightClicked = True
End Function
Steve Gerrard - 29 Jun 2007 02:44 GMT
> 'ok this seems to work in limited testing
> 'in the calling sub I need to hit GetAsyncKeyState to clear the value before
[quoted text clipped - 3 lines]
> 'is there a right way to do this?
> :-)

You could just make a Public sub in  the .bas module to get entities, and put
the calls in there.
With appropriate types for Doc, Entity, and Vpt, something like:

Public Sub GetDocEntity(Doc As X, Entity As Y, Vpt As Z, Msg As String)
'initialize GetAsyncKeyState
Call GetAsyncKeyState(anyInteger)
On Error Resume Next' just for this example
Doc.Utility.GetEntity Entity, Vpt , Msg
If Err.Number <> 0 Then
 If GetAsyncKeyState(VK_RBUTTON) = 1 Then
       MsgBox "Right"
 End If
End If
End Sub

' ....

Sub Main()
   GetDocEntity oDoc, oEnt, vpt, "Pick text or block"
End Sub
Ken Halter - 28 Jun 2007 23:06 GMT
>I thought this used to work
> Now it doesn't seem to
[quoted text clipped - 10 lines]
>  If (0 > GetAsyncKeyState(VK_RMC)) Then UserRightClicked = True
> End Function

This works in VB6 - need a form with a timer
'==============
Option Explicit

Private Declare Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As
Long) As Integer
Private Const VK_RBUTTON As Long = &H2

Private Sub Form_Load()
  With Timer1
     .Enabled = False
     .Interval = 100
     .Enabled = True
  End With
End Sub

Private Sub Timer1_Timer()
  If GetAsyncKeyState(VK_RBUTTON) < 0 Then
     Debug.Print "RButton Down"
  Else
     Debug.Print "RButton Up"
  End If
End Sub

Signature

Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
In Loving Memory - http://www.vbsight.com/Remembrance.htm

MP - 28 Jun 2007 23:33 GMT
>>I thought this used to work
>> Now it doesn't seem to
[quoted text clipped - 34 lines]
>   End If
> End Sub

Thanks for the response Ken,
What I'm trying to do is use it in error traps to detect which key caused
the error
In my case space, esc, enter, or right click can be meaningful in response
to an autocad command.
There seems to be something about having to initialize the call before
checking the value again to see if it was pressed "since the previous call
to GetAsnyc"
Due to the Hi bit Lo bit values (which I don't know how to get at)
The hi bit being if the key is currently pressed and the lo bit if it was
pressed since last time the function was called (or is that visa versa ?
<g>)
Any way thanks for looking at it.
The workaround I posted just before your response seems to work on limited
testing but doesn't seem to be an elegant solution,
having to call it directly, before letting the error check call the test
function "UserRightClicked" etc.

Mark
Mike Williams - 29 Jun 2007 12:59 GMT
> The workaround I posted seems to work on limited testing but doesn't seem
> to be an elegant solution . . .

I'm not sure how your mention of AutoCad VBA fits into this but I assume you
are trying to detect the current state of the right mouse button system wide
from your VB or VBA program? In that case a low level hook might be the best
solution. When hooking, unless you jump through lots of hoops to achieve
"safe in the IDE" hooking, you obviously need to be careful when working in
the VB IDE that you close your app properly using the normal Close button
(and not use the VB Run / End menu while the hook is still on), but in a
compiled exe there are no such problems. Try the following code. Paste the
first block into a VB Form and the second block into a standarde code
module. At runtime your app can check the current state of the right mouse
button at any time merely by checking the value of the Publicly declared
variable RightButton, which will return True or False:

' *** START OF FORM CODE ***
Option Explicit
Private Sub Form_Load()
SetMouseHook
End Sub

Private Sub Form_Unload(Cancel As Integer)
ReleaseMouseHook
End Sub
' *** END OF FORM CODE ***
'
' *** START OF MODULE CODE ***
Option Explicit
Private Declare Function SetWindowsHookEx _
 Lib "user32" Alias "SetWindowsHookExA" _
 (ByVal idHook As Long, ByVal lpfn As Long, _
 ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx _
 Lib "user32" (ByVal hHook As Long) As Long
Private Const WH_MOUSE_LL As Long = 14
Private Declare Function CallNextHookEx _
 Lib "user32" (ByVal hHook As Long, _
 ByVal nCode As Long, ByVal wParam As Long, _
 lParam As Any) As Long
Private Const HC_ACTION = 0
Private Const WM_RBUTTONDOWN As Long = &H204
Private Const WM_RBUTTONUP As Long = &H205
Private Hook As Long
Public RightButton As Boolean

Public Sub SetMouseHook()
Hook = SetWindowsHookEx(WH_MOUSE_LL, _
   AddressOf MouseProc, App.hInstance, 0)
End Sub

Public Sub ReleaseMouseHook()
UnhookWindowsHookEx Hook
End Sub

Private Function MouseProc(ByVal nCode As Long, _
  ByVal wParam As Long, ByVal lParam As Long) As Long
If (nCode = HC_ACTION) Then
 Select Case wParam
   Case WM_RBUTTONDOWN: RightButton = True
   Case WM_RBUTTONUP: RightButton = False
 End Select
End If
' Done our job so allow the system to carry on as normal
MouseProc = CallNextHookEx _
   (0, nCode, wParam, ByVal lParam)
End Function
' *** START OF MODULE CODE ***
DanS - 30 Jun 2007 02:57 GMT
>> The workaround I posted seems to work on limited testing but doesn't
>> seem to be an elegant solution . . .
[quoted text clipped - 65 lines]
> End Function
> ' *** START OF MODULE CODE ***

I was going to offer a mouse hook also, but since this was VBA under
AutoCAD, I wasn't sure of the implications since it's not just plain VB
that I'm used to using.

Anyway, the question is, in the above code, wouldn't it be better to not
use the LL hook, with a global scope, but instead just use a regular
mouse hook on the app threadID ?

Or is there some other reason maybe tied to VBA that you would use the LL
hook here ?

DanS
Mike Williams - 30 Jun 2007 06:09 GMT
> I was going to offer a mouse hook also, but since this was
> VBA under AutoCAD, I wasn't sure of the implications
> since it's not just plain VB that I'm used to using. Anyway,
> the question is, in the above code, wouldn't it be better to
> not use the LL hook, with a global scope, but instead just
> use a regular mouse hook on the app threadID ?

You're probably right. It's just that I wasn't quite sure exactly what the
OP was doing and I've never actually used VBA so I don't really know what is
involved there. I just thought I'd throw the LL Hook into the pot just in
case it was any use to him.

Mike
Ken Halter - 29 Jun 2007 15:40 GMT
GetKeyboardState may be a better option (if you don't go with the hook).
GetAsyncKeyState also tells you if something's been pressed since last call
(see MSDN). May be confusing for your purposes.
'===============
Option Explicit

Private Declare Function _
  GetKeyboardState Lib "user32" (pbKeyState As Byte) As Long

Private Function MouseIsDown() As Boolean
  Const VK_LBUTTON = &H1
  Dim b(255) As Byte
  Call GetKeyboardState(b(0))
  If b(VK_LBUTTON) > 127 Then 'Mouse is down
     MouseIsDown = True
  End If
End Function

Private Function RMouseIsDown() As Boolean
  Const VK_RBUTTON = &H2
  Dim b(255) As Byte
  Call GetKeyboardState(b(0))
  If b(VK_RBUTTON) > 127 Then 'RMouse is down
     RMouseIsDown = True
  End If
End Function

Private Sub Form_Load()
  With Timer1
     .Interval = 100
     .Enabled = True
  End With
End Sub

Private Sub Timer1_Timer()
  Me.Caption = "L-" & MouseIsDown & " R-" & RMouseIsDown
End Sub
'===============

This VB6 code needs a new project with an empty form. It'll build the form
and show the states of all keys and mouse buttons. It also shows that all
keys and buttons are "toggle" buttons, like CapsLock, etc.
'===================
Option Explicit

Private Declare Function _
  GetKeyboardState Lib "user32" (pbKeyState As Byte) As Long
Private WithEvents Timer1 As Timer
Private mobjLabels(255) As Label

Private Sub Form_Load()
  Dim i As Integer
  Dim j As Integer
  Dim iIndex As Integer
  Const STARTXY = 8

  Me.ScaleMode = vbPixels

  For i = 0 To 15
     For j = 0 To 15
     iIndex = i * 16 + j
     Set mobjLabels(iIndex) _
        = Controls.Add("VB.Label", "lbl" & iIndex)

     With mobjLabels(iIndex)
        .BorderStyle = 1
        .Move 30 * j + STARTXY, 21 * i + STARTXY, 26, 17
        .Caption = "00"
        .BackColor = vbButtonFace
        .Visible = True
        .ZOrder
     End With
     Next
  Next

  Set Timer1 = Controls.Add("VB.Timer", "WhoCares")
  With Timer1
     .Interval = 80
     .Enabled = True
  End With

  Me.Height = 400 * Screen.TwipsPerPixelY
  Me.Width = 500 * Screen.TwipsPerPixelX

End Sub

Private Sub Timer1_Timer()
  Dim btArray(255) As Byte
  Dim sList As String
  Dim i As Integer

  Call GetKeyboardState(btArray(0))

  For i = 0 To 255
     With mobjLabels(i)
        .Caption = Right$("0" & Hex$(btArray(i)), 2)
        Select Case btArray(i)
           Case 0
              .BackColor = vbButtonFace
           Case Is < 127
              .BackColor = vbGreen
           Case Else
              .BackColor = vbRed
              sList = sList & GetChar(i) & " "
        End Select
     End With
  Next

  Me.Caption = "Keys pressed now: " & sList

End Sub

Private Function GetChar(ByVal ByteIn As Byte) As String

  GetChar = Right$("0" & Hex$(ByteIn), 2)

  If ByteIn < 32 Or ByteIn > 127 Then
     ByteIn = 63 '="?"
  End If

  GetChar = GetChar & "(" & Chr$(ByteIn) & ")"

End Function
'===================

Signature

Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
In Loving Memory - http://www.vbsight.com/Remembrance.htm

 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.