내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2020-07-10 04:25

제목

[WPF] On Screen Keyboard Helper in WPF


On Screen Keyboard Helper in WPF


안녕하세요. 김대욱입니다. 최근들어 터치스크린을 이용한 프로젝트를 자주 진행하다보니 이번 포스팅은 터치스크린을 이용하는 시스템에서 유용하게 사용될 수 있는 내용이 되겠습니다. 이번시간에 소개해 드릴 내용은 터치스크린을 사용하는 어플리케이션에서 TextBox등의 Control에 Focus 되었을때 자동으로 Screen Keyboard Application을 실행하는 예제입니다. 동영상을 보시면 쉽게 이해하실수 있습니다.



위 동영상에서는 WIndows에서 기본적으로 제공하는 OnScreenKeyboard를 사용했지만, 이번시간에 소개해 드릴 내용을 응용하면 직접 개발한 Keyboard Application을 사용하실 수도 있습니다. 간단하게 원리를 말씀드리자면 입력가능한 컨트롤 즉, TextBox나 PasswordBox에 Focus 되었을때 미리 지정해놓은 Keyboard Application을 실행하고 Focus를 잃었을때 Keyboard Application을 닫는 원리가 되겠습니다.

컨트롤 하나하나 일일이 Focus이벤트 코드를 추가하는 방법을 사용할수도 있겠지만, 이번시간에 소개해 드릴방법은 Attached DependencyProperty를 사용하여 간단하게 Screen Keyboard를 지원하도록 구현했습니다. 사용할때에는 아래와 같이 사용할 수 있습니다.

  1. <!--StackPanel의 자식 Control 전부가 ScreenKeyboard를 지원하도록 합니다.-->  
  2. <StackPanel osk:OSKHelper.IsSurpportScreenKeyboard="True">  
  3.     <TextBox/>  
  4.     <TextBox/>  
  5.     <PasswordBox />  
  6. </StackPanel>  
  7.   
  8. <!--StackPanel의 자식 Control 일부가 ScreenKeyboard를 지원하도록 합니다.-->  
  9. <StackPanel osk:OSKHelper.IsSurpportScreenKeyboard="True">  
  10.     <TextBox/>  
  11.     <TextBox osk:OSKHelper.IsSurpportScreenKeyboard="False"/>  
  12.     <PasswordBox />  
  13. </StackPanel>  
  14.   
  15. <!-- Control 하나하나에 ScreenKeyboard 지원여부를 결정합니다.-->  
  16. <StackPanel >  
  17.     <TextBox osk:OSKHelper.IsSurpportScreenKeyboard="True"/>  
  18.     <TextBox osk:OSKHelper.IsSurpportScreenKeyboard="False"/>  
  19.     <PasswordBox osk:OSKHelper.IsSurpportScreenKeyboard="True"/>  
  20. </StackPanel>  

아래는 Attached DependencyProperty를 구현한 소스코드입니다.

  1. public static class OSKHelper  
  2. {  
  3.   
  4.     // Target Control에 Focus 되었을 경우 실행할 Keyboard Application  
  5.     public static string ScreenKeyboardFile = "osk.exe";  
  6.     public static Process ScreenKeyboardInstance = null;  
  7.   
  8.     // Target Control의 Focus이벤트를 처리하는 EventHandler  
  9.     private static RoutedEventHandler FocusEventHandler = new RoutedEventHandler(FocusHandler);  
  10.   
  11.     // Attached DependencyProperty선언 부분  
  12.     public static readonly DependencyProperty IsSurpportScreenKeyboardProperty =  
  13.         DependencyProperty.RegisterAttached("IsSurpportScreenKeyboard"typeof(bool?),   
  14.         typeof(OSKHelper),   
  15.         new FrameworkPropertyMetadata(nullnew PropertyChangedCallback(IsSurpportScreenKeyboardChanged)));  
  16.   
  17.     public static bool GetIsSurpportScreenKeyboard(FrameworkElement Target)  
  18.     {              
  19.         return (bool)Target.GetValue(IsSurpportScreenKeyboardProperty);  
  20.     }  
  21.   
  22.     public static void SetIsSurpportScreenKeyboard(FrameworkElement Target, bool? Value)  
  23.     {  
  24.         Target.SetValue(IsSurpportScreenKeyboardProperty, Value);  
  25.     }  
  26.   
  27.     // Target Control의 IsSurpportScreenKeyboard Property가 변경되었을때 처리  
  28.     public static void IsSurpportScreenKeyboardChanged(DependencyObject Sender, DependencyPropertyChangedEventArgs e)     
  29.     {  
  30.         FrameworkElement Target = Sender as FrameworkElement;  
  31.   
  32.         // IsSurpportScreenKeyboard Property가 True라면 EventHandler를 추가.  
  33.         if ((bool)e.NewValue )  
  34.         {  
  35.             Target.GotFocus += FocusEventHandler;  
  36.             Target.LostFocus += FocusEventHandler;  
  37.         }  
  38.         // IsSurpportScreenKeyboard Property가 True가 아니고, EventHandler를 추가되었었다면  
  39.         // Event Handler를 제거  
  40.         else if (FocusEventHandler.GetInvocationList().First().Target == Target)  
  41.         {  
  42.             Target.GotFocus -= FocusEventHandler;  
  43.             Target.LostFocus -= FocusEventHandler;      
  44.         }     
  45.     }  
  46.   
  47.   
  48.     static void FocusHandler(object sender, RoutedEventArgs e)  
  49.     {  
  50.         FrameworkElement Target = sender as FrameworkElement;  
  51.         FrameworkElement Source = e.Source as FrameworkElement;  
  52.   
  53.         // IsSurpportScreenKeyboard Property가 False인데 EventHandler가 등록되었다면, 제거  
  54.         if ((bool?)Target.GetValue(IsSurpportScreenKeyboardProperty) == false)  
  55.         {  
  56.             Target.GotFocus -= FocusEventHandler;  
  57.             Target.GotFocus -= FocusEventHandler;  
  58.             return;  
  59.         }  
  60.         // IsSurpportScreenKeyboard Property가 False가 아니고 RoutedEvent가 GotFocus이며,  
  61.         // Source Control이 TextBox이거나 PasswordBox일때 Keyboard Application를 실행  
  62.         else if ((bool?)Source.GetValue(IsSurpportScreenKeyboardProperty) != false &&  
  63.             e.RoutedEvent == FocusManager.GotFocusEvent && (e.Source is TextBox || e.Source is PasswordBox))  
  64.         {  
  65.             ScreenKeyboardInstance = Process.Start(ScreenKeyboardFile);  
  66.         }  
  67.         // RoutedEvent가 LostFocus이고 ScreenKeyboard Application이 생성되어 있다면 종료,  
  68.         else if (e.RoutedEvent == FocusManager.LostFocusEvent && ScreenKeyboardInstance != null)  
  69.         {  
  70.             if (ScreenKeyboardInstance.HasExited == false)  
  71.                 ScreenKeyboardInstance.CloseMainWindow();  
  72.             ScreenKeyboardInstance = null;  
  73.         }  
  74.   
  75.     }    
  76.   
  77. }  

동작원리는 위에서 설명드린것과 동일하며 Attached Dependency Property를 이해하고 있다면, 어렵지 않게 이해하실수 있을것 같습니다 ^^

출처1

http://wpfkorea.tistory.com/category/WPF

출처2