2013-07-05 7 views
6

В приложении я использую экранную клавиатуру (OSK), когда она работает на планшете. Мы создали класс под названием OSK, который имеет метод show и hide.Экранная кнопка закрытия клавиатуры?

Когда пользователь нажимает «вводить» на экранную клавиатуру, скрывается оск. Проблема заключается в том, что пользователь закрывает OSK кнопкой закрытия (x). OSK скрывается, но некоторые вещи должны меняться в пользовательском интерфейсе, когда это происходит.

Есть ли способ (событие или что-то в этом роде) знать, когда пользователь нажимает кнопку закрытия на 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; 

в методе шоу есть этот код:

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); 

Обновление: Найдено рабочее решение для окон 7 .... не работает для Windows 8 (Что мне нужно)

Это то, что я сделал, чтобы решить эту проблему в Windows 7: Главный Идея заключается в том, что в классе OSK я запускаю Dispatchertimer, когда отображается osk. Теперь каждую секунду проверяется, видно ли осковое окно. Если это так, происходит событие, которое может быть обработано в нескольких местах. (Я также проверить _firstshown логическое значение в таймере, потому что иногда требуется некоторое время для OSK появляться

Вот как я сделал это:. первый я сделал DllImport из IsWindowVisible метода

[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), радость была недолговечной, потому что, когда я тестировал его на планшете (окна 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 - это встроенная функциональность для окон 7 и 8. Для этого вы должны использовать API Microsoft Ink. –

+0

Как вы это поняли ?! Я ищу очень похожие функции, но, к сожалению, это не сработало. – YasharBahman

+0

выяснил, что это решение имеет много проблем, работало здесь, но не в штатах и ​​еще много проблем. Мы еще не нашли правильного решения. Этот вопрос не является очень срочным, потому что сенсорные функции на данный момент являются низкими приоритетами. –

2

Честно говоря, я не знаю Oxygene, но это выглядит как Pascal для .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

Предыдущее обновление не работает, но я вдруг подумал: почему бы не использовать чернила API от Microsoft вместо взлома?

Добавить ссылку на Microsoft.Ink сборки вашего проекта, вам необходимо перейти к файлу, так как он не в списке по умолчанию (поиск microsoft.ink.dll под Program Files).

Затем создайте TextInputPanel объект для каждого входа, который нуждается в OSK:

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 вы можете использовать этот метод, чтобы получить HWND в TextBox:

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

Я не владеет системой Domotech :-) ... Я не могу использовать p.MainWindowHandle получает это исключение (не удается вызвать член экземпляра по типам) (все еще экспериментирует с выбывшим Event) –

+0

Я установите p.enableRaisingevents в true и избавитесь от используемого оператора вокруг p: = new Process. Теперь _osk_exited запускается сразу после метода show (не тогда, когда пользователь нажимает кнопку закрытия (x) на OSK. –

+0

Точнее, _osk_exited запускается после p.Start() –

0

вы можете запустить таймер, когда процесс запуска OSK. На этом таймере вы можете проверить

var oskprocess = Process.GetProcessesByName ("osk");

Когда oskprocess.Length = 0

Тогда нет OSK работает. Затем вы можете остановить таймер

0

некоторое время назад я написал код, который использовал Taskkill до конца osk.exe не будут работать в Windows 10 больше, но когда я писал это, я думаю, что я использовал Windows8 это было сделано в обработке (Java) но это может помочь?

launch(new String[] {"c:/Windows/system32/osk.exe" }); // OSK open 

launch(new String[] {"taskkill /IM osk.exe"}); // OSK close