簡體   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