CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    How to make a simple "On screen keyboard".

    This example needs a couple buttons.

    .NET
    Code:
        Const HC_ACTION As Int32 = 0
        Const HC_GETNEXT As Int32 = 1
        Const WM_LBUTTONDOWN As Int32 = 513
        Const WM_LBUTTONUP As Int32 = 514
        Const WM_RBUTTONDOWN As Int32 = 516
        Const WM_RBUTTONUP As Int32 = 517
        Const WM_MBUTTONDOWN As Int32 = 519
        Const WM_MBUTTONUP As Int32 = 520
        Const WM_MOUSEWHEEL As Int32 = 522
        Const WM_MOUSEMOVE As Int32 = 512
        Const WH_MOUSE_LL As Int32 = 14
        Const VK_CONTROL As Int32 = 17
        Const VK_MENU As Int32 = 18
        Const VK_ESCAPE As Int32 = 27
        Const KEYEVENTF_KEYUP As Int32 = 2
        Public Structure POINTAPI
            Public X, Y As Int32
        End Structure
        Private Structure MOUSEHOOKSTRUCT
            Public pt As POINTAPI
            Public hwnd, wHitTestCode, dwExtraInfo As Int32
        End Structure
        Private Structure MSLLHOOKSTRUCT
            Public pt As POINTAPI
            Public mouseData, flags, time, dwExtraInfo As Int32
        End Structure
    
        Private Declare Function apiSetWindowsMouseHookEx Lib "user32" _
        Alias "SetWindowsHookExA" _
        (ByVal idHook As Int32, _
        ByVal lpfn As MouseHookDelegate, _
        ByVal hmod As Int32, _
        ByVal dwThreadId As Int32) As Int32
        Private Declare Function apiUnhookWindowsHookEx Lib "user32" _
        Alias "UnhookWindowsHookEx" _
        (ByVal hHook As Int32) As Int32
        Private Declare Function apiCallNextMouseHookEx Lib "user32" _
        Alias "CallNextHookEx" _
        (ByVal hHook As Int32, _
        ByVal nCode As Int32, _
        ByVal wParam As Int32, _
        ByVal lParam As MOUSEHOOKSTRUCT) As Int32
        Private Delegate Function MouseHookDelegate _
        (ByVal nCode As Int32, _
        ByVal wParam As Int32, _
        ByRef lParam As MOUSEHOOKSTRUCT) As Int32
        Private mCallback As MouseHookDelegate
        Private MouseHandle, wfpWnd As Int32
        Private Declare Function apikeybd_event Lib "user32" _
        Alias "keybd_event" _
        (ByVal vKey As Int32, _
        ByVal bScan As Byte, _
        ByVal dwFlags As Int32, _
        ByVal dwExtraInfo As Int32) As Boolean
        Private Declare Function apiGetMessageExtraInfo Lib "user32" _
        Alias "GetMessageExtraInfo" () As Int32
        Private Declare Function apiGetCursorPos Lib "user32" Alias "GetCursorPos" (ByRef lpPoint As POINTAPI) As Boolean
        Private Declare Function apiWindowFromPoint Lib "user32" Alias "WindowFromPoint" (ByVal xyPoint As POINTAPI) As Int32
    
        Private Sub Form1_Load _
        (ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load
            MouseHook()
        End Sub
    
        Private Sub Form1_FormClosed _
        (ByVal sender As Object, _
        ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
            MouseUnHook()
        End Sub
    
        Private Function MouseStroke(ByRef hStruct As MOUSEHOOKSTRUCT, ByVal wParam As Int32) As Boolean
            On Error Resume Next
            If wParam = WM_LBUTTONDOWN Then
                wfpWnd = WindowFromPoint()
                If wfpWnd = Button1.Handle.ToInt32 Then
                    apikeybd_event(Keys.A, 0, 0, apiGetMessageExtraInfo)
                    apikeybd_event(Keys.A, 0, KEYEVENTF_KEYUP, apiGetMessageExtraInfo)
                    Return True
                ElseIf wfpWnd = Button2.Handle.ToInt32 Then
                    apikeybd_event(Keys.B, 0, 0, apiGetMessageExtraInfo)
                    apikeybd_event(Keys.B, 0, KEYEVENTF_KEYUP, apiGetMessageExtraInfo)
                    Return True
                End If
            ElseIf wParam = WM_LBUTTONUP Then
                '
            ElseIf wParam = WM_RBUTTONDOWN Then
                '
            ElseIf wParam = WM_RBUTTONUP Then
                '
            ElseIf wParam = WM_MOUSEMOVE Then
                '
            Else
                '
            End If
        End Function
    
        Private Function MouseCallback _
        (ByVal Code As Int32, ByVal wParam As Int32, ByRef lParam As MOUSEHOOKSTRUCT) As Int32
            On Error Resume Next
            If Code = HC_ACTION AndAlso MouseStroke(lParam, wParam) = True Then Return HC_GETNEXT
            Return apiCallNextMouseHookEx(MouseHandle, Code, wParam, lParam)
        End Function
    
        Private Function MouseHook() As Boolean
            On Error Resume Next
            mCallback = New MouseHookDelegate(AddressOf MouseCallback)
            MouseHandle = apiSetWindowsMouseHookEx _
            (WH_MOUSE_LL, mCallback, _
            Runtime.InteropServices.Marshal.GetHINSTANCE _
            (Reflection.Assembly.GetExecutingAssembly.GetModules()(0)) _
            .ToInt32, 0)
            Return CBool(MouseHandle)
        End Function
    
        Private Function MouseUnHook() As Boolean
            On Error Resume Next
            MouseHandle = apiUnhookWindowsHookEx(MouseHandle)
            Return Not CBool(MouseHandle)
        End Function
    
        Public Function WindowFromPoint() As Int32
            On Error Resume Next
            Dim ret As Int32, p As New POINTAPI
            If apiGetCursorPos(p) = False Then Return 0
            WindowFromPoint = apiWindowFromPoint(p)
        End Function

    VB6
    Code:
    Option Explicit
    Const HC_ACTION As Long = 0
    Const HC_GETNEXT As Long = 1
    Const WH_MOUSE_LL As Long = 14
    Const WM_LBUTTONDOWN As Long = 513
    Const WM_LBUTTONUP As Long = 514
    Const WM_RBUTTONDOWN As Long = 516
    Const WM_RBUTTONUP As Long = 517
    Const WM_MOUSEMOVE As Long = 512
    Const VK_CONTROL As Int32 = 17
    Const VK_MENU As Int32 = 18
    Const VK_ESCAPE As Int32 = 27
    Const KEYEVENTF_KEYUP As Int32 = 2
    Private Type POINTAPI
        X As Long
        Y As Long
    End Type
    Private Type MOUSEHOOKSTRUCT
        pt As POINTAPI
        hWnd As Long
        wHitTestCode As Long
        dwExtraInfo As Long
    End Type
    Private Declare Function apiCallNextMouseHookEx Lib "user32" Alias "CallNextHookEx" _
    (ByVal hHook As Long, _
    ByVal nCode As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long
    Private Declare Function apiCopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (ByRef pDest As MOUSEHOOKSTRUCT, _
    ByVal pSource As Long, _
    ByVal cb As Long) As Long
    Private Declare Function apiSetWindowsMouseHookEx Lib "user32" Alias "SetWindowsHookExA" _
    (ByVal idHook As Long, _
    ByVal mHookDel As Long, _
    ByVal hmod As Long, _
    ByVal dwThreadId As Long) As Long
    Private Declare Function apiUnhookWindowsHookEx Lib "user32" Alias "UnhookWindowsHookEx" _
    (ByVal hHook As Long) As Long
    Private phwnd As Long
    Private MouseHandle As Long
    Private Declare Function apikeybd_event Lib "user32" Alias "keybd_event" _
    (ByVal vKey As Long, _
    ByVal bScan As Byte, _
    ByVal dwFlags As Long, _
    ByVal dwExtraInfo As Long) As Boolean
    Private Declare Function apiGetMessageExtraInfo Lib "user32" Alias "GetMessageExtraInfo" _
    () As Long
    
    
    
    Public Function HookIt() As Boolean
        On Error Resume Next
        MouseHandle = apiSetWindowsMouseHookEx _
        (WH_MOUSE_LL, AddressOf MouseCallback, App.hInstance, 0)
    End Function
    
    Public Function UnHookIt() As Boolean
        On Error Resume Next
        MouseHandle = apiUnhookWindowsHookEx(MouseHandle)
    End Function
    
    Public Function MouseCallback _
    (ByVal Code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        On Error Resume Next
        Static hStruct As MOUSEHOOKSTRUCT
        Call apiCopyMemory(hStruct, lParam, Len(hStruct))
        If Code = HC_ACTION Then
            If wParam = WM_LBUTTONDOWN Then
                phwnd = WindowFromPoint
    
                If phwnd = frmOSK.Command1.hWnd Then
                    apikeybd_event(Keys.A, 0, 0, apiGetMessageExtraInfo)
                    apikeybd_event(Keys.A, 0, KEYEVENTF_KEYUP, apiGetMessageExtraInfo)
                    MouseCallback = HC_GETNEXT
                    Exit Function
                ElseIf phwnd = frmOSK.Command2.hWnd Then
                    apikeybd_event(Keys.B, 0, 0, apiGetMessageExtraInfo)
                    apikeybd_event(Keys.B, 0, KEYEVENTF_KEYUP, apiGetMessageExtraInfo)
                    MouseCallback = HC_GETNEXT
                    Exit Function
                Else
                    '
                End If
    
            ElseIf wParam = WM_LBUTTONUP Then
            '
            ElseIf wParam = WM_RBUTTONDOWN Then
            '
            ElseIf wParam = WM_RBUTTONUP Then
            '
            End If
        End If
        MouseCallback = apiCallNextMouseHookEx _
        (MouseHandle, Code, wParam, lParam)
    End Function
    Last edited by TT(n); June 17th, 2010 at 03:45 PM. Reason: update

  2. #2
    Join Date
    Jul 2006
    Location
    At home
    Posts
    70

    Re: How to make a simple "On screen keyboard".

    Do you have a question? Not sure I understand what it is that you're asking but here are some suggestions anyway.

    I notice tho that your sub for button 4 is redundant as the event handler for button 3 would do the exact same (you could modify the button 3 MouseDown event handler to read

    Code:
     Private Sub Button3_MouseDown(ByVal sender As Object, ByVal e As _ 
    System.Windows.Forms.MouseEventArgs) Handles Button3.MouseDown, Button4.MouseDown
    Or you could cut your code down to a complete minimum by creating all the button controls programmatically & then processing their events. The code below does pretty much that,

    Code:
    Option Strict On
    Public Class Form1
        Dim btn As New Button
    
        Private Sub Form1_Load(ByVal sender As Object, _ 
    ByVal e As System.EventArgs) Handles Me.Load
            For Each btn In Me.pnlButtons.Controls
                AddHandler btn.Click, AddressOf btn_Click
            Next
        End Sub
    
        Private Sub btn_Click(ByVal sender As Object,  _ 
    ByVal e As System.EventArgs)
            lblText.Text = lblText.Text & CType(sender, Button).Text
        End Sub
    End Class
    You could include module level boolean variables to flag whether a modifier key was pressed and also add processing to the form KeyUp event (provided the forms KeyPreview property is set to True) instead of using an API call.

    Does that help at all?

  3. #3
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    Re: How to make a simple "On screen keyboard".

    If you didn't notice, the title to the thread is:
    "How to...". No question really.

    I'm making a list of examples to place in my signature.
    There's not much of a need for an elaborate example here, I'm just illustrating the use of key combinations, to return the original foreground window. Clean, simple and pretty reliable.

    Does that help at all?
    Not really but thanks anyway.

  4. #4
    Join Date
    Jul 2006
    Location
    At home
    Posts
    70

    Re: How to make a simple "On screen keyboard".

    Quote Originally Posted by TT(n)
    If you didn't notice, the title to the thread is:
    "How to...". No question really.
    I did notice but I'm so used to broken English online that I thought there was a question. I'm sure you've seen questions of the type "How to fill a dataset?" or "How to open a Crystal Report?" or "How to consume COM object?" - I thought this was another of those.

    I have a few questions for you though (if you don't mind) - why are you using an API call for keyboard events when .NET provides you with this already? Are you trying to trap a specific event?

    Why are you posting this in a forum? This could make for good article material. A published article would be far more valuable to you than a few forum threads.

    Why are you using redundant code in your example? There are "cleaner" ways of accomplishing the creation of an onscreen keyboard. If you're using this as a base of examples for your signature shouldn't you provide the best possible code that you know how to write? Or have I missed something in your code that doesn't allow you use delegates? I know you write good code which is why this has me so perplexed.

    Please - don't misinterpret this, I'm genuinely curious.

  5. #5
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    Re: How to make a simple "On screen keyboard".

    I hope your not one of those sticklers, when it comes to English.
    ...always correcting spelling and grammer etc.. lol
    Some questions do start with How to... but usually end with a question mark. I see the confusion, although this is a dead give away:
    This example uses the Alt + Escape combo to return keyboard focus to the previous application. Meant at face value.
    I hadn't seen any good provisions from .NET for keyboard events.
    Show me.
    Generally I prefer API, because they are true, tried and tested.
    That doesn't mean I'm not open to putting up the best, or most elegant example possible, that novice-intermediate readers can still grasp.
    I am an intermediate BTW.

    I might write up an article, when things are more polished.
    Input from others is helpful, so please forgive me If I sounded dismissive.


    Hmmm... as I've told you this was an example so it wasn't really redundant to repeat the "L" key. The reader would automatically know(as you should and did) that each button would go to a different key. Actually It was just easier for me to copy and past the whole event, and then change the letter. I spent most of the time working on the return foregroundwindow part. The important part of the example.

    Please enlighten me, and post updates to the code here.
    My earlier post, looks like I dont appreciate your attempts.



Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured