NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (기계식 또는 하드웨어 방식 키보드 매크로 2부)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 이전 시간에 기계식 또는 하드웨어 방식의 마우스 매크로를 만들어봤는데요. 오늘은 키보드에 대해서 알아보도록 할께요. 이미 키보드 관련 기능들은 대부분 다 개발이 되어 있어서 기존 모델들을 약간(?)만 수정하면 하드웨어 방식으로 동작하는 키보드 매크로를 제작할 수 있습니다. 다만, 소프트웨어 방식(비활성, 활성)과는 다르게 IME 처리가 약간 복잡할 수 있습니다.

     

    키보드는 마우스와 다르게 IME라는 개념을 알아야 합니다. IME란 Input Method Editor로 극동 아시아 언어인 한국어, 중국어, 일본어등 DBCS(Double Byte Character Sets) / MDCS(Multi Byte Character Sets)을 입력 받는 에디터를 말합니다. 일반적으로 윈도우를 설치할 때 사용자가 선택할 수 있도록 메뉴가 준비되어 있습니다. 지역(Locale) 코드가 기본값을 되어 있어서 설정했는지는 잘 기억이 안날수도 있습니다.

     

    일반적인 IME의 동작은 CWnd를 상속받아서 만든 윈도우 영문자를 입력 받아서 WM_KEYDOWN 다음에 WM_CHAR메세지가 발생하게 됩니다. 하지만, 한글인 경우에는 WM_KEYDOWN 다음에 WM_IME_COMPOSITION이 발생하고 한글이 완성이 되면 WM_CHAR가 두번 발생되게 됩니다. 왜 두번인지가 궁금할텐데요. 한글은 2byte라서 한번에 전달할 수 없기 때문입니다.

     

    이 문제점은 한글 처리를 자음이나 모음단위로 처리할 수 없고, 글자 단위로 처리해야 한다는 것입니다. 이런 문제를 해결하기 위해서 기본 IME에서 발생되는 메세지에 대한 처리를 프로그래머가 직접해줘야 합니다. 일단은 복잡한 내용은 천천히 알아보기로 하고, 간단하게 기계식 키보드로 입력하는 방법에 대해서 먼저 알아보겠습니다. 아두이노 장치에 키보드 정보를 전달하는건 KD와 KU입니다. 프로그래밍의 키코드와 가상 키코드는 서로 다릅니다. 따라서 아래 사이트를 참고해서 가상 키보드를 매핑해줘야 합니다.

    [ Microsoft Windows Virtual-Key Codes ]

    SX0Zwjv.png

     

     

    윈도우 키와 가상 키를 매핑하기 위해 User32의 MapVirtualKey 함수를 정의 해줍니다.

    [DllImport("user32.dll")]
    internal static extern uint MapVirtualKey(uint uCode, uint uMapType);

     

    시리얼 연결에 키보드 다운과 업 지연 속성도 추가해야 할거 같네요.

    [LocalizedCategory("KeyboardSpeed")]
    [LocalizedDisplayName("KeyboardDownUpDelay")]
    [LocalizedDescription("KeyboardDownUpDelay")]
    [Browsable(true)]
    [DefaultValue(1)]
    public int KeyboardDownUpDelay { get; set; } = 1;

    eiHtDTv.png

     

     

    기계식 하드웨어 마우스와 동일하게 키보드 설정도 글로벌 영역에 저장해줘야 합니다.

    player.Manager.SerialMouseSpeed = Speed;
    player.Manager.SerialMouseDistance = Distance;
    player.Manager.SerialAutoCorrection = AutoCorrection;
    player.Manager.SerialMouseDownUpDelay = MouseDownUpDelay;
    player.Manager.SerialKeyboardDownUpDelay = KeyboardDownUpDelay;

     

    이제 키보드 다운 모델을 만들어볼까요? 시리얼 통신 모드에서 키보드 다운과 업 지연 값을 미리 저장해줍니다. 속도가 0일수는 없으니 1보다 작으면 1로 셋팅했습니다.

    case DeviceInputType.Serial:
        int speed = player.Manager.SerialKeyboardDownUpDelay;
        if (speed < 1)
            speed = 1;

     

    하드웨어 방식으로 키보드를 처리할 때 윈도우의 펑션키는 처리가 불가능합니다. 따라서 아래와 같이 별도로 만들어야 합니다.

    if (Key == Api.NativeInputManager.Native.KeyboardVirtualKeyCode.CONTROL)
    {
        player.Manager.SerialPort.Write($"KD{Ai.Api.ApiHelper.SerialKeyCode(Ai.Api.NativeInputManager.Native.KeyboardVirtualKeyCode.CONTROL)}");
        break;
    }

     

    위에는 콘트롤키만 처리하고 있는데요. 추가적으로 가상키의 Alt, Shift, WindowsKey도 동일하게 처리해줘야 합니다. 사실 시리얼 통신 코드를 수정하면 이 작업을 안해도 되긴하지만, 8비트 장치에 긴 문자열을 전송할수가 없는데다가 전송 속도도 매우 느리기 때문에 축약한 키를 정의해서 사용하도록 했습니다. 이렇게하지 않으면 입력이 밀려서 문제가 발생할 수 있거든요.

     

    가상키를 시리얼키로 매핑하는 코드도 작성해야 합니다.

    public static string SerialKeyCode(NativeInputManager.Native.KeyboardVirtualKeyCode keyCode)
    {
        if (keyCode.ToString().Length == 2 && keyCode.ToString().StartsWith("N"))
            return keyCode.ToString().Substring(1);

     

    가상키와 시리얼키를 연결하는건 아두이노의 키보드 처리 로직에 따라 달라질 수 있습니다. 직접 만든 모듈이 있다면 이 내용은 달라질거예요. 자신이 구성한 디자인에 따라서 내용도 달라지기 때문에 꼭 이렇게 코딩해야 하는건 아닙니다. 더 효율적인 방법이 있을수도 있거든요. 아마도 개발자마다 자신만의 스타일이 있어서 저보다 더 효율적인 코드를 작성했을수도 있습니다. 코딩에서 정해진 답 같은건 없으니까요.

     

    하드웨어 키보드가 눌린 상태를 릴리즈할 수 있는 방법이 없기 때문에 키보드 업도 동일하게 코딩을 해줘야 합니다. 다만, 명령어만 KD에서 KU로 변경해주면 됩니다.

    player.Manager.SerialPort.Write($"KU{Api.ApiHelper.SerialKeyCode(Key)}");

     

    이제 이 내용을 이용해서 키보드 다운업 액션에도 동일하게 적용시켜볼께요. 키보드 다운과 키보드 업을 합치면 됩니다.

    if (Key != Ai.Api.NativeInputManager.Native.KeyboardVirtualKeyCode.NONE)
    {
        player.Manager.SerialPort.Write($"KD{Api.ApiHelper.SerialKeyCode(Key)}");
        System.Threading.Thread.Sleep(speed);
        player.Manager.SerialPort.Write($"KU{Api.ApiHelper.SerialKeyCode(Key)}");
    }

     

    정상적으로 동작하는지 간단하게 테스트를 해볼까요? 테스트 스크립트는 아래와 같습니다. 이 테스트의 시나리오는 메모장에 a 키를 1초간 누르고 있는 상황을 연출한것입니다.

    R1iInB6.png

     

     

    아래 동영상처럼 매크로를 실행하면 메모장을 클릭하고, 키보드 다운과 업이 실행됩니다. 키보드 업 전에 1초 대기가 있어서 a키를 누르고 있는 상태가 연출됩니다. 참고로, 소프트웨어 신호를 사용하면 a키를 누르고 있는 상태가 연출되지 않습니다. 소프트웨어 방식은 신호를 한번 주면 끝나기 때문입니다. 하드웨어 방식은 우리가 실제로 키보드를 사용하는것과 동일하기 때문에 누르고 있는 시간만큼 연속해서 키보드 신호가 발생합니다.

     

     

    대문자를 입력하려면 시프트키를 눌러주면 됩니다. 스크립트 내용을 아래와 같이 변경하고 다시 실행하면 됩니다.

    AAYHfWv.png

     

     

    매크로를 실행 해보세요. 예상한데로 잘 동작하는군요.

     

     

    키보드 입력(키보드 다운 업) 액션을 사용하면 아래와 같이 동작합니다.

    mKWaKbE.png

     

     

    결과는 대문자 A를 입력합니다. 시프트키를 누르고 있기 때문입니다.

    9KwVrXg.png

     

     

    키보드 다운과 업을 조합하면서 1초간 누르고 있는 동작을 동일하게 사용하려면 키보드 다운 업 지연 속성에 값을 입력하면 됩니다.

    84cyPlK.png

     

     

    이렇게해서 키보드 관련 내용을 대부분 알아봤는데요. 가장 복잡하고 어려운 텍스트 쓰기만 남겨놓고 있습니다. 텍스트 쓰기 기능은 한글과 영어, 특수문자등등... 다양한 경우의 수가 있고 이글 처음에 언급했듯이 한글 2바이트와 영어 및 특수문자 1바이트를 구분해내야 합니다. 그리고, 사용자 편의를 위해 자소 처리와 IME 처리도 같이 추가해야 합니다. 내용이 많다보니 여기에서 모두 다루기엔 무리네요. 하드웨어 기계식 마우스 키보드 매크로 강좌를 2부로 마무리 하려고 했는데요. 생각보다 글이 길어져서 3부까지 작성해야 할듯 합니다.

     

    텍스트 쓰기 관련된 내용은 3부에서 자세하게 알아보기로 하고, 하드웨어 기계식 키보드 매크로 제작 강좌는 여기서 마칠께요. 다음 3부도 기대해주세요.

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.