[소프트웨어 접근성] 가상 키보드 만들기 8 - 가상 키보드 만들기
윈도우즈 폼 응용 프로젝트를 추가한 후에 키보드 이벤트와 마우스 이벤트 처리를 위한 WrapNative 클래스를 추가하세요. 이 부분은 앞에서 설명한 부분이라 별도의 설명은 생략할게요. 아래의 소스 코드를 참고하세요.
using System; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Threading; namespace DemoKeyEvent { [Flags] public enum KeyFlag{ KE_DOWN = 0, KE__EXTENDEDKEY=1, KE_UP = 2 } static class WrapNative { static Mutex mu = new Mutex(); const int IME_CMODE_NATIVE = 0x1; [DllImport("imm32.dll")] static extern int ImmGetContext(int hWnd); [DllImport("imm32.dll")] static extern int ImmReleaseContext(int hWnd, int hImc); [DllImport("imm32.dll")] static extern int ImmGetConversionStatus(int hImc, out int fdwConversion, out int fdwSentence); [DllImport("imm32.dll")] static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence); public static bool IsNativeMode(int handle) { int hImc, dwConversion = 0, dwSentense = 0; hImc = ImmGetContext(handle); ImmGetConversionStatus(hImc, out dwConversion, out dwSentense); return (dwConversion & IME_CMODE_NATIVE) == 1; } [DllImport("user32.dll")] private static extern int GetKeyboardState(byte[] pbKeyState); [DllImport("User32.dll")] static extern void keybd_event(byte vk, byte scan, int flags, int extra); public static void KeyDown(Keys keycode) { mu.WaitOne(); keybd_event((byte)keycode,0,(int)(KeyFlag.KE_DOWN|KeyFlag.KE__EXTENDEDKEY),0); mu.ReleaseMutex(); } public static void KeyUp(Keys keycode) { mu.WaitOne(); keybd_event((byte)keycode, 0, (int)(KeyFlag.KE_UP|KeyFlag.KE__EXTENDEDKEY), 0); mu.ReleaseMutex(); } public static void KeyClick(Keys keycode,bool shift) { mu.WaitOne(); if (shift) { keybd_event((byte)Keys.ShiftKey,0, (int)(KeyFlag.KE_DOWN|KeyFlag.KE__EXTENDEDKEY),0); keybd_event((byte)keycode, 0, (int)(KeyFlag.KE_DOWN | KeyFlag.KE__EXTENDEDKEY), 0); keybd_event((byte)keycode, 0, (int)(KeyFlag.KE_UP | KeyFlag.KE__EXTENDEDKEY), 0); keybd_event((byte)Keys.ShiftKey, 0, (int)(KeyFlag.KE_UP | KeyFlag.KE__EXTENDEDKEY), 0); } else { keybd_event((byte)keycode, 0, (int)(KeyFlag.KE_DOWN | KeyFlag.KE__EXTENDEDKEY), 0); keybd_event((byte)keycode, 0, (int)(KeyFlag.KE_UP | KeyFlag.KE__EXTENDEDKEY), 0); } mu.ReleaseMutex(); } public static bool IsPress(Keys keycode) { byte[] vks = new byte[256]; GetKeyboardState(vks); return vks[(int)keycode] == 1; } } } |
[소스] WrapNative.cs
이번 작업에서는 논리적인 처리외에도 키보드 인터페이스 부분이 있어서 과도한 중복 작업이 존재합니다. 먼저 폼의 자식 컨트롤을 배치하세요.
[그림] 가상 키보드 폼의 자식 컨트롤 배치
다음은 자식 컨트롤에 배치한 컨트롤 형식과 컨트롤 이름입니다. 그림에는 보이지 않지만 좌측 상단에 정보를 표시할 레이블(Label lb_text)을 하나 배치하세요.
Button btn_toggle_ime; 한/영 변환
Button btn_esc; Esc
Button btn_f1; F1
Button btn_f2; F2
Button btn_f3; F3
Button btn_f4; F4
Button btn_f5; F5
Button btn_f6; F6
Button btn_f7; F7
Button btn_f8; F8
Button btn_f9; F9
Button btn_f10; F10
Button btn_f11; F11
Button btn_f12; F12
Button btn_equal; =
Button btn_dash; -
Button btn_0; 0
Button btn_9; 9
Button btn_8; 8
Button btn_7; 7
Button btn_6; 6
Button btn_5; 5
Button btn_4; 4
Button btn_3; 3
Button btn_2; 2
Button btn_1; 1
Button btn_fpu; ` (ESC 밑)
Button btn_bs; \
Button btn_barrow; <-
Button btn_enter; Enter
Button btn_postb; ]
Button btn_preb; [
Button btn_p; p
Button btn_o; o
Button btn_i; i
Button btn_u; u
Button btn_y; y
Button btn_t; t
Button btn_r; r
Button btn_e; e
Button btn_w; w
Button btn_q; q
Button btn_tab; Tab
Button btn_upper; '(Enter 옆)
Button btn_semi; ;
Button btn_l; l
Button btn_k; k
Button btn_j; j
Button btn_h; h
Button btn_g; g
Button btn_f; f
Button btn_d; d
Button btn_s; s
Button btn_a; a
Button btn_caps; Caps
Button btn_slush; /
Button btn_dot; .
Button btn_comma; ,
Button btn_m; m
Button btn_n; n
Button btn_b; b
Button btn_v; v
Button btn_c; c
Button btn_x; x
Button btn_z; z
Button btn_shift; Shift
Button btn_space; Space
Button btn_alt; Alt
Button btn_ctrl; Ctrl
ListBox lbox_event;
CheckBox cb_cabs;
CheckBox cb_with_shift;
Label lb_text; (좌측 상단에 레이블을 배치하세요.)
이제 폼의 코드를 작성합시다. 먼저 현재 쉬프트 키를 눌렀는지 확인할 수 있는 멤버 필드를 선언하세요.
bool is_press_shift;
한글 모드인지 확인할 수 있는 멤버 필드를 선언하세요.
bool check;
자동화 요소의 초점 변경 이벤트 개체를 기억할 멤버를 선언하세요.
AutomationFocusChangedEventHandler afceh;
현재 초점을 소유한 자동화 요소 개체와 값 패턴의 개체를 기억할 멤버를 선언합니다.
AutomationElement target_ae;
ValuePattern target;
한글 개체를 기억할 멤버도 선업합니다.
Hangul hangul;
폼의 Load 이벤트 핸들러를 추가하세요.
private void MainForm_Load(object sender, EventArgs e)
{
초점 변경 이벤트 핸들러를 생성하여 등록합니다.
afceh = new AutomationFocusChangedEventHandler(FocusChanged);
Automation.AddAutomationFocusChangedEventHandler(afceh);
}
private void FocusChanged(object sender, AutomationFocusChangedEventArgs e)
{
초점이 바뀌었을 때 AutomationElement 클래스의 정적 멤버인 FocusedElement를 이용하여 초점을 소유한 자동화 요소 개체를 참조합니다.
AutomationElement ae = AutomationElement.FocusedElement;
만약 멤버 필드로 기억하고 있는 타겟 요소와 같으면 이벤트 처리기를 끝냅니다.
if (ae == target_ae){ return; }
만약 초점을 소유한 개체의 프로세스 ID가 현재 프로세스 ID와 같을 때도 이벤트 처리기를 끝냅니다.
if (ae.Current.ProcessId == Process.GetCurrentProcess().Id){ return; }
자동화 요소 개체가 활성화 상태인지 확인합니다.
if (ae.Current.IsEnabled)
{
활성화 상태이면 Value 패턴인지 확인합니다.
object obj;
if (ae.TryGetCurrentPattern(ValuePattern.Pattern, out obj))
{
Value 패턴이면 타겟을 설정합니다. 이 부분은 크로스 스레드 문제가 발생할 수 있으므로 별도의 메서드를 만들게요.
SetTarget(ae, obj);
}
Value 패턴이 아니면 타겟 자동화 요소와 타겟 Value 패턴을 null로 설정합니다.
else{ target_ae = null; target = null; }
}
활성화 상태가 아니면 타겟 자동화 요소와 타겟 Value 패턴을 null로 설정합니다.
else{ target_ae = null; target = null; }
}
SetTarget 메서드를 정의합시다. 이 부분에서는 크로스 스레드 문제가 발생할 수 있어서 이를 처리하기 위한 대리자를 정의합니다.
delegate void SetTargetDele(AutomationElement ae,object obj);
private void SetTarget(AutomationElement ae,object obj)
{
수행하고 있는 스레드가 폼을 소유하는 스레드인지 확인합니다.
if(this.InvokeRequired)
{
만약 폼을 소유하는 스레드가 아니면 Invoke 메서드를 호출하여 .NET 프레임워크를 통해 폼을 소유한 스레드가 SetTarget 메서드를 호출할 수 있게 합니다.
this.Invoke(new SetTargetDele(SetTarget),new object[]{ae,obj});
}
else
{
전달받은 타겟을 Value 패턴으로 참조 연산합니다.
target = obj as ValuePattern;
타겟 자동화 개체도 설정합니다.
target_ae = ae;
새로운 타겟을 설정하였으니 해당 개체에 한글 처리를 위한 한글 개체를 생성합니다.
hangul = new Hangul();
타겟의 값을 가져와 한글 개체의 Text 속성에 설정합니다.
hangul.Text = target.Current.Value;
정보를 표시할 레이블의 Text 속성도 설정합니다.
lb_text.Text = hangul.Text;
래핑한 API 정적 클래스 WrapNative의 IsPress 메서드를 호출하여 CapsLock 버튼을 누른 상태인지 얻어와서 cb_cabs의 Checked 속성을 설정합니다.
cb_cabs.Checked = WrapNative.IsPress(Keys.CapsLock);
이에 따라 키보드 UI 부분을 설정합니다. 이 부분은 ButtonSet 메서드로 구현합시다.
ButtonSet();
이벤트 정보를 표시할 리스트 박스에 항목을 추가합니다.
lbox_event.Items.Add(ae.Current.Name);
}
}
키보드 버튼 상태에 따라 키보드 UI를 설정하는 ButtonSet 메서드를 정의합시다. 이 부분은 특별한 연산은 없지만 많은 키의 Text 속성을 설정하므로 작업량이 많습니다.
private void ButtonSet()
{
if (is_press_shift)
{
쉬프트 키를 눌렀을 때 버튼의 Text 속성을 설정합시다.
btn_fpu.Text = "~"; btn_1.Text = "!"; btn_2.Text = "@";
btn_3.Text = "#"; btn_4.Text = "$"; btn_5.Text = "%";
btn_6.Text = "^"; btn_7.Text = "&&"; btn_8.Text = "*";
btn_9.Text = "("; btn_0.Text = ")"; btn_dash.Text = "_";
btn_equal.Text = "+"; btn_bs.Text = "|"; btn_preb.Text = "{";
btn_postb.Text = "}"; btn_semi.Text = ":"; btn_upper.Text = "\"";
btn_comma.Text = "<"; btn_dot.Text = ">"; btn_slush.Text = "?";
}
else
{
쉬프트 키를 누르지 않을 때의 버튼 Text 속성을 설정합시다.
btn_fpu.Text = "`"; btn_1.Text = "1"; btn_2.Text = "2";
btn_3.Text = "3"; btn_4.Text = "4"; btn_5.Text = "5";
btn_6.Text = "6"; btn_7.Text = "7"; btn_8.Text = "8";
btn_9.Text = "9"; btn_0.Text = "0"; btn_dash.Text = "-";
btn_equal.Text = "="; btn_bs.Text = "\\";
btn_preb.Text = "["; btn_postb.Text = "]";
btn_semi.Text = ";"; btn_upper.Text = "'";
btn_comma.Text = ","; btn_dot.Text = ".";
btn_slush.Text = "/";
}
한글 모드인지 여부에 따라서 키보드 UI를 설정하는 부분도 필요합니다.
if (check)
{
if (is_press_shift)
{
한글 모드에서 쉬프트 키를 눌렀을 때의 버튼 Text 속성을 설정하세요.
btn_q.Text = "ㅃ"; btn_w.Text = "ㅉ"; btn_e.Text = "ㄸ";
btn_r.Text = "ㄲ"; btn_t.Text = "ㅆ"; btn_o.Text = "ㅒ";
btn_p.Text = "ㅖ";
}
else
{
한글 모드에서 쉬프트 키를 누르지 않았을 때의 버튼 Text 속성을 설정하세요.
btn_q.Text = "ㅂ"; btn_w.Text = "ㅈ"; btn_e.Text = "ㄷ";
btn_r.Text = "ㄱ"; btn_t.Text = "ㅅ"; btn_o.Text = "ㅐ";
btn_p.Text = "ㅔ";
}
한글 모드에서 쉬프트 키에 관계없는 버튼의 Text 속성을 설정하세요.
btn_y.Text = "ㅛ"; btn_u.Text = "ㅕ"; btn_i.Text = "ㅑ";
btn_a.Text = "ㅁ"; btn_s.Text = "ㄴ"; btn_d.Text = "ㅇ";
btn_f.Text = "ㄹ"; btn_g.Text = "ㅎ"; btn_h.Text = "ㅗ";
btn_j.Text = "ㅓ"; btn_k.Text = "ㅏ"; btn_l.Text = "ㅣ";
btn_z.Text = "ㅋ"; btn_x.Text = "ㅌ"; btn_c.Text = "ㅊ";
btn_v.Text = "ㅍ"; btn_b.Text = "ㅠ"; btn_n.Text = "ㅜ";
btn_m.Text = "ㅡ";
}
else
{
한글 모드가 아닐 때의 처리입니다.
if (is_press_shift ^ cb_cabs.Checked)
{
쉬프트 키를 눌렀거나 CapsLock이 눌렀거나 둘 중에 하나가 참일 때의 처리입니다.
btn_q.Text = "Q"; btn_w.Text = "W"; btn_e.Text = "E";
btn_r.Text = "R"; btn_t.Text = "T"; btn_y.Text = "Y";
btn_u.Text = "U"; btn_i.Text = "I"; btn_o.Text = "O";
btn_p.Text = "P"; btn_a.Text = "A"; btn_s.Text = "S";
btn_d.Text = "D"; btn_f.Text = "F"; btn_g.Text = "G";
btn_h.Text = "H"; btn_j.Text = "J"; btn_k.Text = "K";
btn_l.Text = "L"; btn_z.Text = "Z"; btn_x.Text = "X";
btn_c.Text = "C"; btn_v.Text = "V"; btn_b.Text = "B";
btn_n.Text = "N"; btn_m.Text = "M";
}
else
{
쉬프트 키를 누르고 CapsLock도 눌러진 상태이거나 둘 다 누른 상태가 아닐 때의 처리입니다.
btn_q.Text = "q"; btn_w.Text = "w"; btn_e.Text = "e";
btn_r.Text = "r"; btn_t.Text = "t"; btn_y.Text = "y";
btn_u.Text = "u"; btn_i.Text = "i"; btn_o.Text = "o";
btn_p.Text = "p"; btn_a.Text = "a"; btn_s.Text = "s";
btn_d.Text = "d"; btn_f.Text = "f"; btn_g.Text = "g";
btn_h.Text = "h"; btn_j.Text = "j"; btn_k.Text = "k";
btn_l.Text = "l"; btn_z.Text = "z"; btn_x.Text = "x";
btn_c.Text = "c"; btn_v.Text = "v"; btn_b.Text = "b";
btn_n.Text = "n"; btn_m.Text = "m";
}
}
}
cb_cabs 체크 박스의 체크 상태 변경 이벤트 핸들러를 등록하세요.
private void cb_cabs_CheckedChanged(object sender, EventArgs e)
{
체크 상태에 따라 체크 박스의 배경 색을 다르게 지정하여 쉽게 알 수 있게 합시다.
if (cb_cabs.Checked){ cb_cabs.BackColor = Color.YellowGreen; }
else{ cb_cabs.BackColor = SystemColors.Control; }
}
cb_with_shift 체크 박스의 체크 상태 변경 이벤트 핸들러를 등록하세요.
private void cb_with_shift_CheckedChanged(object sender, EventArgs e)
{
is_press_shift에 현재 체크 상태로 설정하고 키보드 버튼의 UI 정보를 설정합니다.
is_press_shift = cb_with_shift.Checked;
ButtonSet();
}
폼의 FormClosed 이벤트 핸들러를 등록합니다.
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
{
폼 Load할 때 등록했던 초점 변경 이벤트 핸들러를 해제합니다.
Automation.RemoveAutomationFocusChangedEventHandler(afceh);
}
모든 버튼의 클릭 이벤트는 Button_Click으로 추가하세요.
private void Button_Click(object sender, EventArgs e)
{
먼저 어느 버튼인지 sender를 Button 형식으로 참조합니다.
Button btn = sender as Button;
만약 값 패턴 개체인 target이 존재하는지 확인합니다.
if (target != null)
{
target이 존재하면 타겟에 초점을 설정합니다.
target_ae.SetFocus();
내부 처리 속도로 SetFocus를 호출해도 바로 초점을 잡지 않아 약간의 시간을 지연합니다.
Thread.Sleep(10);
}
이제 버튼에 따라 처리를 합니다.
switch (btn.Text)
{
다음은 래핑한 API 정적 클래스인 WrapNative의 KeyClick 메서드를 호출하여 프로그램 방식으로 키 이벤트를 발생할 키에 관한 처리입니다.
case "Esc": WrapNative.KeyClick(Keys.Escape, is_press_shift); break;
case "F1": WrapNative.KeyClick(Keys.F1, is_press_shift); break;
case "F2": WrapNative.KeyClick(Keys.F2, is_press_shift); break;
case "F3": WrapNative.KeyClick(Keys.F3, is_press_shift); break;
case "F4": WrapNative.KeyClick(Keys.F4, is_press_shift); break;
case "F5": WrapNative.KeyClick(Keys.F5, is_press_shift); break;
case "F6": WrapNative.KeyClick(Keys.F6, is_press_shift); break;
case "F7": WrapNative.KeyClick(Keys.F7, is_press_shift); break;
case "F8": WrapNative.KeyClick(Keys.F8, is_press_shift); break;
case "F9": WrapNative.KeyClick(Keys.F9, is_press_shift); break;
case "F10": WrapNative.KeyClick(Keys.F10, is_press_shift); break;
case "F11": WrapNative.KeyClick(Keys.F11, is_press_shift); break;
case "F12": WrapNative.KeyClick(Keys.F12, is_press_shift); break;
case "Tab": WrapNative.KeyClick(Keys.Tab, is_press_shift); break;
case "Shift": WrapNative.KeyClick(Keys.ShiftKey, is_press_shift); break;
case "Enter": WrapNative.KeyClick(Keys.Enter, is_press_shift); break;
case "Caps": WrapNative.KeyClick(Keys.CapsLock, is_press_shift);
캡션 키를 눌렀을 때는 체크 박스의 체크 상태를 토글합니다.
cb_cabs.Checked ^= true;
캡션에 따라 키보드 UI 인터페이스의 내용이 바뀌어야 하므로 ButtonSet 메서드를 호출합니다.
ButtonSet(); break;
case "Ctrl": WrapNative.KeyClick(Keys.ControlKey, is_press_shift); break;
case "Alt": WrapNative.KeyClick(Keys.Alt, is_press_shift); break;
case "한/영 변환":
한/영 변환 버튼을 눌렀을 때도 한글 모드를 기억하는 check 멤버를 토클합니다.
check ^= true;
그리고 키보드 UI 인터페이스의 내용을 바꾸어야 하므로 ButtonSet 메서드를 호출합니다.
ButtonSet(); break;
Space 버튼을 누렀을 때는 별도의 메서드를 통해 문자를 누른 것처럼 처리할 PressKey 메서드를 이용하여 처리할게요.
case "Space": PressKey(' '); break;
<- 버튼을 눌렀을 때도 PressKey 메서드를 호출합시다.
case "<-": PressKey('\b'); break;
나머지 키는 버튼의 Text 속성의 첫번째 문자를 인자로 PressKey 메서드를 호출합니다.
default: PressKey(btn.Text[0]); break;
}
키보드 이벤트를 보여줄 리스트 박스에 항목을 추가합니다.
lbox_event.Items.Add(btn.Text);
그리고 추가한 항목을 화면에 보일 수 있게 선택 항목으로 설정합니다.
lbox_event.SelectedIndex = lbox_event.Items.Count - 1;
래핑한 API 정적 클래스 WrapNative의 KeyClick 메서드를 이용해 End 키를 누른 이벤트를 발생합니다. 이를 통해 캐럿이 맨 뒤로 이동합니다.
WrapNative.KeyClick(Keys.End,is_press_shift);
}
private void PressKey(char ch)
{
만약 타겟 개체가 없으면 메서드를 종료합니다.
if (target == null){ return; }
만약 한글 모드이면 hangul 개체의 Input 메서드를 호출합니다.
if (check){ hangul.Input(ch); }
그렇지 않다면 한글 개체의 InputNoKorea 메서드를 호출합니다.
else{ hangul.InputNoKorea(ch); }
정보를 표시할 레이블의 Text 속성을 한글의 Text 속성으로 설정합니다.
lb_text.Text = hangul.Text;
Value 패턴인 타겟의 SetValue 메서드를 이용하여 한글의 Text 속성으로 설정합니다.
target.SetValue(hangul.Text);
}
using System; using System.Drawing; using System.Windows.Forms; using System.Threading; using EHHangulLibrary; using System.Windows.Automation; using System.Collections.Generic; using System.Diagnostics;
namespace DemoKeyEvent { public partial class Form1 : Form { bool is_press_shift; bool check;
AutomationFocusChangedEventHandler afceh; AutomationElement target_ae; ValuePattern target; Hangul hangul;
public Form1() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { afceh = new AutomationFocusChangedEventHandler(FocusChanged); Automation.AddAutomationFocusChangedEventHandler(afceh); } private void FocusChanged(object sender, AutomationFocusChangedEventArgs e) { AutomationElement ae = AutomationElement.FocusedElement; if (ae == target_ae){ return; } if (ae.Current.ProcessId == Process.GetCurrentProcess().Id) { return; } if (ae.Current.IsEnabled) { object obj; if (ae.TryGetCurrentPattern(ValuePattern.Pattern, out obj)) { SetTarget(ae, obj); } else { target_ae = null; target = null; } } else { target_ae = null; target = null; } } delegate void SetTargetDele(AutomationElement ae, object obj); private void SetTarget(AutomationElement ae, object obj) { if (this.InvokeRequired) { this.Invoke(new SetTargetDele(SetTarget), new object[] { ae, obj }); } else { target = obj as ValuePattern; target_ae = ae; hangul = new Hangul(); hangul.Text = target.Current.Value; lb_text.Text = hangul.Text; cb_cabs.Checked = WrapNative.IsPress(Keys.CapsLock); ButtonSet(); lbox_event.Items.Add(ae.Current.Name); } } private void ButtonSet() { if (is_press_shift) { btn_fpu.Text = "~"; btn_1.Text = "!"; btn_2.Text = "@"; btn_3.Text = "#"; btn_4.Text = "$"; btn_5.Text = "%"; btn_6.Text = "^"; btn_7.Text = "&&"; btn_8.Text = "*"; btn_9.Text = "("; btn_0.Text = ")"; btn_dash.Text = "_"; btn_equal.Text = "+"; btn_bs.Text = "|"; btn_preb.Text = "{"; btn_postb.Text = "}"; btn_semi.Text = ":"; btn_upper.Text = "\""; btn_comma.Text = "<"; btn_dot.Text = ">"; btn_slush.Text = "?"; } else { btn_fpu.Text = "`"; btn_1.Text = "1"; btn_2.Text = "2"; btn_3.Text = "3"; btn_4.Text = "4"; btn_5.Text = "5"; btn_6.Text = "6"; btn_7.Text = "7"; btn_8.Text = "8"; btn_9.Text = "9"; btn_0.Text = "0"; btn_dash.Text = "-"; btn_equal.Text = "="; btn_bs.Text = "\\"; btn_preb.Text = "["; btn_postb.Text = "]"; btn_semi.Text = ";"; btn_upper.Text = "'"; btn_comma.Text = ","; btn_dot.Text = "."; btn_slush.Text = "/"; } if (check) { if (is_press_shift) { btn_q.Text = "ㅃ"; btn_w.Text = "ㅉ"; btn_e.Text = "ㄸ"; btn_r.Text = "ㄲ"; btn_t.Text = "ㅆ"; btn_o.Text = "ㅒ"; btn_p.Text = "ㅖ"; } else { btn_q.Text = "ㅂ"; btn_w.Text = "ㅈ"; btn_e.Text = "ㄷ"; btn_r.Text = "ㄱ"; btn_t.Text = "ㅅ"; btn_o.Text = "ㅐ"; btn_p.Text = "ㅔ"; } btn_y.Text = "ㅛ"; btn_u.Text = "ㅕ"; btn_i.Text = "ㅑ"; btn_a.Text = "ㅁ"; btn_s.Text = "ㄴ"; btn_d.Text = "ㅇ"; btn_f.Text = "ㄹ"; btn_g.Text = "ㅎ"; btn_h.Text = "ㅗ"; btn_j.Text = "ㅓ"; btn_k.Text = "ㅏ"; btn_l.Text = "ㅣ"; btn_z.Text = "ㅋ"; btn_x.Text = "ㅌ"; btn_c.Text = "ㅊ"; btn_v.Text = "ㅍ"; btn_b.Text = "ㅠ"; btn_n.Text = "ㅜ"; btn_m.Text = "ㅡ"; } else { if (is_press_shift ^ cb_cabs.Checked) { btn_q.Text = "Q"; btn_w.Text = "W"; btn_e.Text = "E"; btn_r.Text = "R"; btn_t.Text = "T"; btn_y.Text = "Y"; btn_u.Text = "U"; btn_i.Text = "I"; btn_o.Text = "O"; btn_p.Text = "P"; btn_a.Text = "A"; btn_s.Text = "S"; btn_d.Text = "D"; btn_f.Text = "F"; btn_g.Text = "G"; btn_h.Text = "H"; btn_j.Text = "J"; btn_k.Text = "K"; btn_l.Text = "L"; btn_z.Text = "Z"; btn_x.Text = "X"; btn_c.Text = "C"; btn_v.Text = "V"; btn_b.Text = "B"; btn_n.Text = "N"; btn_m.Text = "M"; } else { btn_q.Text = "q"; btn_w.Text = "w"; btn_e.Text = "e"; btn_r.Text = "r"; btn_t.Text = "t"; btn_y.Text = "y"; btn_u.Text = "u"; btn_i.Text = "i"; btn_o.Text = "o"; btn_p.Text = "p"; btn_a.Text = "a"; btn_s.Text = "s"; btn_d.Text = "d"; btn_f.Text = "f"; btn_g.Text = "g"; btn_h.Text = "h"; btn_j.Text = "j"; btn_k.Text = "k"; btn_l.Text = "l"; btn_z.Text = "z"; btn_x.Text = "x"; btn_c.Text = "c"; btn_v.Text = "v"; btn_b.Text = "b"; btn_n.Text = "n"; btn_m.Text = "m"; } } }
private void cb_cabs_CheckedChanged(object sender, EventArgs e) { if (cb_cabs.Checked) { cb_cabs.BackColor = Color.YellowGreen; } else { cb_cabs.BackColor = SystemColors.Control; } } private void cb_with_shift_CheckedChanged(object sender, EventArgs e) { is_press_shift = cb_with_shift.Checked; ButtonSet(); } private void MainForm_FormClosed(object sender, FormClosedEventArgs e) { Automation.RemoveAutomationFocusChangedEventHandler(afceh); } private void Button_Click(object sender, EventArgs e) { Button btn = sender as Button; if (target != null) { target_ae.SetFocus(); Thread.Sleep(10); } switch (btn.Text) { case "Esc": WrapNative.KeyClick(Keys.Escape, is_press_shift); break; case "F1": WrapNative.KeyClick(Keys.F1, is_press_shift); break; case "F2": WrapNative.KeyClick(Keys.F2, is_press_shift); break; case "F3": WrapNative.KeyClick(Keys.F3, is_press_shift); break; case "F4": WrapNative.KeyClick(Keys.F4, is_press_shift); break; case "F5": WrapNative.KeyClick(Keys.F5, is_press_shift); break; case "F6": WrapNative.KeyClick(Keys.F6, is_press_shift); break; case "F7": WrapNative.KeyClick(Keys.F7, is_press_shift); break; case "F8": WrapNative.KeyClick(Keys.F8, is_press_shift); break; case "F9": WrapNative.KeyClick(Keys.F9, is_press_shift); break; case "F10": WrapNative.KeyClick(Keys.F10, is_press_shift); break; case "F11": WrapNative.KeyClick(Keys.F11, is_press_shift); break; case "F12": WrapNative.KeyClick(Keys.F12, is_press_shift); break; case "Tab": WrapNative.KeyClick(Keys.Tab, is_press_shift); break; case "Shift": WrapNative.KeyClick(Keys.ShiftKey, is_press_shift); break; case "Enter": WrapNative.KeyClick(Keys.Enter, is_press_shift); break; case "Caps": WrapNative.KeyClick(Keys.CapsLock, is_press_shift); cb_cabs.Checked ^= true; ButtonSet(); break; case "Ctrl": WrapNative.KeyClick(Keys.ControlKey, is_press_shift); break; case "Alt": WrapNative.KeyClick(Keys.Alt, is_press_shift); break; case "한/영 변환": check ^= true; ButtonSet(); break; case "Space": PressKey(' '); break; case "<-": PressKey('\b'); break; default: PressKey(btn.Text[0]); break; } lbox_event.Items.Add(btn.Text); lbox_event.SelectedIndex = lbox_event.Items.Count - 1; WrapNative.KeyClick(Keys.End,is_press_shift); } private void PressKey(char ch) { if (target == null){ return; } if (check){ hangul.Input(ch); } else { hangul.InputNoKorea(ch); } lb_text.Text = hangul.Text; target.SetValue(hangul.Text); } } } |
[소스] Form1.cs
가상 키보드 만들기 결과물
관련 게시물
[소프트웨어 접근성] 가상 키보드 만들기 2 - 키보드 이벤트 예광탄
[소프트웨어 접근성] 가상 키보드 만들기 3 - 마우스 이벤트 예광탄
[소프트웨어 접근성] 가상 키보드 만들기 4 -한글 오토마타 만들기 개요
[소프트웨어 접근성] 가상 키보드 만들기 5 -한글 문자 생성기
[소프트웨어 접근성] 가상 키보드 만들기 6 -한글 라이브러리 만들기
[소프트웨어 접근성] 가상 키보드 만들기 7 - 가상 키보드 타겟 데모
'프로그래밍 기술 > 소프트웨어 접근성, UI 자동화' 카테고리의 다른 글
9. 접근성 평가 도구 만들기 - 5. ImageCaptuer 클래스 (0) | 2016.10.19 |
---|---|
9. 접근성 평가 도구 만들기 - 4. WrapWinAPI 클래스 구현 (0) | 2016.10.19 |
9. 접근성 평가 도구 만들기 - 3. 속성과 컨트롤 패턴 열거형 정의하기 (0) | 2016.10.19 |
9. 접근성 평가 도구 만들기 - 2. 사용자 정의 형식 (0) | 2016.10.19 |
9. 접근성 평가 도구 만들기 - 1. 소개 (0) | 2016.10.18 |
[소프트웨어 접근성] 가상 키보드 만들기 7 - 가상 키보드 타겟 데모 (0) | 2016.05.13 |
[소프트웨어 접근성] 가상 키보드 만들기 6 -한글 라이브러리 만들기 (0) | 2016.05.13 |
[소프트웨어 접근성] 가상 키보드 만들기 5 -한글 문자 생성기 (0) | 2016.05.13 |
[소프트웨어 접근성] 가상 키보드 만들기 4 -한글 오토마타 만들기 개요 (0) | 2016.05.13 |
[소프트웨어 접근성] 가상 키보드 만들기 3 - 마우스 이벤트 예광탄 (0) | 2016.05.13 |