3

After launching osk.exe with ShellExecuteEx() I would like to position the keyboard window relative to the data-entry fields, so that it doesn't cover them.

How do I set the window position for the osk before calling it?

Also, how can I have the application hide the osk when I am finished?

mghie
  • 32,028
  • 6
  • 87
  • 129

2 Answers2

6

You can use FindWindow using the window class "OSKMainClass" to get the window handle, and then SetWindowPos on that handle to position it to the coordinates you want. (You may need to use the control's ClientToScreen method to convert to the proper coordinates, but I'll let you figure that part out.)

// Off the top of my head - not at a machine that has a Delphi compiler at
// the moment.
var
  OSKWnd: HWnd;
begin
  OSKWnd := FindWindow(PChar('OSKMainClass'), nil);
  if OSKWnd <> 0 then
  begin
    SetWindowPos(OSKWnd, 
                 HWND_BOTTOM, 
                 NewPos.Left, 
                 NewPos.Top, 
                 NewPos.Width,
                 NewPos.Height, 
                 0);
  end;
end;

Code taken in part from a CodeProject article related to the same topic. I got the window class using AutoHotKey's Window Spy utility.

Notes:

  1. Remy Lebeau points out in a comment that you should make sure to use CreateProcess() or ShellExecuteEx() so that you get back a process handle that can then be passed to WaitForInputIdle() before calling FindWindow(). Otherwise the call to FindWindow() may happen before OSK creates the window.

  2. mghie points out in a comment that the only way he could get this to work was by running the app as Administrator; otherwise the call to SetWindowPos() resulted in an "Access Denied (5)".

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 2
    You should also use `CreateProcess()` or `ShellExecuteEx()` instead of `ShellExecute()` so that you are given a process `HANDLE` that you can pass to `WaitForInputIdle()` before calling `FindWindow()`. Otherwise you might call it before OSK creates its window. – Remy Lebeau Jul 12 '14 at 04:03
  • HWND_TOPMOST and SWP_NOZORDER are contradictory – David Heffernan Jul 12 '14 at 11:53
  • @David: Thanks. My error transcribing from the linked project. Corrected. – Ken White Jul 12 '14 at 15:58
  • On my system (Windows 7 64 bit) this code does not cause any change to the osk window. – mghie Jul 12 '14 at 16:22
  • @mghie: What coordinates did you use for the new position? (As I indicated, I haven't had a chance to test the code; I ported it from a CodeProject article (that I linked), which was done in C#.) – Ken White Jul 12 '14 at 16:33
  • @mghie: Also, did you see Remy's comment about WaitForInputIdle()? My code doesn't make any effort to start OSK, as the poster says they've already done that using ShellExecuteEx. – Ken White Jul 12 '14 at 16:40
  • I started osk manually, so the window was visible. The `HWND` was correctly read, and I used `GetWindowRect()`, then `OffsetRect(-50, -50)`, then `SetWindowPos()`, but without any visible effect. The comment by Hans Passant on question http://stackoverflow.com/questions/5608393/how-can-i-programmatically-manipulate-the-windows-7-on-screen-keyboard-osk-move?rq=1 makes me wonder whether it is even possible using this code. BTW, there is a missing `end` for your procedure. – mghie Jul 12 '14 at 18:53
  • @mghie: Thanks for the info on the end; as I've mentioned, I wasn't in front of a compiler when I wrote it. I looked at the comment by Hans that you mention, but I think that refers to changing styles and borders of the OSK, not changing its position. (Being able to move it would appear to be necessary at times to prevent obscuring the UI.) – Ken White Jul 12 '14 at 18:59
  • I've tried some more, and found that I have to start the program as Administrator for it to work, otherwise the `SetWindowPos()` fails with error 5 (access denied). +1 for your answer, but the permission issue may be worth pointing out. – mghie Jul 12 '14 at 19:55
  • OSK is a very special program with extreme power. Hardly surprising that it is secured. – David Heffernan Jul 12 '14 at 20:00
  • @Ken `SWP_NOZORDER` means "ignore `hWndInsertAfter`" and so it might just be better to pass `0`. But it makes no difference to behaviour of course. This is a side show and I'll shut up now. – David Heffernan Jul 12 '14 at 20:01
  • 1
    @KenWhite Thanks Ken and others. The OSK seems to be oblivious to any of my SetWindowPos settings. The Top/etc seems to be ignored as the OSK appears where it wants and at a fixed size. Also, I looked at the CodeProject trying to find a way to hide the OSK but nothing has worked yet, including NoActivate. –  Jul 13 '14 at 17:44
  • 1
    @user2175495: Why do you accept this if it doesn't solve your problem? – mghie Jul 14 '14 at 03:48
1

I can,t move the window as mentioned above. Using Win32 commands, SetWindow or MoveWindow not worked for on screen keyboard. Its worked only while running exe in admin privilege.

I think its not a good solution. I found another solution. Please go through this. After trying using registry values its worked well i can move on screen keyboard in my application

try

                               {

                               RegistryKey myKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Osk", true);

                               myKey.SetValue("WindowLeft", oskLeft, RegistryValueKind.DWord);
                               myKey.SetValue("WindowTop", oskTop, RegistryValueKind.DWord);


                               }

                               catch

                               {

                                        //Log the error
                               }