안녕하세요.
오늘은 Windows에 C 개발환경 설치와 Windows.h 라이브러리를 사용하여 마우스 매크로를 만들어 보려고 합니다.
C 개발환경 구성하기
제일 좋은 방법은 역시 Visual Studio를 이용해서 개발하는 것 입니다.
그렇지만 우리는 단순히 C 개발만 할 것이고, Visual Studio를 쓰기엔 지나치게 무겁고 느립니다.
그래서 오늘은 MinGW를 이용해서 개발환경을 구성해 볼 예정입니다.
MinGW 설치
MinGW는 마이크로소프트 윈도우로 포팅한 GNU 소프트웨어 도구 모음입니다.
Source Forge에서 설치파일을 다운로드 받을 수 있습니다.
다운로드 받아서 설치 하면 아래와 같이 패키지 설치 매니저가 뜹니다.
Basic Setup항목들을 모두 선택한 후에 상단 Installation > Apply Changes를 누르시면 GCC 컴파일러가 설치 되게 됩니다.
엄밀히 말해, 모든 패키지가 필요하지는 않습니다. Description을 읽어보시고 필요한 항목만 설치 하셔도 무방합니다.
Visual Studio Code 에 C 개발환경 세팅하기
우선 Visual Studio Code에서 C 파일을 하나 생성한 후 파일을 열어봅시다.
아래처럼 기본적인 하이라이팅은 지원되지만, 빌드도 안되고 인덱싱도 안되어 있어서 개발 환경이라고 하기엔 많이 부족합니다.
아래 Extention 3가지만 추가로 설치 해 주면 모든 설정이 끝납니다.
이제 파일을 다시 열어보면 아래와 같이 우측 상단에 뭔가 생긴것을 볼 수 있습니다.
그 중 실행 버튼을 눌러보시면 아래와 같이 자동으로 빌드가 됩니다.
Visual Studio 와 동일하게 F5 키를 눌러도 동작합니다!
소스코드가 있는 디렉터리에 가 보시면 ~~~.exe라는 파일이 생성 되어있습니다. ~~~에는 파일명이 쓰이게 됩니다.
실행해 보시면 아래와 같이 우리가 작성한 코드 그대로 실행 되는것을 볼 수 있습니다.
이제 개발환경 설정은 끝입니다! 참 쉽죠? 예전 같았으면 PATH 설정이라던지, 여러가지 번거로운 작업들을 해주었어야 했을테지만, 요즘엔 Visual Studio Code에서 알아서 설정 해 주어서 참 쉽게 설정할 수 있었던것 같습니다.
windows.h 사용해보기
windows.h는 윈도우 개발자들이 필요한 모든 매크로들, 다양한 함수들과 서브시스템에서 사용되는 모든 데이터 타입들 그리고 윈도우 API의 함수들을 위한 정의를 포함하는 윈도우의 C 및 C++ 헤더 파일입니다.
Wikipedia를 보면 알겠지만 정말 엄청나게 많은 Windows용 기능들을 가지고 있는 헤더 파일인데요.
오늘 만들어볼 매크로는 여기에 있는 함수 몇가지를 이용해 만들어볼 예정입니다.
GetPrivateProfileString
GetPrivateProfileString
함수는 ini 파일을 읽기 위해 사용할 수 있는 함수입니다.
아래와 같은 구조의 ini 파일이 있을 때
[Title1]
Name=test.cpp
Path=C:\temp\test.cpp
Version=2.1.0.1
아래와 같이 사용할 수 있습니다.
1
2
3
4
5
char ret[256];
memset(ret, 0, sizeof(ret));
GetPrivateProfileString( "Title1", "Name", "-", ret, sizeof(ret), "C:\\temp\\test.ini" );
// ret에는 'test.cpp'가 담기게 됨
// Name이 없을 경우 '-'가 담기게 됨
GetKeyState
GetKeyState
함수는 키가 눌려있는지를 체크할 수 있는 함수입니다.
키 코드는 Microsoft 공식 문서에서 확인 해 주세요
아래와 같이 사용할 수 있습니다.
1
2
3
4
if (GetKeyState(VK_F10) < 0) { // F10키를 누르면
printf("프로그램을 종료합니다.\n");
return 0; // 프로그램 종료
}
GetCursorPos
GetCursorPos
함수는 현재 커서의 위치를 가져오는 함수입니다.
아래와 같이 사용할 수 있습니다.
1
2
3
4
5
6
POINT pt; // 마우스 포인터
// ...
GetCursorPos(&pt); // 마우스 좌표값들 받아옴
printf("%d, %d\n", pt.x, pt.y);
SetCursorPos, mouse_event
SetCursorPos
함수는 마우스 커서를 움직이는 함수입니다.
mouse_event
함수는 마우스 이벤트를 발생 시키는 함수이구요.
이 둘을 조합해서 아래와 같이 자동 클릭 매크로를 만들 수 있습니다.
1
2
3
4
SetCursorPos(x[i],y[i]); // 지정한 곳의 좌표로 마우스 이동
mouse_event(MOUSEEVENTF_LEFTDOWN, x[i], y[i], 0, 0); // 좌표에 맞게 왼쪽버튼 누르기
Sleep(1); // 1ms 쉬기
mouse_event(MOUSEEVENTF_LEFTUP, x[i], y[i], 0, 0); // 좌표에 맞게 왼쪽버튼 떼기
매크로 전체 코드
제가 만든 전체 코드는 아래와 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <windows.h>
#include <stdio.h>
#include <sys/time.h>
void home();
int main(void) {
char *cBuf = NULL;
int delay = 0;
int milliseconds = 0;
struct timeval stop, start;
cBuf = (char *)malloc(sizeof(char) * 256);
memset(cBuf, 0x00, sizeof(cBuf));
GetPrivateProfileString("Section_1", "Delay", "-", cBuf, 256, "./setting.ini");
delay = atoi(cBuf);
memset(cBuf, 0x00, sizeof(cBuf));
GetPrivateProfileString("Section_1", "Milliseconds", "-", cBuf, 256, "./setting.ini");
milliseconds = atoi(cBuf);
memset(cBuf, 0x00, sizeof(cBuf));
POINT pt; // 마우스 포인터
int x[50000]; // 매크로 x좌표
int y[50000]; // 매크로 y좌표
int check_mouse = 2; // 마우스 관련 변수
int check_mouse2 = 2; // 마우스 관련 변수
int i = 0; // 매크로 녹화시 이용
// int n = 0; // 메크로 진행시 이용
system("mode con: cols=30 lines=13"); // 화면 고정
// printf("%d\n", milliseconds);
home(); // home이라는 이름을 가진 함수
for (i = 0; i <= 50000; i++) //초기화
{
x[i] = 0;
y[i] = 0; // 초기화 과정 다 0으로 초기화해줌
}
i = 0;
while (1) //무한반복 break문이나 return문으로 나가야됨.
{
if (GetKeyState(VK_F10) < 0) // F10키 누르면
{
printf("프로그램을 종료합니다.\n");
return 0; // 프로그램 종료
}
else if (GetKeyState(0x5A) < 0) // z 키를 누를 경우 해당 좌표 기록
{
GetCursorPos(&pt); // 마우스 좌표값들 받아옴
x[i] = pt.x; // x좌표값 저장
y[i] = pt.y; // y좌표값 저장
i++; // i는 프레임을 의미
printf("%d, %d\n", pt.x, pt.y);
Sleep(1000);
}
else if (GetKeyState(VK_F8) < 0) // 매크로 재생
{
i = 0; // 프레임 처음으로 돌아가서 재생하기 위한 n
printf("macro started. \n");
gettimeofday(&start, NULL);
while (1)
{
if (GetKeyState(VK_F7) < 0) // 0.01초마다 조건문 확인
{
printf("macro stoped.\n");
break;
}
if (GetKeyState(VK_F10) < 0)
{
printf("program exit.\n");
return 0;
}
gettimeofday(&stop, NULL);
printf("took %lu us\n", (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec);
SetCursorPos(x[i],y[i]); // 지정한 곳의 좌표로 마우스 이동
mouse_event(MOUSEEVENTF_LEFTDOWN, x[i], y[i], 0, 0); // 좌표에 맞게 왼쪽버튼 누르기
Sleep(1); // 1ms 쉬기
mouse_event(MOUSEEVENTF_LEFTUP, x[i], y[i], 0, 0); // 좌표에 맞게 왼쪽버튼 떼기
i++;
if (x[i] == 0 || y[i] == 0)
{
printf("program end.\n");
break;
}
gettimeofday(&start, NULL);
Sleep(delay-1); // 100ms마다 한번씩 쉬고
}
}
Sleep(10); // Sleep(1000)은 1초임. 즉, 0.01초를 기다린후 위로 올라가 반복문을 다시 실행
}
return 0; //메인문을 나감.
}
void home()
{
//홈화면
puts(" ----------------------"); // puts함수는 자동으로 줄바꿈 처리를 한다.
puts(" | |");
puts(" | Mouse Macro |");
puts(" | |");
puts(" | z : location save |");
puts(" | F7 : macro stop |");
puts(" | F8 : macro start |");
puts(" | F10 : exit |");
puts(" | |");
puts(" ----------------------");
}