In an application I am using an onscreen keyboard(OSK) for when it is running on a tablet. We've made a class called OSK which has a show and hide method.
When the user presses 'enter' on the onscreen keyboard, the osk hides. The problem is when the user closes the OSK with the close (x) button. The OSK hides, but some things need to change in the UI when this happens.
Is there a way (an event or something like that) to know when the user pushes the close button on the OSK?
I'll show some of the code I"ve used for showing and hiding the OSK. The code shown is in Oxygene (but it looks a lot like C# I think)
First we've have some 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;
In the show method there is 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 next 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....not working for windows 8 (What i need)
This is what i did to solve the problem in windows 7: The main idea is that in the OSK class i start a Dispatchertimer when the osk is shown. Now every second is checked if the osk window is visible. If so an event is fired which can be handled in several places. (I also check a _firstshown boolean in the timer because it sometimes takes a while for the osk to appear.
Here's how I did that: first i made a 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 can take a while for the osk to appear) Before this i've set the timer interval on 1 second and added an 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;
There was pleasure when this worked on my development machine (windows 7), the joy was shortlived because when i tested it on the tablet (windows 8) it didn't work. the timer etc works fine, it just looks like windows 8 doesn't handle the iswindowVisible method.
Anyway all help is very much appreciated
To be honest, I don't know Oxygene, but it looks like Pascal for .NET :)
Since your program starts the OSK itself, you can just subscribe to the Process.Exited
event which will be called when the user closes the OSK.
So, make p
a 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 see why you need FindWindow
, can't you use p.MainWindowHandle
instead?
UPDATE2
Previous update didn't work, but suddenly I thought: why not use Microsoft's Ink API instead of hacking?
Add a reference to the Microsoft.Ink
assembly to your project, you'll need to browse to the file, because it is not in the list by default (search for microsoft.ink.dll
under Program Files
).
Then create a TextInputPanel
object for each input that needs the OSK:
tip = new TextInputPanel(textBox1);
tip.InPlaceVisibleOnFocus = true;
tip.DefaultInPlaceState = InPlaceState.Expanded;
Now, the text input panel will show up when textBox1
gets focus and hide when it loses focus. You can even attach a handler to the InPlaceVisibilityChanged
event if you're 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're using WPF you can use this method to get the HWND
of the TextBox
:
HwndSource textHandle = (HwndSource)PresentationSource.FromVisual(wpfTextBox);
tip = new TextInputPanel();
tip.AttachedEditWindow = textHandle.Handle;
tip.InPlaceVisibleOnFocus = true;
tip.DefaultInPlaceState = InPlaceState.Expanded;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With