2013-07-05 176 views
6

在应用程序中,我正在使用屏幕键盘(OSK)在平板电脑上运行它。 我们做了一个叫做OSK的类,它有一个显示和隐藏方法。屏幕键盘关闭按钮事件?

当用户在屏幕键盘上按下'enter'时,osk隐藏。问题是当用户用close(x)按钮关闭OSK时。 OSK隐藏,但发生这种情况时,UI中需要更改一些内容。

有没有一种方法(一个事件或类似的东西)知道用户何时按下OSK上的关闭按钮?

我将展示一些代码I“已经用于显示和隐藏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; 

在展示方法有以下代码:

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; 

在隐藏方法的下一个代码被用来隐藏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秒,并向timer.Tick添加了一个eventhandlerf:

_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方法。

反正所有的帮助是非常赞赏

回答

1

终于找到使用注册表我的问题的解决方案。 osk使用一个名为UserClosed的注册表键。 如果用户关闭了osk,则用户关闭的注册表项将是一个。

所以,我们要做的第一件事就是到这个注册表键值设置为0(在App.Xaml.cs覆盖OnStartup)

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

现在注册表项设置为0时,应用程序启动。

现在,当osk被调用时,计时器开始并在每个时钟周期中,我们需要查看注册表键是否为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; 
+0

因为osk是Windows 7和Windows 8的内置功能,所以您不需要使用所有这些黑客技巧。您应该使用Microsoft Ink API。 –

+0

你怎么解决这个问题?我正在寻找非常类似的功能,但不幸的是,这不起作用。 – YasharBahman

+0

发现这个解决方案有很多问题,在这里工作,但没有在州和更多的问题。我们还没有找到合适的解决方案。这个问题在这里并不是很紧急,因为触摸功能现在是低优先级的。 –

2

说实话,我不知道OXYGENE,但它看起来像帕斯卡尔.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

上更新没有工作,但突然我想:为什么不使用微软的油墨API,而不是黑客的?

添加到Microsoft.Ink集的引用到你的项目,你需要浏览到该文件,因为它不是在列表中的默认(搜索microsoft.ink.dllProgram Files下)。

然后为需要的OSK每个输入创建一个TextInputPanel对象:

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

现在,文本输入面板会显示当textBox1获得焦点和隐藏,当它失去焦点。你甚至可以附加一个处理程序的InPlaceVisibilityChanged事件如果你有兴趣,当用户隐藏面板:

tip.InPlaceVisibilityChanged += tip_InPlaceVisibilityChanged; 

void tip_InPlaceVisibilityChanged(object sender, InPlaceVisibilityChangeEventArgs e) 
{ 
    // do something with e.Visible 
} 

如果你使用WPF,你可以用这个方法来获取TextBoxHWND

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

我不拥有Domotech系统:-) ......我不能使用p.MainWindowHandle得到这个异常(不能调用类型的实例成员)(AM仍与退出事件实验) –

+0

我已经将p.enableRaisingevents设置为true,然后摆脱p:= new Process中的using语句。现在_osk_exited在show方法之后立即触发(不是当用户按下OSK上的(x)关闭按钮时)。 –

+0

更确切地说,_osk_exited在p.Start()后触发() –

0

就可以启动一个定时器,当过程开始OSK。 在该计时器上,您可以检查

var oskprocess = Process.GetProcessesByName(“osk”);

当oskprocess.Length = 0

那就没有OSK运行。 然后你就可以停止计时器

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