3

I have been trying to get the onscreen keyboard (osk.exe) to appear (and disappear) on Windows 10 from within my app. My app was running fine in windows 7. Calling ShellExecute() on osk.exe would show the keyboard there but trying to get the same behaviour in Windows 10 has proved to be a pain.

To try to hide the keyboard, once it is visible, I tried this:

HANDLE wHandle = FindWindowW(L"OSKMainClass", L"On-Screen Keyboard");
if (wHandle != NULL)
{
    long style = GetWindowLong(wHandle, GWL_STYLE);
    if (style & WS_VISIBLE)
    {
        return TRUE;
    }
    else
    {
        SetWindowLongPtr(wHandle, GWL_STYLE, WS_VISIBLE);
    }

but that had no effect.

I also tried using the TabTip keyboard but was unable to detect when it is visible (I can detect when it's not visible but I can't get a handle to it when it is visible!).

Any help with this problem would be appreciated.

Update: The reason osk wasn't initially been shown was the 'nCmdShowparameter supplied toShellExecute`, the original code supplied NULL for this value and it was working fine on Windows 7 so I had assumed the problem lay elseware. changing it from NULL to SW_SHOWNORMAL fixed the issue with the keyboard appearing.

Comment by Paul Sanders: In a 32 bit app you have to do one more thing, see, see: https://stackoverflow.com/a/50510526/5743288.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
stuicidle
  • 297
  • 1
  • 8
  • 4
    `style &= WS_VISIBLE` is an assignment. It will always be true. If you want to test, use `if (style & WS_VISIBLE)...` – Paul Ogilvie May 18 '18 at 12:19
  • style &= WS_VISIBLE does not always return true, the if statement is working as intended – stuicidle May 18 '18 at 13:25
  • `style &= WS_VISIBLE` means `style = style & WS_VISIBLE; if (style)...`. You are right that it works, however, you canot use `style` anymore as it now only has the visible bit (or not even that). – Paul Ogilvie May 18 '18 at 13:31
  • @Paul Oglivie, You are correct, this is legacy code and I didn't fully appreciate this was clearing the style value thanks :) – stuicidle May 18 '18 at 13:53
  • This question has a terrible title. It should be something like 'How do I show and hide the onscreen keyboard in Windows 10?'. Please try to say what you mean. Look at all the trouble it has caused. – Paul Sanders May 18 '18 at 21:37
  • Running "osk.exe" works reliably for me to show the on-screen keyboard on Windows 10, even when it is already running minimized. To close it, `PostMessage(FindWindowW(L"OSKMainClass", nullptr), WM_SYSCOMMAND, SC_CLOSE, 0)` does the trick. You should elaborate what "has proved to be a pain" means. – zett42 May 20 '18 at 15:49

3 Answers3

4

I have decided to rewrite this answer, because the original contained a lot of irrelevant details, most of which were wrong. Now that I understand properly how it all actually works there's a lot less to say, and what there is to say should be a lot more useful to future visitors.

First up, the answer to the OP's question is here. That should let him do exactly what he wants to do. Kudos to @zett42 for pointing out the WM_SYSCOMMAND trick. Now for the interesting stuff.

Question 1: why does posting a WM_SYSCOMMAND message to osks main window work when calling ShowWindow(), as the OP was trying to do, does not?

Answer: Well, putting aside the fact that hiding the OSK rather than closing or minimising it is probably not a good idea anyway, the answer lies in something called UI Privilege Level Isolation (UIPI). OSK runs elevated and this limits the ways it can be manipulated by a regular app. You can read more about UIPI here.

For future reference, you can figure out if a program is running elevated using SysInternals' Process Explorer. If you look in the Security tab of the Process Properties window, then for OSK you see:

Flags: Integrity Group: Mandatory Label\ High Mandatory Label

while for (e.g.) the Settings app, you see:

Flags: Integrity Group: Mandatory Label\ Medium Mandatory Label

Question 2: Is any of this affected by the fact that OSK is a UWP app (see comments below by @IInspectable)?

Answer: Actually, no. The top-level HWND's of UWP apps appear to be just regular HWND's, although Microsoft don't want you to rely on that. You can investigate the exact window hierarchy they use - what there is of it - with Spy++ (and use the 64 bit version, lol).

Asides:

  1. OP, please try to write better questions. This one was a bit of a mess and it has caused a lot of trouble. I have edited your question by way of example and to clean it up for future visitors, please take a look. And please vote me up. I have earned it.

  2. People posting replies: please do a bit of research first. The other answers in this thread are not useful, partly (I would be the first to admit) because of the way the question was originally worded. I myself made this mistake in my initial comments so we can all learn from this.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • [I brought this process into the world, and I can take it out!](https://blogs.msdn.microsoft.com/oldnewthing/20120924-00/?p=6523). `WM_SYS­COMMAND` is the key. – zett42 May 20 '18 at 15:57
  • @zett42: excellent, well done. I nearly tried that but it was late and I was tired and I talked myself out of it. Serves me right. I have edited my 'answer' appropriately. – Paul Sanders May 20 '18 at 16:46
  • Question posted at https://stackoverflow.com/questions/50437413/why-cant-spy-see-messages-sent-to-uwp-apps, if anyone's interested. – Paul Sanders May 20 '18 at 17:10
2

You can use IsWindowVisible function from WinAPI to determine if your hwnd is a visible window or not. Have you tried that? Checking and managing flags directly for such simple task is not the best idea

https://msdn.microsoft.com/en-us/library/windows/desktop/ms633530(v=vs.85).aspx

Marcin
  • 77
  • 8
  • `IsWindowVisible` is the same as retrieveing the bit from the style (it is what Windows does under the hood of this function). – Paul Ogilvie May 18 '18 at 12:26
  • And that's why we shouldn't reinvent the weel :) But you're right, I said that this can have different results, but it shouldn't - will edit my post. – Marcin May 18 '18 at 12:29
  • 1
    @PaulOgilvie: Not quite. IsWindowVisible also checks the visibility of the parent windows, as [documented](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633530%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396). So testing the style bit might be warranted in some cases (although probably not here). – Paul Sanders May 18 '18 at 12:55
  • I don't need to determine if the window is visible, I want to make it visible if it is not currently visible. The if statement is working fine and when I try to get a handle of the TabTip keyboard window, it fails when its visible so I can't then call IsWindowVisible – stuicidle May 18 '18 at 13:28
  • @stuicidle are you sure that keyboard you see and can not detect by your code is exactly the one you search for? Maybe window class for visible keyboard is different. Do some play with Inspect app (brilliant tool for exploring UI structure on Windows) https://msdn.microsoft.com/pl-pl/library/windows/desktop/dd318521(v=vs.85).aspx – Marcin May 18 '18 at 13:32
  • I used Spy++ to find the correct class etc for the keyboard window then used "FindWindowW(L"Windows.UI.Core.CoreWindow", L"Microsoft Text Input Application");" but this didn't return a handle when the keyboard was visible only when it was hidden – stuicidle May 18 '18 at 13:48
  • `IsWindowVisible` works with `HWND`s. The Windows 10 on-screen keyboard doesn't have a `HWND` associated with it (for display purposes anyway), as explained in the question. This is the correct answer, to a different question. – IInspectable May 18 '18 at 13:49
0

You are making a few errors:

  • in your if you use an assignment in stead of a test

  • in your SetWindowLongPtr you set only one bit and all existing flags are lost. You should use:

       long style = GetWindowLong(wHandle, GWL_STYLE);
        if (style & WS_VISIBLE) // test
        {
            return TRUE;
        }
        else
        {
            style |= WS_VISIBLE; // set the bit
            SetWindowLongPtr(wHandle, GWL_STYLE, style); // set the new style
            ShowWindow(wHandle, SW_SHOWDEFAULT);
        }
    

Note: The windows documentation says you must call SetWindowPos, not ShowWindow.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • And setting the style bit is a bit pointless if you're going to be showing the window anyway... The original code, as posted, is a bit confused. – Paul Sanders May 18 '18 at 12:57
  • 1
    Still wrong, it must be `style |= WS_VISIBLE`. Though as previous poster wrote, it's pointless anyway. – zett42 May 18 '18 at 13:16
  • I have also tried a call to SetWindowPos "SetWindowPos(wHandle, NULL, 0, 0, 100, 100, SWP_DRAWFRAME);" but this had no effect – stuicidle May 18 '18 at 13:56
  • 1
    Actually (IInspectable's comment above notwithstanding), there's no need to test anything, just show the window. If it's already visible, this does nothing. And you don't need to twiddle the style bits people!! So the code should simply be (if we had a valid HWND, which apparently we don't): `ShowWindow (wHandle, SW_SHOW);` Honestly. – Paul Sanders May 18 '18 at 15:07
  • @PaulSanders: The Windows 10 on-screen keyboard is a UWP application. UWP application visibility is *not* controlled through the associated `HWND`. Unfortunately, Microsoft have not yet thoroughly documented, what role `HWND`s play in UWP applications. I believe they are limited to input handling, as well as to serve as targets for broadcast messages. But not much more. – IInspectable May 18 '18 at 16:34
  • @IInspectable: Yes, thanks, I did get that (the gist of it, anyway). My comment was more about the code that people were posting to make a window visible when one _does_ have an HWND available. I just couldn't stand the way everyone was going all round the houses. At some point (not sure when), I will make an effort to educate myself about UWP apps. Even if I don't like them, they're not going to go away. – Paul Sanders May 18 '18 at 17:08
  • @PaulSanders: Once you do make sure to have a look at [Introduction to C++/WinRT](https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/intro-to-using-cpp-with-winrt). It's the Windows Runtime projection C++ developers have been waiting for. – IInspectable May 18 '18 at 17:19
  • @IInspectable: OK, thank you. I will do some background reading when I have the time, need to keep up and all that. – Paul Sanders May 18 '18 at 18:14