Skip to content

Commit

Permalink
Finished Documentation
Browse files Browse the repository at this point in the history
- Fully documented all functions within the program.
- The program icon will now change when the auto clicker is enabled to act as an indicator.
  • Loading branch information
ryandw11 committed Dec 29, 2021
1 parent d7cc262 commit 3766e88
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 18 deletions.
70 changes: 54 additions & 16 deletions AutoClickerDL/AutoClickerDL.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);

Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -554,14 +570,17 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
updateCurrentSettings(&currentSettings);
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.
Expand All @@ -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);
Expand All @@ -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()) {
Expand All @@ -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();
Expand All @@ -613,15 +642,18 @@ 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;
recordingState.previousClick = recordingState.startOfRecording;
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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions AutoClickerDL/AutoClickerDL.rc
Original file line number Diff line number Diff line change
Expand Up @@ -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
/////////////////////////////////////////////////////////////////////////////

Expand Down
1 change: 1 addition & 0 deletions AutoClickerDL/AutoClickerDL.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
</ItemGroup>
<ItemGroup>
<Image Include="icon.ico" />
<Image Include="icon2.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand Down
3 changes: 3 additions & 0 deletions AutoClickerDL/AutoClickerDL.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@
<Image Include="icon.ico">
<Filter>Resource Files</Filter>
</Image>
<Image Include="icon2.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
</Project>
52 changes: 52 additions & 0 deletions AutoClickerDL/General.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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:
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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)

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 3766e88

Please sign in to comment.