본문 바로가기
매크로

2부 - 비개발자의 매크로 제작하기. (C# 또는 Python 파이썬 메크로 만들기)

by 백수아저씨 2022. 1. 30.
반응형

중고 자동차 매매, KB차차차, 거래소 자동 매매, 카모두, 에듀파인, 업무 자동화 제작 의뢰

개인용 메크로 프로그램 제작 http://ngmsoftware.com 

 

엔지엠소프트웨어

엔지엠 매크로는 복잡한 반복작업을 자동화할 수 있습니다. PC 게임, 모바일 게임을 최적으로 지원하며 모든 PC 프로그램 및 업무에 적용할 수 있습니다.

www.ngmsoftware.com

 

안녕하세요. 엔지엠소프트웨어입니다. [ 1부 파이썬 메크로 만들기 ]에 이어 2부에서는 C#으로 메크로를 만드는 방법에 대해 알려드리겠습니다. 파이썬은 잘 만들어진 패키지들이 존재하기 때문에 개발자라면 하루만에 원하는 매크로를 만들 수 있을정도로 정말 쉽습니다. 비개발자라도 일주일이면 가능할정도죠^^; 물론, 자동화하는 업무의 복잡도와 작업자(개발자 또는 일반인)의 이해력과 응용력에 따라 1주일에서 2주일정도 감안하면 될거 같습니다. 가장 쉬운건 엔지엠 에디터를 사용하는거지만요^^;

 

C# 메크로 만들기

 

 

C#은 파이썬보다 어려울 수 있습니다. GUI까지 갖추려면 더 많은 시간과 노력이 필요합니다. 그렇더라도 비주얼 스튜디오라는 막강한 무료 도구가 있어서 몇번 만져보다보면 누구나 쉽게 GUI를 구성해서 사용할 수 있습니다. 자바 개발자가 C#으로 넘어오더라도 크게 문제되지 않는 수준이거든요. 반대로 C# 개발자는 자바로 넘어가기가 쉽습니다. GUI를 신경쓰지 않고 비즈니스 로직만 구현하면 되니까요. UI 스레드와 작업자 스레드로부터도 자유로워요. 아무튼, C#으로 매크로를 개발하기 위한 준비단계라서 개발 환경을 갖추는것부터 하나씩 알아보도록 하겠습니다. 우선 Visual Studio Community를 [ 여기 ]에서 다운로드 받은 후 설치하세요. 설치 방법은 아래 글을 참고하세요.

비주얼 스튜디오 설치하기 ]

 

비주얼 스튜디오를 실행하기 전 중요한 설정이 있습니다. 이 내용을 설정하지 않으면 앞으로 개발하는데 문제가 발생하더라도 원인을 찾기가 상당히 어려워집니다. 아래 그림과 같이 설치한 비주얼 스튜디오에서 우클릭 후 자세히 > 파일 위치 열기를 클릭 하세요.

 

 

비주얼 스튜디오에서 우클릭 후 속성을 클릭하세요.

 

 

고급 버튼을 클릭하세요.

 

 

관리자 권한으로 실행에 체크하고, 확인을 클릭하세요.

 

 

개발할 때 관리자 권한으로 실행해야 합니다. 당연한 말이겠지만, 매크로 프로그램이 다른 프로그램을 제어해야 하기 때문에 높은 권한이 필요합니다. 그래서, 비주얼 스튜디오를 관리자 권한으로 매번 실행할 수 있도록 설정한겁니다. 추후에는 직접 만든 프로그램도 관리자 권한으로 실행될 수 있도록 처리해야 하는데요. 이건 차차 알아보기로 하고, C#을 개발하기 위한 비주얼 스튜디오를 실행 해봅시다. 여러분들은 아래 그림처럼 코딩되어 있지는 않을겁니다.

 

 

비주얼 스튜디오를 실행한 후 "새 프로젝트 만들기"를 클릭하세요.

 

 

Windows Forms 앱(.NET Framework) 프로젝트를 만들기 아래 그림을 참고해서 따라해보세요.

  1. 언어는 C# 선택
  2. 플렛폼은 Windows 선택
  3. 프로젝트 형식은 데스크톱 선택
  4. Windows Forms 앱(.NET Framework) 선택
  5. 다음 클릭

 

 

프로젝트 이름에 MyPlayer를 입력한 후 위치를 설정하세요. 이 예제에서는 기본 위치를 사용합니다. 마지막으로 프레임워크를 4.6.1로 선택하고 만들기를 클릭하세요.

 

 

여기까지 하면 아래와 같은 윈폼 프로젝트가 생성됩니다. 현업에서는 Windows Forms를 줄여서 윈폼이라고 부릅니다. 보시면 아시겠지만~ 엔지엠 에디터와 비슷한 화면 구성을 가지고 있습니다. 대부분의 IDE가 이런 구성을 가지는데요. 가장 효율적으로 많은 정보를 표시할 수 있는 UI/UX라고 보면 될거 같습니다. 저는 뭔가 할때마다 새창이 뜨는걸 별로 안좋아 합니다. 작업의 흐름을 방해하기 때문이죠^^;

 

 

여기까지해서 C# 매크로를 만들기 위한 준비를 마쳤습니다. 이제 매크로를 실행하고, 중지할 수 있는 버튼을 만드는것부터 시작해야 합니다. 아래 동영상을 참고해서 버튼 2개를 추가하고, 각각 표시할 텍스트를 "실행"과 "중지"로 수정 해주세요.

 

 

각각의 버튼을 더블 클릭하면 버튼을 눌렀을 때 동작해야 하는 이벤트 처리기를 자동으로 추가 해줍니다.

 

 

C#에는 윈도우에 마우스 이벤트를 줄 수 있는 기능이 없습니다. 그래서, 윈도우 API인 win32 라이브러리를 이용해야 합니다. 다행스럽게도~ C나 C++처럼 윈도우 라이브러리를 쉽게 가져와서 사용할 수 있습니다. 이제 마우스 클릭에 대한 코드를 작성 해볼까요? 아래 2줄을 추가하세요.

        const uint LBUTTONDOWN = 0x0002;    // 왼쪽 마우스 버튼 누름
        const uint LBUTTONUP = 0x0004;      // 왼쪽 마우스 버튼 땜

 

전체 코드는 아래와 같습니다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MyPlayer
{
    public partial class Form1 : Form
    {
        const uint LBUTTONDOWN = 0x0002;    // 왼쪽 마우스 버튼 누름
        const uint LBUTTONUP = 0x0004;      // 왼쪽 마우스 버튼 땜

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            
        }

        private void button2_Click(object sender, EventArgs e)
        {

        }
    }
}

 

주석(// ...)에도 설명을 달아두었지만, 마우스 클릭은 기본적으로 마우스를 누르고 때는 동작을 말합니다. 그렇기 때문에 LBUTTONDOWN과 LBUTTONUP으로 윈도우에 신호를 줘야 합니다. 신호 값은 0x0002와 0x0004와 같은 16진수 값입니다. 이 값은 컴퓨터 언어로 우리가 외워서 사용하기는 쉽지 않습니다. 2개정도야 뭐 문제가 안되겠지만요^^; 매크로를 만들다보면 무수히 많은 비트 값을 처리해야 하는데요. 이런 값들을 사용하기 쉽게 하려고 이름을 지어준다고 생각하시면 이해하기 쉬울겁니다. 아래와 같이 win32 라이브러리를 추가 해줍니다.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyPlayer
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        const uint LBUTTONDOWN = 0x0002;    // 왼쪽 마우스 버튼 누름
        const uint LBUTTONUP = 0x0004;      // 왼쪽 마우스 버튼 땜

 

그냥 알아보기 쉽게 숫자를 사용하면 될텐데 왜 16진수를 사용하는지 약간 궁금할수도 있습니다. 16진수는 0부터 F까지 16개의 수를 가집니다.

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F

 

대부분의 프로그래밍 언어에서 숫자(Integer)는 2바이트로 이루어져 있습니다. 1바이트는 8비트로 이루어져 있죠. 그래서 숫자형은 16비트입니다. 8비트를 반으로 나누면 4비트가 되는데 4비트는 1부터 16까지 표현이 가능합니다. 이는 컴퓨터의 CPU가 한번에 처리할 수 있는 최소 단위와 동일해서 2진수와 변환이 쉬운 16진수를 사용하게 되었습니다. 그래서 16비트의 숫자형에는 0xFFFF까지 넣을 수 있습니다. 요즘은 32비트, 64비트를 한번에 처리할 수 있습니다. 초창기에 컴퓨터 처리 단위가 지금까지 이어져서 사용된다고 이해하면 되겠습니다^^; 홈페이지 어딘가에... CPU, Memory, 컴퓨터에 대해 작성해둔 글이 있는데 한번 찾아보시면 좋을거 같네요.

 

위 코드에서 불필요한 using은 제거한 상태입니다. 일단, DllImport는 비관리 라이브러리에서 정적 메소드를 사용할 수 있도록 해주는 C# 특성(Attribute)입니다. 점점 어려운 용어들이 나오고 있어서... 설명해야 하나 말아야 하나 고민이 깊어집니다. 개발자라면 그냥 아는 이야기들인데요. 이걸 설명하려면 또 많은 시간을 잡아먹을듯 하군요. 여러분들은 단순히 비관리(C나 C++로 만들어진 동적 라이브러리) 기능을 가져다가 쓸 때 이 특성을 이용하면 된다고 이해하시면 됩니다. 바탕화면의 아이콘들의 좌표를 알아내기 위해 엔지엠 에디터를 실행하고, 마우스 액션을 하나 추가 해줍니다.

엔지엠 에디터 무료 버전 다운로드 받기 ]

 

 

우측 속성창에서 마우스 좌표 속성을 선택하세요. 그러면, 우측에 "..." 버튼이 표시됩니다.

 

 

"..." 버튼을 클릭한 후 바탕화면의 "내 PC" 로 이동하세요. 그리고, F1을 누르면 해당 좌표를 확인할 수 있습니다. 제 모니터 해상도(1920x1080) 기준 "내 PC"의 좌표는 "40, 31"입니다. 이 값을 아래와 같이 마우스 클릭 좌표로 사용하면 됩니다. 완성된 전체 코드입니다.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyPlayer
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        const uint LBUTTONDOWN = 0x0002;    // 왼쪽 마우스 버튼 누름
        const uint LBUTTONUP = 0x0004;      // 왼쪽 마우스 버튼 땜

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Cursor.Position = new Point(40, 31); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);
        }

        private void button2_Click(object sender, EventArgs e)
        {

        }
    }
}

 

간단하죠? 이제 정상적으로 동작하는지 테스트를 해볼까요? 비주얼 스튜디오에서 F5(실행)를 누르거나 아래 동영상처럼 ▶ 버튼을 클릭해도 됩니다. 우리가 만든 프로그램이 컴파일된 후 아래와 같은 프로그램이 실행됩니다. 여기서 실행 버튼을 클릭하면 정확하게 내 PC를 클릭합니다.

 

 

순차적으로 바탕화면의 모든 아이콘을 클릭 해볼까요? 엔지엠 에디터에서 마우스 클릭 액션의 "..."을 눌러서 각각의 좌표를 알아냅니다. 그리고, 아래와 같이 코드를 3번 복사한 후 좌표 값만 변경 해줍니다. 이 때 X 좌표는 동일하므로 Y 좌표만 변경해주면 됩니다.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyPlayer
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        const uint LBUTTONDOWN = 0x0002;    // 왼쪽 마우스 버튼 누름
        const uint LBUTTONUP = 0x0004;      // 왼쪽 마우스 버튼 땜

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Cursor.Position = new Point(40, 31); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);

            Cursor.Position = new Point(40, 109); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);

            Cursor.Position = new Point(40, 195); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);

            Cursor.Position = new Point(40, 278); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);
        }

        private void button2_Click(object sender, EventArgs e)
        {

        }
    }
}

 

 

다시 실행 해보면, 아래 동영상처럼 동작 할겁니다. 그런데 마우스가 순차적으로 클릭한건지 잘 확인이 되지 않습니다. 너무 빠르기 때문인데요. 코드를 약간 수정해야 할듯 합니다.

 

 

마우스 클릭 사이에 System.Threading.Thread.Sleep(500); 을 추가해줬습니다. 이 코드는 0.5초(500) 쉰다는 뜻입니다.

        private void button1_Click(object sender, EventArgs e)
        {
            Cursor.Position = new Point(40, 31); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);

            System.Threading.Thread.Sleep(500);

            Cursor.Position = new Point(40, 109); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);

            System.Threading.Thread.Sleep(500);

            Cursor.Position = new Point(40, 195); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);

            System.Threading.Thread.Sleep(500);

            Cursor.Position = new Point(40, 278); // 내 PC 좌표
            mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
            mouse_event(LBUTTONUP, 0, 0, 0, 0);
        }

 

 

수정된 코드를 확인 해볼까요? 여러분들도 아래 동영상처럼 0.5초 간격으로 바탕화면의 아이콘을 클릭할겁니다.

 

 

추가로, 이 동작을 5번 반복하려면 어떻게 해야 할까요? for문으로 감싼 후 조건을 5로 주면 됩니다. C# 반복문에 대한 자세한 설명은 [ 여기 ]를 참고하세요.

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 5; i++)
            {
                Cursor.Position = new Point(40, 31); // 내 PC 좌표
                mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                mouse_event(LBUTTONUP, 0, 0, 0, 0);

                System.Threading.Thread.Sleep(500);

                Cursor.Position = new Point(40, 109); // 내 PC 좌표
                mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                mouse_event(LBUTTONUP, 0, 0, 0, 0);

                System.Threading.Thread.Sleep(500);

                Cursor.Position = new Point(40, 195); // 내 PC 좌표
                mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                mouse_event(LBUTTONUP, 0, 0, 0, 0);

                System.Threading.Thread.Sleep(500);

                Cursor.Position = new Point(40, 278); // 내 PC 좌표
                mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                mouse_event(LBUTTONUP, 0, 0, 0, 0);
            }
        }

 

 

5번 반복하고 매크로가 중지 되었습니다.

 

 

마지막으로 중지 버튼을 누르면 매크로의 동작이 남아 있더라도 즉시 중지되도록 만들어보겠습니다. 마우스의 제어권을 사용자가 아닌 매크로가 가지고 있으므로, 중지 버튼을 누를 시간이 필요합니다. 그래서, "System.Threading.Thread.Sleep(500);" 값을 "System.Threading.Thread.Sleep(1000);" 으로 변경 했습니다. 사용자가 중지 버튼을 눌렀는지 확인하기 위한 상태 저장용 변수를 하나 추가 해줍니다.

bool isStop = true;

 

시작 버튼을 누르면 싱행중이니 이 값은 false로 바뀌고, 중지 버튼을 누르면 이 값은 true로 변경됩니다. 전체 코드는 아래와 같습니다.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyPlayer
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        const uint LBUTTONDOWN = 0x0002;    // 왼쪽 마우스 버튼 누름
        const uint LBUTTONUP = 0x0004;      // 왼쪽 마우스 버튼 땜

        bool isStop = true;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            isStop = false;

            new System.Threading.Thread(new System.Threading.ThreadStart(delegate
            {
                for (int i = 0; i < 5; i++)
                {
                    Cursor.Position = new Point(40, 31); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);

                    Cursor.Position = new Point(40, 109); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);

                    Cursor.Position = new Point(40, 195); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);

                    Cursor.Position = new Point(40, 278); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);
                }
            })).Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            isStop = true;
        }
    }
}

 

 

실행중에 재빠르게 중지 버튼을 눌러보세요. 5회 반복하지 않고 매크로가 중지됩니다.

 

 

이렇게해서 간단하게 마우스 매크로를 만들어 봤습니다. 사실, 여러가지 많은 테스트를 해보고 싶지만~ 가급적이면 C# 언어 강좌를 보고 직접 학습하면서 살을 붙여 나가는게 좋습니다. 어느정도 기초 지식과 응용력이 있어야 더 좋은 매크로를 만들 수 있거든요. 단순히 마우스 클릭만으로 이루어진 간단한 업무의 경우 이정도만 알아도 좌표를 가져다가 클릭으로 처리할 수 있기도 합니다. 이미지 서치 기능을 만들기 위해 버튼을 하나 추가 해줍니다. 아래 동영상을 참고해서 버튼을 추가하고 이름은 이미지 서치로 설정하세요.

 

 

이미지 서치에 대한 기능을 직접 구현하는건 상당히 많은양의 코드를 작성해야 합니다. [ 파이썬 매크로 만들기 ]와 동일하게 C#도 누군가가 이미 만들어놓은 멋진 모듈이 존재합니다. 90프로의 개발자는 남이 만들어놓은 코드 또는 모듈을 가져다가 사용합니다^^; 물론, 저도 그렇구요~ 아래와 같이 메뉴의 도구 > NuGet 패키지 관리자 > 솔루션용 NuGet 패키지 관리를 클릭하세요.

 

 

찾아보기 탭에서 imagefinder를 검색하세요. 이미지 서치 또는 이미지 파인더로 검색하면 많은 모듈이 나올겁니다. 괜찮은 모듈을 찾아서 사용하면 됩니다^^

 

 

ImageFinder를 선택하고, 설치를 진행하세요. 설치가 완료되면 프로젝트에 해당 모듈의 참조가 자동으로 추가되고, 사용할 수 있는 상태가 됩니다.

 

 

이미지를 찾으려면 어디에서 무엇을 찾을지 설정해야 합니다. "어디에서"는 컴퓨터의 화면입니다.  "무엇을"은 컴퓨터 화면에서 찾을 어떤 그림을 말합니다. 이 예제에서는 그림판에 오랜지색 점을 하나 추가한 후 이 점을 찾아서 클릭하는 예제를 만들겁니다. 따라서, 그림판을 실행하고 오랜지색 점을 하나 찍어줘야 합니다.

 

 

화면에 오랜지색 점이 있으니 인식할 이미지를 만들어야겠죠? 엔지엠 에디터를 실행하고 아래 동영상처럼 오랜지색 점을 캡쳐해서 이미지로 만듭니다. 무료 버전 엔지엠 에디터를 설치한 후 아래와 같이 해도되지만, 별도의 캡쳐 프로그램이 있다면 그 프로그램을 사용해서 오랜지색 점만 따서 별도로 저장하면 됩니다.

 

 

아래 그림처럼 바탕화면에 orange.png로 이미지를 저장 했습니다.

 

 

이제 이미지 서치 이벤트에 아래와 같이 코드를 작성해줍니다.

        private void button3_Click(object sender, EventArgs e)
        {
            // 현재 모니터 화면을 이미지로 설정합니다.
            ImageFinderNS.ImageFinder.SetSource(ImageFinderNS.ImageFinder.MakeScreenshot());

            // 바탕화면에 찾을 이미지를 선택한 후 유사도를 설정합니다.
            // 유사도는 float값으로 1.0f로 설정 했습니다.
            var finds = ImageFinderNS.ImageFinder.Find(Image.FromFile(@"C:\Users\ngmas\Desktop\orange.png"), 1.0f);

            // 찾은 이미지들의 목록만큼 반복하면서 클릭해줍니다.
            foreach (var find in finds)
            {
                // 유사도가 90프로 일치하면 클릭하도록 해줍니다.
                if (find.Similarity > 0.9f)
                {
                    Rectangle rect = find.Zone;

                    // 찾은 이미지의 중앙을 클릭하기 위해 좌표에 크기의 반을 더해줍니다.
                    Cursor.Position = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);
                }
            }
        }

 

주석을 달아놓았기 때문에 ImageFinder 모듈을 사용하는데 크게 어려운점은 없을겁니다^^; 이제 프로그램을 실행한 후 오랜지색 점을 클릭하는지 볼까요?

 

 

여러분들도 그림판의 오랜지색 점을 잘 클릭했을거예요. 엔지엠 에디터와 같은 매크로 프로그램을 사용하면 쉽게 처리할 수 있지만, 직접 코딩으로 구현하려면 여러가지 신경써줘야 할것들이 많습니다. 이미지를 캡쳐하는 프로그램부터 좌표계를 계산하는 부분까지 그렇죠. 그리고, 게임에서 이용하는 경우에는 랜덤 값을 많이 쓰는데요. 이런 것들도 코딩으로 처리해줘야 합니다. 엔지엠 매크로 에디터는 아래와 같이 간단하게 처리할 수 있습니다.

 

 

찾은 이미지에서 랜덤하게 마우스를 클릭하려면 랜덤 최대값과 최소값을 설정하기만 하면 됩니다. 최소 -100에서 최대 100까지 설정해서 그런지 이미지에서 많이 벗어난 위치도 클릭하고 있네요. 보통은 이미지 크기에 따라서 이 값도 적절하게 설정해주는게 좋습니다. 아주 작은 이미지에서 큰 랜덤 값은 해당 이미지를 클릭하지 못할수도 있으니까요~

 

 

이렇게 C#으로 이미지 인식 매크로를 만들어봤습니다. 어느정도 로직이 들어가야 업무에 활용할 수 있겠지만, 현재로써는 이정도만 알아도 대부분의 업무용 매크로를 직접 만들어서 사용하는데 크게 어려운 부분은 없을겁니다. 이외에도 키보드 관련 내용도 준비중이니 많은 기대 부탁드리며, 오늘은 여기에서 마치도록 하겠습니다. 아래는 이 매크로의 전체 코드입니다!

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyPlayer
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        const uint LBUTTONDOWN = 0x0002;    // 왼쪽 마우스 버튼 누름
        const uint LBUTTONUP = 0x0004;      // 왼쪽 마우스 버튼 땜

        bool isStop = true;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            isStop = false;

            new System.Threading.Thread(new System.Threading.ThreadStart(delegate
            {
                for (int i = 0; i < 5; i++)
                {
                    Cursor.Position = new Point(40, 31); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);

                    Cursor.Position = new Point(40, 109); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);

                    Cursor.Position = new Point(40, 195); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);

                    Cursor.Position = new Point(40, 278); // 내 PC 좌표
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);

                    if (isStop) break;
                    System.Threading.Thread.Sleep(1000);
                }
            })).Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            isStop = true;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            // 현재 모니터 화면을 이미지로 설정합니다.
            ImageFinderNS.ImageFinder.SetSource(ImageFinderNS.ImageFinder.MakeScreenshot());

            // 바탕화면에 찾을 이미지를 선택한 후 유사도를 설정합니다.
            // 유사도는 float값으로 1.0f로 설정 했습니다.
            var finds = ImageFinderNS.ImageFinder.Find(Image.FromFile(@"C:\Users\ngmas\Desktop\orange.png"), 1.0f);

            // 찾은 이미지들의 목록만큼 반복하면서 클릭해줍니다.
            foreach (var find in finds)
            {
                // 유사도가 90프로 일치하면 클릭하도록 해줍니다.
                if (find.Similarity > 0.9f)
                {
                    Rectangle rect = find.Zone;

                    // 찾은 이미지의 중앙을 클릭하기 위해 좌표에 크기의 반을 더해줍니다.
                    Cursor.Position = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
                    mouse_event(LBUTTONDOWN, 0, 0, 0, 0);
                    mouse_event(LBUTTONUP, 0, 0, 0, 0);
                }
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            // 창을 활성화 하기 위해 1초 기다려줍니다.
            System.Threading.Thread.Sleep(1000);

            // 텍스트 박스에 입력한 텍스트를 가져와서 text 변수에 저장합니다.
            string text = textBox1.Text;

            // 활성화된 창에 텍스트를 씁니다.
            SendKeys.Send(text);
        }
    }
}

 

마지막으로 키보드 메크로를 만들어 보겠습니다. 아래 동영상을 참고해서 입력할 텍스트를 적을 TextBox 콘트롤을 추가하고, 실행할 버튼도 하나 추가해줍니다.

 

 

텍스트 쓰기 버튼을 더블 클릭하면 이벤트 처리기가 소스에 자동으로 추가 됩니다. 이제는 버튼을 추가하고 더블 클릭하면 이 버튼을 클릭했을 때 동작하는 코드를 작성해야 한다는걸 알게 되었습니다. 2부와 3부 내용을 학습하신 분들은 이미 알고 있겠지만요^^; 아래와 같이 코드를 추가하세요.

        private void button4_Click(object sender, EventArgs e)
        {
            // 창을 활성화 하기 위해 1초 기다려줍니다.
            System.Threading.Thread.Sleep(1000);

            // 활성화된 창에 텍스트를 씁니다.
            SendKeys.Send("안녕하세요! NGMsoftware입니다.");
        }

 

F5를 눌러서 실행 해볼까요? 아래 동영상처럼 텍스트 쓰기 버튼을 누른 후 재빠르게 메모장을 클릭해놔야 합니다. 잘 동작하죠?

 

 

이제 텍스트 박스에 입력한 텍스트를 메모장에 쓰게 코드를 약간 수정해야 합니다. 아래와 같이 코드를 변경하세요.

        private void button4_Click(object sender, EventArgs e)
        {
            // 창을 활성화 하기 위해 1초 기다려줍니다.
            System.Threading.Thread.Sleep(1000);

            // 텍스트 박스에 입력한 텍스트를 가져와서 text 변수에 저장합니다.
            string text = textBox1.Text;

            // 활성화된 창에 텍스트를 씁니다.
            SendKeys.Send(text);
        }

 

프로그램을 실행한 후 텍스트 박스에 원하는 글자를 입력하세요. 그리고, 텍스트 쓰기 버튼을 클릭하면 사용자가 입력한 내용을 쓸 수 있게됩니다.

 

 

특수키를 입력하려면 어떻게 해야 할까요? 특수키는 탭 또는 엔터(리턴)키와 같은 것들입니다. 특수키는 대괄호를 이용해서 입력할 수 있습니다. 텍스트 박스에 "안녕!{enter}NGM입니다!"와 같이 입력한 후 다시 실행 해보세요. 대괄호에 입력한 enter로 인해서 줄바꿈이 되는걸 확인할 수 있습니다.

 

 

C#의 "SendKeys.Send" 메소드는 입력된 텍스트를 그대로 입력해줍니다. 한글과 영어 그리고, 특수문자까지도요. 그래서 대소문자를 굳이 처리하지 않아도 됩니다. 그러나, Ctrl+A, Ctrl+C, Ctrl+V와 같은 동작들은 자주 사용되는 기능들입니다. 그래서, Shift, Ctrl, Alt와 같은 스페셜 키도 입력할 수 있어야 합니다. 이들은 아래와 같이 처리됩니다.

  • Shift: +
  • Ctrl: ^
  • Alt: %

 

테스트를 위해 텍스트 박스에 "^a^c{end}{enter}^v"와 같이 입력한 후 실행 했습니다. 보면 아시겠지만, 전체 선택 후 클립보드에 복사합니다. 그리고, 엔드키를 눌러서 마지막으로 커서를 이동하고 엔터를 눌러서 줄바꿈 해줍니다. 마지막으로 붙여넣기 후 작업이 완료됩니다.

 

 

생각보다 사용법이 너무 쉽죠^^? 이렇게해서 장장 4부에 걸쳐서 C#으로 마우스, 키보드, 이미지 인식 매크로를 만들어봤습니다. 사실 복잡한 업무를 매크로로 만들려면 더 많은 기능들을 추가해야겠지만, 기본적인 뼈대는 이미 만들었으므로 여기에 살만 좀 붙이면 괜찮은 매크로가 될거 같습니다. 비개발자분들은 시간이 좀 걸리겠지만, 아는 개발자 지인이 있다면 치킨 한마리 사주고 원하는 기능을 만들어 달라고하면 한두시간이면 뚝딱 만들겁니다. 개발자 입장에서는 매크로 프로그램이 그렇게 어렵지 않은 소프트웨어거든요^^

※ 특수키 코드표는 [ 여기 ]를 참고하세요!

 

업무용 메크로 제작 의뢰, 매크로 프로그램 제작, 단순 반복 업무 자동화, 오토 작업 개발 의뢰

엔지엠 무료 메크로 다운로드 http://ngmsoftware.com

 

엔지엠소프트웨어

엔지엠 매크로는 복잡한 반복작업을 자동화할 수 있습니다. PC 게임, 모바일 게임을 최적으로 지원하며 모든 PC 프로그램 및 업무에 적용할 수 있습니다.

www.ngmsoftware.com

 

반응형

댓글