Thursday, March 5, 2015

Windows OSK inside our Form

Have shared earlier an embedding technique of a 3rd-party app called Virtual Keyboard with codes of  Vilhelm-lon Praisach (with his permission) because while I don't need it, others who used to frequent my blog may.

But since I wanted to find out also how to embed the nasty elusive built-in On-Screen Keyboard (OSK) of Windows which yesterday gave me a lot of frustration as surprisingly it is harder to control than said Free Virtual Keyboard, gleaming new codes from Vilhelm I decided to renew my failed attempts on how it can be done.  Sometimes though when I do try to control things I do not need yet like this one, in the midst of it I wish I should have simply banged my head on the table; for again it seems I am unnecessarily stressing myself  on something I myself do not need nor use (yet).

Anyhow, while finding ways like this sometimes makes my blood pressure go up due to frustrations, in the end when I find a way, I felt a bit of contentment as that is another understanding (to an extent) of these somewhat elusive WinAPIs.   I have yet fully understood these things and just relies on my observations and trials and errors; but I think I am slowly getting there.

After adopting some technique and codes used by Vilhelm I am able to successfully embed OSK within our form under XP OS.  However, trying the same codes inside Windows 7 renews my frustration as said OS does not respect the settings I have done earlier.

Finally, here are the codes that work on both XP and Windows 7 (32-bit, I do not have 64-bit to test it to):

* OSK inside VFP Form XP/Win 7 32-bit

Declare Integer FindWindow In user32;
      STRING lpClassName, String lpWindowName

Declare Integer GetWindowLong In User32 Integer HWndInteger nIndex

Declare Integer ShellExecute In shell32.Dll ;
      INTEGER hndWin, ;
      STRING cAction, ;
      STRING cFileName, ;
      STRING cParams, ;
      STRING cDir, ;
      INTEGER nShowWin

Declare Integer SetWindowLong In user32 Integer HWnd,;
      INTEGER nIndex, Integer dwNewLong

Declare Integer SetWindowPos In user32;
      INTEGER HWnd,;
      INTEGER hWndInsertAfter,;
      INTEGER x,;
      INTEGER Y,;
      INTEGER cx,;
      INTEGER cy,;
      INTEGER uFlags

Declare Integer SetParent In user32;
      INTEGER hWndChild,;
      INTEGER hWndNewParent

Declare Integer SetFocus In user32 Integer

Clear

Public oForm
oForm = Createobject('form1')
oForm.Show()

Define Class form1 As Form
      Height = 400
      Width = 900
      Caption = "OSK Inside VFP Form"
      Desktop = .T.
      AutoCenter = .T.

      Add Object text1 As TextBox With;
            top = 20, Left = 10, Width = 100, Height = 28

      Add Object tmr As Timer With Interval = 100

      Procedure KeyPress
            Lparameters nKeyCode, nCtrlShift
            If nKeyCode = 27
                  Thisform.Release
            Endif
      Endproc

      Procedure Load
            ShellExecute(0,'open','osk.exe','','',1)
      Endproc

      Procedure tmr.Timer
            Local nOSKHeight
            nOSKHeight = 250  && initial OSK height
            nHwnd = FindWindow(Null,'On-Screen Keyboard')
            lnStyle = GetWindowLong(m.nHwnd, -16)
            SetWindowLong (m.nHwnd, -16, Bitset(m.lnStyle,30))  && remove menu
            SetWindowLong(m.nHwnd, -16, Bitxor(m.lnStyle, 0xCF0000))
           
            * In Windows7, OSK is not positioned properly until you do this first and do another below later
            SetWindowPos(m.nHwnd, 0, 0, Thisform.Height-m.nOSKHeight,Thisform.Width, m.nOSKHeight,  0x0020)
           
            SetParent(m.nHwnd,Thisform.HWnd)
            SetWindowPos(m.nHwnd, 0, 0, Thisform.Height-m.nOSKHeight,Thisform.Width+10, m.nOSKHeight,  0x0020)
            This.Enabled = .F.
            SetFocus(Thisform.HWnd)
      Endproc
Enddefine

Some difference in attitude:

  • on XP, it can be resized on-the-ply; on Window 7 it is fixed size
  • on XP  version of OSK,  there is no word suggestion; while on Windows 7 there is 
Here are images showing the difference in appearance and attitude on both OS mentioned:






Afterthought:

If you noticed on the final SetWindowPos, I added 10.  That is because Windows 7 has thicker border than XP and that is used to counter or compensate for the thickness difference.  You can perform an OS() function to determine whether that extra 10 can be added or not.   

Hope this and Vilhelm's will help you on your on screen keyboard needs.  Cheers!


2 comments:

  1. Excellent solution!
    You overestimated my contribution :-)

    ReplyDelete
    Replies
    1. Oh no! Without your codes on the SetWindowLong flags on FreeVK, I do not think I will be able to work on OSK easy. Your post on FreeVK and this one will give them some options what to use.

      Delete