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