繁体   English   中英

屏幕键盘关闭按钮事件?

[英]On Screen Keyboard close button event?

在应用程序中,我在平板电脑上运行时使用屏幕键盘(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秒并向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方法。

无论如何所有的帮助非常感谢

说实话,我不知道Oxygene,但看起来像Pascal for .NET :)

由于您的程序启动了OSK本身,您只需订阅Process.Exited事件,该事件将在用户关闭OSK时调用。

因此,将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程序集的引用添加到项目中,您需要浏览到该文件,因为默认情况下它不在列表中(在Program Files下搜索microsoft.ink.dll )。

然后为需要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;

最后使用注册表找到了我的问题的解决方案。 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时,计时器启动并在每个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;

你可以在进程启动osk时启动一个计时器。 在那个计时器上你可以检查

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

当oskprocess.Length = 0时

然后没有运行的osk。 然后你可以停止计时器

有时回来我编写的代码使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM