在应用程序中,我在平板电脑上运行时使用屏幕键盘(OSK)。 我们创建了一个名为OSK的类,它有一个show和hide方法。
当用户按下'输入'在屏幕键盘上,osk隐藏起来。问题是当用户使用关闭(x)按钮关闭OSK时。 OSK隐藏了,但是当发生这种情况时,有些事情需要在UI中进行更改。
有没有办法(一个事件或类似的东西)知道用户何时按下OSK上的关闭按钮?
我将展示一些用于显示和隐藏OSK的代码。 显示的代码在Oxygene中(但它看起来很像C#我认为)
首先我们有一些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;
在show方法中有以下代码:
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;
在Hide方法中,下一个代码用于隐藏OSK:
var oskWindow := FindWindow("IPTip_Main_Window", nil);
var WM_SYSCOMMAND := 274;
var SC_CLOSE := 61536;
PostMessage(oskWindow, WM_SYSCOMMAND, SC_CLOSE, 0);
更新: 找到了适用于Windows 7的工作解决方案....不适用于Windows 8(我需要什么)
这就是我在Windows 7中解决问题的方法: 主要的想法是,在OSK类中,我在显示osk时启动Dispatchertimer。现在,如果osk窗口可见,则检查每秒。如果是这样,则会触发一个可以在多个地方处理的事件。 (我还检查了计时器中的_firstshown布尔值,因为有时需要一段时间才能显示osk。
以下是我的表现方式: 首先我制作了一个IsWindowVisible方法的dllImport
[DllImport("user32.dll", CharSet:=CharSet.Auto)]
class method IsWindowVisible(hWnd:IntPtr):Boolean; external;
在OSK.Show我启动计时器并将_firstShown设置为false(因为它可能需要一段时间才能显示osk) 在此之前,我已经将计时器间隔设置为1秒,并将一个eventhandlerf添加到timer.Tick:
_timer.Interval := new TimeSpan(0,0,1);
_timer.Tick += new EventHandler(_timer_Tick);
这是_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;
当我在我的开发机器(Windows 7)上运行时,很高兴,因为当我在平板电脑(Windows 8)上测试它时,它的乐趣很短暂。计时器等工作正常,它看起来像Windows 8不处理iswindowVisible方法。
无论如何,非常感谢所有帮助
答案 0 :(得分:2)
老实说,我不知道Oxygene,但看起来像Pascal for .NET:)
由于您的程序启动了OSK本身,您只需订阅当用户关闭OSK时将调用的Process.Exited
事件。
因此,将p
设为全局变量并订阅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;
另外,我不明白为什么你需要FindWindow
,你不能使用p.MainWindowHandle
吗?
<强> UPDATE2 强>
以前的更新无效,但我突然想到:为什么不使用Microsoft的Ink API而不是黑客?
在项目中添加对Microsoft.Ink
程序集的引用,您需要浏览到该文件,因为默认情况下它不在列表中(在{{1}下搜索microsoft.ink.dll
})。
然后为每个需要OSK的输入创建一个TextInputPanel
对象:
Program Files
现在,文本输入面板将在tip = new TextInputPanel(textBox1);
tip.InPlaceVisibleOnFocus = true;
tip.DefaultInPlaceState = InPlaceState.Expanded;
获得焦点时显示,并在失去焦点时隐藏。如果您对用户隐藏面板感兴趣,您甚至可以将处理程序附加到textBox1
事件:
InPlaceVisibilityChanged
如果您使用的是WPF,则可以使用此方法获取tip.InPlaceVisibilityChanged += tip_InPlaceVisibilityChanged;
void tip_InPlaceVisibilityChanged(object sender, InPlaceVisibilityChangeEventArgs e)
{
// do something with e.Visible
}
的{{1}}:
HWND
答案 1 :(得分:2)
最后使用注册表找到了我的问题的解决方案。 osk使用名为UserClosed的注册表项。 如果用户关闭osk,则用户关闭的注册表项将为1。
所以要做的第一件事就是将此注册表项设置为0(在App.Xaml.cs中覆盖OnStartup)
var regKeyUserClosed := Registry.CurrentUser.OpenSubKey("Software\Microsoft\TabletTip\1.7",true);
regKeyUserClosed.SetValue("UserClosed",0);
现在,当应用程序启动时,注册表项设置为0.
现在当调用osk时,计时器启动并且在每个tick上我们需要查看注册表项是否为1(用户已关闭OSK),如果这样我们触发事件,停止计时器并设置注册表键到0。
这是我的新timer_tick方法:
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;
答案 2 :(得分:0)
你可以在进程启动osk时启动一个计时器。 在那个计时器上你可以检查
var oskprocess = Process.GetProcessesByName(&#34; osk&#34;);
当oskprocess.Length = 0时
然后没有运行的osk。 然后你可以停止计时器
答案 3 :(得分:0)
有时候我写了一些使用taskkill结束osk.exe的代码 不会再在windows10中工作但是当我写它时我觉得我在使用windows8 这是在处理(java)中完成的,但这可能有助于???
launch(new String[] {"c:/Windows/system32/osk.exe" }); // OSK open
launch(new String[] {"taskkill /IM osk.exe"}); // OSK close