diff --git a/AutoClickerDL/AutoClickerDL.c b/AutoClickerDL/AutoClickerDL.c
index 8eb3b73..b12e28d 100644
--- a/AutoClickerDL/AutoClickerDL.c
+++ b/AutoClickerDL/AutoClickerDL.c
@@ -62,16 +62,22 @@ RecordingState recordingState;
// Keeps track of the current settings when the autoclicker is turned on.
Settings currentSettings;
+// The hook handle for the mouse hook.
HHOOK mouseHook;
+// The normal and activated icons.
+HICON normalIcon, clickActivatedIcon;
+
// Process callbacks.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK SettingsProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK RememberProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
+// Hook Callback
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
-// Main method.
+/*
+ This is the main method for the program.
+*/
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
// Prevent more than 1 instance of the program from running.
HANDLE mutexHandle = CreateMutex(NULL, TRUE, L"com_ryandw11_autoclickerdl");
@@ -83,12 +89,17 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
// Class name of the window.
const wchar_t CLASS_NAME[] = L"AutoClickerDL Window Class";
+ // Load the icons
+ normalIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
+ clickActivatedIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON2));
+
+ // Create and register the primary window class.
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
wc.lpszClassName = CLASS_NAME;
- wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
+ wc.hIcon = normalIcon;
RegisterClass(&wc);
@@ -97,6 +108,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX), CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT,
NULL, NULL, hInstance, NULL);
+ // If failed, return.
if (windowHandle == NULL) {
return 0;
}
@@ -283,19 +295,11 @@ void updateCurrentSettings(Settings* settings) {
settings->rmbPlayHotKey = SendMessage(rmbClkRecordPlayHK, HKM_GETHOTKEY, NULL, NULL);
}
-BOOL isHotkeyAlreadyInUse(int hotkeyID, int hotkey) {
- if (hotkeyID != AUTO_CLICK_HOTKEY && hotkey == SendMessage(startStopHotKey, HKM_GETHOTKEY, NULL, NULL)) {
- return TRUE;
- }
- if (hotkeyID != REMEMBER_HOTKEY && hotkey == SendMessage(rmbClkRecordHK, HKM_GETHOTKEY, NULL, NULL)) {
- return TRUE;
- }
- if (hotkeyID != REMEMBER_PLAY_HOTKEY && hotkey == SendMessage(rmbClkRecordPlayHK, HKM_GETHOTKEY, NULL, NULL)) {
- return TRUE;
- }
- return FALSE;
-}
+/**
+ Checks if one of the hot key controls are in focus.
+ @returns If one of the hotkey controls are in focus.
+*/
BOOL isHotkeyControlInFocus() {
HWND handle = GetFocus();
if (handle == startStopHotKey || handle == rmbClkRecordHK || handle == rmbClkRecordPlayHK) {
@@ -325,6 +329,7 @@ LRESULT CALLBACK SettingsProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam
SetFocus(mainWindowHandle);
}
}
+ // Handle a button being clicked.
else if (cmd == BN_CLICKED) {
int id = LOWORD(wParam);
// Handle the check click for the timed checkbox.
@@ -358,6 +363,9 @@ LRESULT CALLBACK SettingsProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
+/*
+ The process callback for the remember display area.
+*/
LRESULT CALLBACK RememberProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_COMMAND:
@@ -384,9 +392,12 @@ LRESULT CALLBACK RememberProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam
SetFocus(mainWindowHandle);
}
}
+ // Triggered by a button press.
else if (cmd == BN_CLICKED) {
int id = LOWORD(wParam);
+ // If the load recording button was pressed.
if (id == REMEMBER_LOAD_RECORDING) {
+ // Only trigger if the recording state is loaded or none.
if (!(recordingState.state == REC_STATE_LOADED || recordingState.state == REC_STATE_NONE)) {
break;
}
@@ -416,7 +427,9 @@ LRESULT CALLBACK RememberProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam
}
}
}
+ // If the save recording button was pressed.
else if (id == REMEMBER_SAVE_RECORDING) {
+ // Only trigger if the recording state is loaded.
if (recordingState.state != REC_STATE_LOADED) {
break;
}
@@ -445,6 +458,8 @@ LRESULT CALLBACK RememberProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam
break;
case WM_TIMER:
{
+ // This timer is triggered by the remember click play hotkey.
+
MouseClick* currentClick = recordingState.previousClick;
if (GetTickCount() - recordingState.prevoiusSystemTime < currentClick->delay) {
break;
@@ -543,6 +558,7 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_HOTKEY:
{
switch (wParam) {
+ // If the hotkey for the autoclicker was pressed.
case AUTO_CLICK_HOTKEY:
{
// If a hotkey contorl is in focus, don't trigger the auto clicker.
@@ -554,14 +570,17 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
updateCurrentSettings(¤tSettings);
startClickerTime = time(NULL);
autoClickerTimer = SetTimer(hwnd, 1001, (1000 / currentSettings.cps), (TIMERPROC)NULL);
+ SetClassLong(hwnd, GCL_HICON, clickActivatedIcon);
}
// Else, kill it.
else {
KillTimer(hwnd, autoClickerTimer);
autoClickerTimer = NULL;
+ SetClassLong(hwnd, GCL_HICON, normalIcon);
}
}
break;
+ // If the hotkey to remember the clicks was pressed.
case REMEMBER_HOTKEY:
{
// If a hotkey contorl is in focus, don't trigger the recording.
@@ -571,7 +590,9 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (autoClickerTimer != NULL) {
return;
}
+ // If the recording state is none or loaded, then start recording.
if (recordingState.state == REC_STATE_NONE || recordingState.state == REC_STATE_LOADED) {
+ // Delete the existing data if the recording is loaded.
if (recordingState.state == REC_STATE_LOADED) {
DeleteRecordingState(&recordingState);
InitRecordingState(&recordingState);
@@ -582,20 +603,27 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
recordingState.prevoiusSystemTime = GetTickCount();
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, GetModuleHandle(NULL), 0);
SetWindowText(rememberClickStatus, L"Recording clicks...");
+ // Change the icon to gray.
+ SetClassLong(hwnd, GCL_HICON, clickActivatedIcon);
}
+ // If the program is currently recording mouse clicks, stop the recording.
else if (recordingState.state == REC_STATE_RECORDING) {
recordingState.state = REC_STATE_LOADED;
recordingState.prevoiusSystemTime = 0;
recordingState.previousClick = recordingState.startOfRecording;
+ // Unhook the mouse hook to prevent lag if an error were to occur.
UnhookWindowsHookEx(mouseHook);
mouseHook = NULL;
EnableWindow(saveRecordingButton, TRUE);
wchar_t str[200] = {0};
swprintf(str, 200, L"Recording loaded with %d mouse clicks!\0", recordingState.numberOfClicks);
SetWindowText(rememberClickStatus, str);
+ // Change the icon back to normal.
+ SetClassLong(hwnd, GCL_HICON, normalIcon);
}
}
break;
+ // If the play recording hotkey was pressed.
case REMEMBER_PLAY_HOTKEY:
{
if (isHotkeyControlInFocus()) {
@@ -604,6 +632,7 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (autoClickerTimer != NULL) {
return;
}
+ // If the state is loaded, then play the recording.
if (recordingState.state == REC_STATE_LOADED) {
recordingState.state = REC_STATE_PLAYING;
recordingState.prevoiusSystemTime = GetTickCount();
@@ -613,8 +642,10 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
recordingState.previousClick = recordingState.startOfRecording;
rememberClickTimer = SetTimer(rememberClickDisplayArea, 1002, USER_TIMER_MINIMUM, (TIMERPROC)NULL);
+ SetClassLong(hwnd, GCL_HICON, clickActivatedIcon);
}
- else if (recordingState.state = REC_STATE_PLAYING) {
+ // If a recording is being played, stop the recording.
+ else if (recordingState.state == REC_STATE_PLAYING) {
KillTimer(rememberClickDisplayArea, rememberClickTimer);
recordingState.state = REC_STATE_LOADED;
recordingState.prevoiusSystemTime = 0;
@@ -622,6 +653,7 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
wchar_t str[200] = { 0 };
swprintf(str, 200, L"Recording loaded with %d mouse clicks!\0", recordingState.numberOfClicks);
SetWindowText(rememberClickStatus, str);
+ SetClassLong(hwnd, GCL_HICON, normalIcon);
}
}
break;
@@ -630,6 +662,7 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
break;
+ // This timer is for the normal auto clicker.
case WM_TIMER:
{
int up = 0;
@@ -669,6 +702,11 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
+/*
+ This is the callback for the mouse hook.
+
+ The mouse hook is set when the remember click record hotkey is pressed.
+*/
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if(nCode < 0 || recordingState.state != REC_STATE_RECORDING)
return CallNextHookEx(NULL, nCode, wParam, lParam);
diff --git a/AutoClickerDL/AutoClickerDL.rc b/AutoClickerDL/AutoClickerDL.rc
index 543dc7a..f3c89ec 100644
--- a/AutoClickerDL/AutoClickerDL.rc
+++ b/AutoClickerDL/AutoClickerDL.rc
@@ -54,6 +54,8 @@ END
// remains consistent on all systems.
IDI_ICON1 ICON "icon.ico"
+IDI_ICON2 ICON "icon2.ico"
+
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
diff --git a/AutoClickerDL/AutoClickerDL.vcxproj b/AutoClickerDL/AutoClickerDL.vcxproj
index 1959040..1b9a06c 100644
--- a/AutoClickerDL/AutoClickerDL.vcxproj
+++ b/AutoClickerDL/AutoClickerDL.vcxproj
@@ -154,6 +154,7 @@
+
diff --git a/AutoClickerDL/AutoClickerDL.vcxproj.filters b/AutoClickerDL/AutoClickerDL.vcxproj.filters
index 43a667a..ea6fc5a 100644
--- a/AutoClickerDL/AutoClickerDL.vcxproj.filters
+++ b/AutoClickerDL/AutoClickerDL.vcxproj.filters
@@ -45,5 +45,8 @@
Resource Files
+
+ Resource Files
+
\ No newline at end of file
diff --git a/AutoClickerDL/General.c b/AutoClickerDL/General.c
index 764128e..1022d6c 100644
--- a/AutoClickerDL/General.c
+++ b/AutoClickerDL/General.c
@@ -61,6 +61,12 @@ HWND CreateSpinner(HWND parent, HINSTANCE hInstance, Spinner spinner) {
return (spinnerUpDown);
}
+/**
+ Convert Windows Mouse (provided from windows mouse hook) value into the Mouse Click Type value.
+
+ @param wParam The WM value (example: WM_LBUTTONDOWN).
+ @returns The MC value (example: MC_TYPE_LEFT_DOWN). (Returns MC_TYPE_ERROR if not valid).
+*/
int WMToMC(int wParam) {
switch (wParam)
{
@@ -82,6 +88,12 @@ int WMToMC(int wParam) {
return 0;
}
+/*
+ Convert a MC Type to a Mouse Event Type.
+
+ @param mc The mouse click type. (Example: MC_TYPE_LEFT_DOWN).
+ @returns The event mouse type. (Example: MOUSEEVENTF_LEFTDOWN) (Returns MC_TYPE_ERROR if invalid input).
+*/
int MCToEventMouse(int mc) {
switch (mc) {
case MC_TYPE_LEFT_DOWN:
@@ -101,6 +113,11 @@ int MCToEventMouse(int mc) {
}
}
+/**
+ Initalize the recording state. (Note: the default state is NONE).
+
+ @param The pointer to the recording state to initalize.
+*/
void InitRecordingState(RecordingState* state) {
state->numberOfClicks = 0;
state->startOfRecording = NULL;
@@ -109,6 +126,12 @@ void InitRecordingState(RecordingState* state) {
state->prevoiusSystemTime = 0;
}
+/**
+ Add a mouse click the recording. (This will take care of every case and increment the numberOfClicks field).
+
+ @param recState The pointer to the recording state to add the mouse click to.
+ @param mouseClick The mouse click struct to add. (Note: mouseClick.nextClick does not need to be set).
+*/
void AddMouseClickToState(RecordingState* recState, MouseClick mouseClick) {
MouseClick* permElem = (MouseClick*)malloc(sizeof(MouseClick));
permElem->type = mouseClick.type;
@@ -128,10 +151,21 @@ void AddMouseClickToState(RecordingState* recState, MouseClick mouseClick) {
recState->numberOfClicks++;
}
+/**
+ Get the next mouse click for the recording state. (If the end of the recording is reached, it will look back to the begining).
+ Get the pointer to the MouseClick struct from `recState.prevoiusClick`.
+
+ @param recState The recording state to get the next mouse click from.
+*/
void NextMouseClick(RecordingState* recState) {
recState->previousClick = recState->previousClick->nextClick == NULL ? recState->startOfRecording : recState->previousClick->nextClick;
}
+/**
+ Delete (free) the memory used by the recording state. (Note: you should call InitRecordingState() if you intended on reusing the same struct).
+
+ @param state The recording state to free the memory from.
+*/
void DeleteRecordingState(RecordingState* state) {
if (state->numberOfClicks == 0) return;
state->previousClick = state->startOfRecording;
@@ -146,6 +180,15 @@ void DeleteRecordingState(RecordingState* state) {
state->state = REC_STATE_NONE;
}
+/**
+ Save a recording state to a file.
+ Note: The `previousClick` field of the recording state will be mutated.
+
+ @param state The recording state to save to a file.
+ @param location The location and name of the file to save to. (This is intented to be the output of a save file dialog box).
+
+ @returns If the save was successful.
+*/
BOOL SaveRecordingState(RecordingState* state, LPCWSTR location) {
#pragma warning(disable: 4996)
@@ -174,6 +217,15 @@ BOOL SaveRecordingState(RecordingState* state, LPCWSTR location) {
return TRUE;
}
+/**
+ Load a recording state from a file.
+ Note: This will delete the passed in recording state an re-initalize it.
+
+ @param state The recording state to load into.
+ @param location The location and name of the file to load. (Note: this is intended to be the output of an open file dialog box).
+
+ @returns If the recording was successfully loaded. (If not, the recording state will be the default initalized state of NONE).
+*/
BOOL LoadRecordingState(RecordingState* state, LPCWSTR location) {
#pragma warning(disable: 4996)
DeleteRecordingState(state);
diff --git a/AutoClickerDL/General.h b/AutoClickerDL/General.h
index 3c03ab6..4a4d18a 100644
--- a/AutoClickerDL/General.h
+++ b/AutoClickerDL/General.h
@@ -18,22 +18,41 @@
#define REC_STATE_RECORDING 3
#define REC_STATE_PLAYING 4
+/*
+ The representation of a MouseClick for use with the Remeber Click feature.
+*/
typedef struct {
+ // The type of click (denoted by MC_TYPE_ macros).
int type;
+ // The delay (in milliseconds) from the previous click.
int delay;
+ // The x position.
LONG x;
+ // The y position.
LONG y;
+ // The pointer to the next click in the recording.
struct MouseClick* nextClick;
} MouseClick;
+/*
+ The current state of the recording system for the Remember Click feature.
+*/
typedef struct {
+ // The current state (denoted by REC_STATE_ macros).
int state;
+ // The first click in a recording.
MouseClick* startOfRecording;
+ // The previous click that was done in a recording.
MouseClick* previousClick;
+ // The previous system time in milliseconds.
DWORD prevoiusSystemTime;
+ // The number of clicks stored.
int numberOfClicks;
} RecordingState;
+/*
+ The struct that contains all of the settings for the program.
+*/
typedef struct {
int cps;
BOOL timedAutoClick;
@@ -45,6 +64,9 @@ typedef struct {
int rmbPlayHotKey;
} Settings;
+/*
+ The struct used to define the properties of a spinner for creation.
+*/
typedef struct {
int x;
int y;
diff --git a/AutoClickerDL/IO.c b/AutoClickerDL/IO.c
index dfe715d..3e96e3a 100644
--- a/AutoClickerDL/IO.c
+++ b/AutoClickerDL/IO.c
@@ -5,6 +5,14 @@
#include "IO.h"
#pragma warning(disable: 4996)
+
+/**
+ Load settings from a file.
+ Note: If an error occurs, the settings will be set to the default.
+
+ @param fileName The name of the file.
+ @param settings The settings struct to load into.
+*/
void loadSettings(const char* fileName, Settings* settings) {
FILE* inputFile = fopen(fileName, "r");
@@ -41,10 +49,17 @@ void loadSettings(const char* fileName, Settings* settings) {
fclose(inputFile);
}
-
// FILE FORMAT::
// (1 bytes vernum) - (1 bytes CPS) - (1 byte bool) - (1 bytes - timedAutoClickerValue) - (1 bytes - delay time) - (1 bytes - mouse click type) - (4 bytes - hotkey) -
// (4 bytes - start recording hotkey) - (4 bytes - play recording hotkey)
+/**
+ Save settings to a file.
+
+ @param fileName The file name as a null terminated string.
+ @param settings The settings.
+
+ @returns -1 if error, 0 if ok.
+*/
int saveSettings(const char* fileName, Settings* settings) {
FILE* outputFile = fopen(fileName, "w");
@@ -65,18 +80,38 @@ int saveSettings(const char* fileName, Settings* settings) {
return 0;
}
+/**
+ Put an integer in a file in a byte format.
+
+ @param file The file to put the integer in.
+ @param input The integer to put in the file.
+*/
void fputi(FILE* file, int input) {
char charr[5] = { 0 };
itoa(input, charr, 10);
fprintf(file, "%c%c%c%c", charr[0], charr[1], charr[2], charr[3]);
}
+/**
+ Put a long in a file in a byte format.
+
+ @param file The file to put the long in.
+ @param input The long to put in the file.
+*/
void fputl(FILE* file, LONG input) {
char charr[9] = { 0 };
ltoa(input, charr, 10);
fprintf(file, "%c%c%c%c%c%c%c%c", charr[0], charr[1], charr[2], charr[3], charr[4], charr[5], charr[6], charr[7]);
}
+/**
+ Get an integer from a file in a byte format.
+
+ @param file The file to read from.
+ @param output The pointer to the variable where the obatined integer will be stored.
+
+ @returns If the integer was successfully grabbed. (FALSE if EOF occurs).
+*/
BOOL fgeti(FILE* file, int* output) {
char charr[5] = { 0 };
int opt = fscanf(file, "%c%c%c%c", &charr[0], &charr[1], &charr[2], &charr[3]);
@@ -84,6 +119,14 @@ BOOL fgeti(FILE* file, int* output) {
return opt != 4 ? FALSE : TRUE;
}
+/**
+ Get a long from a file in a byte format.
+
+ @param file The file to read from.
+ @param output The pointer to the variable where the obtained long will be stored.
+
+ @returns If the long was successfully grabbed. (FALSE if EOF occurs).
+*/
BOOL fgetl(FILE* file, LONG* output) {
char charr[9] = { 0 };
int opt = fscanf(file, "%c%c%c%c%c%c%c%c", &charr[0], &charr[1], &charr[2], &charr[3], &charr[4], &charr[5], &charr[6], &charr[7]);
diff --git a/AutoClickerDL/icon2.ico b/AutoClickerDL/icon2.ico
new file mode 100644
index 0000000..b2df6be
Binary files /dev/null and b/AutoClickerDL/icon2.ico differ
diff --git a/AutoClickerDL/resource.h b/AutoClickerDL/resource.h
index 306c261..3da6a6c 100644
--- a/AutoClickerDL/resource.h
+++ b/AutoClickerDL/resource.h
@@ -3,12 +3,13 @@
// Used by AutoClickerDL.rc
//
#define IDI_ICON1 103
+#define IDI_ICON2 104
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 104
+#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101