The on-screen button to close the keyboard?

In the application, I use the on-screen keyboard (OSK) when it works on the tablet. We created a class called OSK that has a show and hide method.

When the user presses 'enter' on the on-screen keyboard, osk is hiding. The problem is that the user closes the OSK with the close button (x). OSK is hiding, but some things should change in the user interface when this happens.

Is there any way (event or something like that) to know when the user clicks the close button on OSK?

I will show the code that I used to show and hide OSK. The code shown is in Oxygene (but it is very similar to C #, I think)

First we have dllImports:

[DllImport("user32.dll", SetLastError := true)] class method PostMessage(hWnd: IntPtr; Msg: UInt32; wParam, lParam: IntPtr): Boolean; external; [DllImport("user32.dll", SetLastError := true)] class method FindWindow(lpClassName, lpWindowName: String): IntPtr; external; 

The show method has this code:

  using p := new Process do begin p.StartInfo.UseShellExecute := true; p.StartInfo.FileName := 'C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe'; p.Start(); end; 

In the Hide method, the following code is used to hide the OSK:

  var oskWindow := FindWindow("IPTip_Main_Window", nil); var WM_SYSCOMMAND := 274; var SC_CLOSE := 61536; PostMessage(oskWindow, WM_SYSCOMMAND, SC_CLOSE, 0); 

Update: Found a working solution for Windows 7 .... does not work for Windows 8 (What I need)

This is what I did to solve the problem on Windows 7: The main idea is that in the OSK class I run Dispatchertimer when osk is displayed. Now every second it checks to see if the splinter window is visible. If so, an event occurs that can be processed in several places. (I also check _firstshown boolean in the timer, because sometimes it takes some time for osk to appear.

Here's how I did it: first I made the dllImport of the IsWindowVisible method

 [DllImport("user32.dll", CharSet:=CharSet.Auto)] class method IsWindowVisible(hWnd:IntPtr):Boolean; external; 

In OSK.Show, I start the timer and set _firstShown to false (because it may take some time to display osk) Before that, I set the timer interval to 1 second and added eventhandlerf to timer.Tick:

  _timer.Interval := new TimeSpan(0,0,1); _timer.Tick += new EventHandler(_timer_Tick); 

This is the code in _timer_tick:

 class method OSK._timer_Tick(sender: Object; e: EventArgs); begin var oskWindow := FindWindow("IPTip_Main_Window", nil); var IsOSKOpen := IsWindowVisible(oskWindow); if not _firstShown then begin if IsOSKOpen then _firstShown := true; exit; end; if not IsOSKOpen then begin OSKClosed(nil,new EventArgs()); _timer.Stop(); _firstShown := false; end; end; 

It was a pleasure when it worked on my development machine (Windows 7), the joy was short-lived, because when I tested it on a tablet (window 8), it did not work. timer, etc. works great, it just looks like Windows 8 doesn’t process the iswindowVisible method.

Anyway all help is much appreciated

+6
source share
4 answers

Finally found a solution to my problem using the registry. Osk uses the UserClosed registry key. If the user closes osk, the user registry key will be one of them.

So, the first thing to do is set this registry key to 0 (override OnStartup in App.Xaml.cs)

  var regKeyUserClosed := Registry.CurrentUser.OpenSubKey("Software\Microsoft\TabletTip\1.7",true); regKeyUserClosed.SetValue("UserClosed",0); 

Now, when the application starts, the registry key is set to 0.

Now, when osk is called a timer, it starts and at each tick we need to see if the registry key is 1 (the user has closed OSK), if so, we fire the event, stop the timer and set the registry key back to 0.

This is my new timer_tick method:

  class method OSK._timer_Tick(sender: Object; e: EventArgs); begin var regKeyUserClosed := Registry.CurrentUser.OpenSubKey("Software\Microsoft\TabletTip\1.7",true); var UserClosed := Convert.ToInt32(regKeyUserClosed.GetValue("UserClosed")); if UserClosed.Equals(1) then begin OSKClosed(nil,new EventArgs()); _timer.Stop(); regKeyUserClosed.SetValue("UserClosed",0); end; end; 
+1
source

Honestly, I don't know Oxygene, but it looks like Pascal for .NET :)

Since your program launches OSK itself, you can simply subscribe to the Process.Exited event, which is raised when the user closes OSK.

So make p global variable and subscribe to Exited

 p.Exited += new EventHandler(_osk_Exited); class method OSK._osk_Exited(sender: Object; e: EventArgs); begin // will be called when OSK gets closed end; 

Also, I don't understand why you need FindWindow , can you use p.MainWindowHandle instead?

UPDATE2

The previous update did not work, but suddenly I thought: why not use the Microsoft Ink API instead of hacking?

Add the link to the Microsoft.Ink assembly to your project, you will need to go to the file, because it is not in the list by default (find microsoft.ink.dll under Program Files ).

Then create a TextInputPanel object for each input that the OSK needs:

 tip = new TextInputPanel(textBox1); tip.InPlaceVisibleOnFocus = true; tip.DefaultInPlaceState = InPlaceState.Expanded; 

Now the text input panel will be displayed when textBox1 gets focus and hides when it loses focus. You can even bind a handler to the InPlaceVisibilityChanged event if you are interested in when the user hides the panel:

 tip.InPlaceVisibilityChanged += tip_InPlaceVisibilityChanged; void tip_InPlaceVisibilityChanged(object sender, InPlaceVisibilityChangeEventArgs e) { // do something with e.Visible } 

If you are using WPF, you can use this method to get the HWND TextBox :

 HwndSource textHandle = (HwndSource)PresentationSource.FromVisual(wpfTextBox); tip = new TextInputPanel(); tip.AttachedEditWindow = textHandle.Handle; tip.InPlaceVisibleOnFocus = true; tip.DefaultInPlaceState = InPlaceState.Expanded; 
+2
source

you can start the timer when the osk process starts. On this timer you can check

var oskprocess = Process.GetProcessesByName ("osk");

When oskprocess.Length = 0

Then there is no Oscan race. Then you can stop the timer

0
source

Sometime ago I wrote code that used taskkill to complete osk.exe wont work in windows10 anymore, but when I wrote this, I think that I used windows8 it was done during processing (java), but that could help.

 launch(new String[] {"c:/Windows/system32/osk.exe" }); // OSK open launch(new String[] {"taskkill /IM osk.exe"}); // OSK close 
0
source

Source: https://habr.com/ru/post/948769/


All Articles