Skip to content

Commit 237cbde

Browse files
committed
Add 2008 source code from https://dlaa.me/blog/post/8964592.
0 parents  commit 237cbde

6 files changed

Lines changed: 620 additions & 0 deletions

BuildAllRelease.cmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
MSBuild -t:Rebuild -p:Configuration=Release -p:Platform=Win32
2+
MSBuild -t:Rebuild -p:Configuration=Release -p:Platform=x64

MouseButtonClicker.cpp

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// MouseButtonClicker - http://blogs.msdn.com/Delay
2+
//
3+
// "MouseButtonClicker clicks the mouse so you don't have to!"
4+
//
5+
// Simple Windows utility to click the primary mouse button whenever the mouse
6+
// stops moving as a usability convenience/enhancement.
7+
8+
9+
#include <windows.h>
10+
#include <tchar.h>
11+
#include <malloc.h>
12+
#include <strsafe.h>
13+
14+
// Macro for compile-time assert
15+
#define COMPILE_TIME_ASSERT(e) typedef int CTA[(e) ? 1 : -1]
16+
17+
// Constants for code simplification
18+
#define RI_ALL_MOUSE_BUTTONS_DOWN (RI_MOUSE_BUTTON_1_DOWN | RI_MOUSE_BUTTON_2_DOWN | RI_MOUSE_BUTTON_3_DOWN | RI_MOUSE_BUTTON_4_DOWN | RI_MOUSE_BUTTON_5_DOWN)
19+
#define RI_ALL_MOUSE_BUTTONS_UP (RI_MOUSE_BUTTON_1_UP | RI_MOUSE_BUTTON_2_UP | RI_MOUSE_BUTTON_3_UP | RI_MOUSE_BUTTON_4_UP | RI_MOUSE_BUTTON_5_UP)
20+
21+
// Check that bit-level assumptions are correct
22+
COMPILE_TIME_ASSERT(RI_MOUSE_BUTTON_1_DOWN == (RI_MOUSE_BUTTON_1_UP >> 1));
23+
COMPILE_TIME_ASSERT(RI_MOUSE_BUTTON_2_DOWN == (RI_MOUSE_BUTTON_2_UP >> 1));
24+
COMPILE_TIME_ASSERT(RI_MOUSE_BUTTON_3_DOWN == (RI_MOUSE_BUTTON_3_UP >> 1));
25+
COMPILE_TIME_ASSERT(RI_MOUSE_BUTTON_4_DOWN == (RI_MOUSE_BUTTON_4_UP >> 1));
26+
COMPILE_TIME_ASSERT(RI_MOUSE_BUTTON_5_DOWN == (RI_MOUSE_BUTTON_5_UP >> 1));
27+
COMPILE_TIME_ASSERT(RI_ALL_MOUSE_BUTTONS_DOWN == (RI_ALL_MOUSE_BUTTONS_UP >> 1));
28+
29+
// Macro for absolute value
30+
#define ABS(v) ((0 <= v) ? v : -v)
31+
32+
// Application-level constants
33+
#define APPLICATION_NAME (TEXT("MouseButtonClicker"))
34+
#define TIMER_EVENT_ID (1)
35+
#define MOUSE_MOVE_THRESHOLD (2)
36+
37+
// Window procedure
38+
LRESULT CALLBACK WndProc(const HWND hWnd, const UINT message, const WPARAM wParam, const LPARAM lParam)
39+
{
40+
// Tracks the mouse move delta threshold across calls to WndProc
41+
static LONG lLastClickDeltaX = 0;
42+
static LONG lLastClickDeltaY = 0;
43+
static bool fOkToClick = false;
44+
45+
switch (message)
46+
{
47+
// Raw input message
48+
case WM_INPUT:
49+
{
50+
// Query for required buffer size
51+
UINT cbSize = 0;
52+
if(0 == GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, NULL, &cbSize, sizeof(RAWINPUTHEADER)))
53+
{
54+
// Allocate buffer on stack (falls back to heap)
55+
const LPVOID pData = _malloca(cbSize);
56+
if(NULL != pData)
57+
{
58+
// Get raw input data
59+
if(cbSize == GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, pData, &cbSize, sizeof(RAWINPUTHEADER)))
60+
{
61+
// Only interested in mouse input
62+
const RAWINPUT* const pRawInput = static_cast<LPRAWINPUT>(pData);
63+
if (RIM_TYPEMOUSE == pRawInput->header.dwType)
64+
{
65+
// Only interested in devices that use relative coordinates
66+
// Specifically, input from pens/tablets is ignored
67+
if(0 == (pRawInput->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE))
68+
{
69+
// Tracks the state of the mouse buttons across calls to WndProc
70+
static UINT usMouseButtonsDown = 0;
71+
72+
// Update mouse delta variables
73+
lLastClickDeltaX += pRawInput->data.mouse.lLastX;
74+
lLastClickDeltaY += pRawInput->data.mouse.lLastY;
75+
76+
// Enable clicking once the mouse has exceeded the threshold in any direction
77+
fOkToClick |= ((MOUSE_MOVE_THRESHOLD < ABS(lLastClickDeltaX)) || (MOUSE_MOVE_THRESHOLD < ABS(lLastClickDeltaY)));
78+
79+
// Determine the input type
80+
const UINT usButtonFlags = pRawInput->data.mouse.usButtonFlags;
81+
if(0 == (usButtonFlags & (RI_ALL_MOUSE_BUTTONS_DOWN | RI_ALL_MOUSE_BUTTONS_UP | RI_MOUSE_WHEEL)))
82+
{
83+
// Mouse move: (Re)set click timer if no buttons down and mouse moved enough to avoid jitter
84+
if((0 == usMouseButtonsDown) && fOkToClick)
85+
{
86+
// Use double-click time as an indication of the user's responsiveness preference
87+
(void)SetTimer(hWnd, TIMER_EVENT_ID, GetDoubleClickTime(), NULL);
88+
}
89+
}
90+
else
91+
{
92+
// Mouse button down/up or wheel rotation: Cancel click timer
93+
(void)KillTimer(hWnd, TIMER_EVENT_ID);
94+
95+
// Update mouse button state variable (asserts above ensure the bit manipulations are correct)
96+
usMouseButtonsDown |= (usButtonFlags & RI_ALL_MOUSE_BUTTONS_DOWN);
97+
usMouseButtonsDown &= ~((usButtonFlags & RI_ALL_MOUSE_BUTTONS_UP) >> 1);
98+
99+
// Reset mouse delta and threshold variables
100+
lLastClickDeltaX = 0;
101+
lLastClickDeltaY = 0;
102+
fOkToClick = false;
103+
}
104+
}
105+
}
106+
}
107+
// Free buffer
108+
(void)_freea(pData);
109+
}
110+
}
111+
}
112+
break;
113+
// Timer message
114+
case WM_TIMER:
115+
{
116+
// Timeout, stop timer and click primary button
117+
(void)KillTimer(hWnd, TIMER_EVENT_ID);
118+
INPUT pInputs[2] = {0};
119+
pInputs[0].type = INPUT_MOUSE;
120+
pInputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
121+
pInputs[1].type = INPUT_MOUSE;
122+
pInputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;
123+
(void)SendInput(2, pInputs, sizeof(INPUT));
124+
125+
// Reset mouse delta and threshold variables
126+
lLastClickDeltaX = 0;
127+
lLastClickDeltaY = 0;
128+
fOkToClick = false;
129+
}
130+
break;
131+
// Close message
132+
case WM_DESTROY:
133+
(void)PostQuitMessage(0);
134+
break;
135+
// Unhandled message
136+
default:
137+
return DefWindowProc(hWnd, message, wParam, lParam);
138+
}
139+
// Return value 0 indicates message was processed
140+
return 0;
141+
}
142+
143+
// WinMain entry point
144+
int APIENTRY _tWinMain(const HINSTANCE hInstance, const HINSTANCE hPrevInstance, const LPTSTR lpCmdLine, const int nCmdShow)
145+
{
146+
// Avoid compiler warnings for unreferenced parameters
147+
UNREFERENCED_PARAMETER(hPrevInstance);
148+
UNREFERENCED_PARAMETER(lpCmdLine);
149+
UNREFERENCED_PARAMETER(nCmdShow);
150+
151+
// Create a mutex to prevent running multiple simultaneous instances
152+
const HANDLE mutex = CreateMutex(NULL, FALSE, APPLICATION_NAME);
153+
if((NULL != mutex) && (ERROR_ALREADY_EXISTS != GetLastError()))
154+
{
155+
// Register the window class
156+
WNDCLASS wc = {0};
157+
wc.lpfnWndProc = WndProc;
158+
wc.hInstance = hInstance;
159+
wc.lpszClassName = APPLICATION_NAME;
160+
if(0 != RegisterClass(&wc))
161+
{
162+
// Create a message-only window to receive WM_INPUT and WM_TIMER
163+
const HWND hWnd = CreateWindow(APPLICATION_NAME, APPLICATION_NAME, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, hInstance, NULL);
164+
if (NULL != hWnd)
165+
{
166+
// Register for the mouse's raw input data
167+
RAWINPUTDEVICE rid = {0};
168+
rid.usUsagePage = 1; // HID_DEVICE_SYSTEM_MOUSE
169+
rid.usUsage = 2; // HID_DEVICE_SYSTEM_MOUSE
170+
rid.dwFlags = RIDEV_INPUTSINK;
171+
rid.hwndTarget = hWnd;
172+
if(RegisterRawInputDevices(&rid, 1, sizeof(rid)))
173+
{
174+
// Pump Windows messages
175+
MSG msg = {0};
176+
while (GetMessage(&msg, NULL, 0, 0))
177+
{
178+
TranslateMessage(&msg);
179+
DispatchMessage(&msg);
180+
}
181+
// Return success
182+
return static_cast<int>(msg.wParam);
183+
}
184+
}
185+
}
186+
// Failed to initialize, output a diagnostic message (which is not more
187+
// friendly because it represents a scenario that should never occur)
188+
TCHAR szMessage[64];
189+
if(SUCCEEDED(StringCchPrintf(szMessage, sizeof(szMessage)/sizeof(szMessage[0]), TEXT("Initialization failure. GetLastError=%d\r\n"), GetLastError())))
190+
{
191+
(void)MessageBox(NULL, szMessage, APPLICATION_NAME, MB_OK | MB_ICONERROR);
192+
}
193+
}
194+
// Return failure
195+
return 0;
196+
// By contract, Windows frees all resources as part of process exit
197+
}

MouseButtonClicker.ico

1.05 KB
Binary file not shown.

MouseButtonClicker.rc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "afxres.h"
2+
3+
4+
// English (U.S.) resources
5+
6+
#ifdef _WIN32
7+
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
8+
#pragma code_page(1252)
9+
#endif //_WIN32
10+
11+
12+
// Version
13+
14+
VS_VERSION_INFO VERSIONINFO
15+
FILEVERSION 1,0,1,0
16+
PRODUCTVERSION 1,0,1,0
17+
FILEFLAGSMASK 0x17L
18+
#ifdef _DEBUG
19+
FILEFLAGS 0x1L
20+
#else
21+
FILEFLAGS 0x0L
22+
#endif
23+
FILEOS 0x4L
24+
FILETYPE 0x1L
25+
FILESUBTYPE 0x0L
26+
BEGIN
27+
BLOCK "StringFileInfo"
28+
BEGIN
29+
BLOCK "040904b0"
30+
BEGIN
31+
VALUE "CompanyName", "http://blogs.msdn.com/Delay/"
32+
VALUE "FileDescription", "MouseButtonClicker clicks the mouse so you don't have to!"
33+
VALUE "FileVersion", "1.01"
34+
VALUE "InternalName", "MouseButtonClicker"
35+
VALUE "LegalCopyright", "Copyright (C) 2008"
36+
VALUE "OriginalFilename", "MouseButtonClicker"
37+
VALUE "ProductName", "MouseButtonClicker"
38+
VALUE "ProductVersion", "1.01"
39+
END
40+
END
41+
BLOCK "VarFileInfo"
42+
BEGIN
43+
VALUE "Translation", 0x409, 1200
44+
END
45+
END
46+
47+
48+
// Icon
49+
50+
101 ICON "MouseButtonClicker.ico"

MouseButtonClicker.sln

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 10.00
3+
# Visual Studio 2008
4+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseButtonClicker", "MouseButtonClicker.vcproj", "{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}"
5+
EndProject
6+
Global
7+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8+
Debug|Win32 = Debug|Win32
9+
Debug|x64 = Debug|x64
10+
Release|Win32 = Release|Win32
11+
Release|x64 = Release|x64
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Debug|Win32.ActiveCfg = Debug|Win32
15+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Debug|Win32.Build.0 = Debug|Win32
16+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Debug|x64.ActiveCfg = Debug|x64
17+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Debug|x64.Build.0 = Debug|x64
18+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Release|Win32.ActiveCfg = Release|Win32
19+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Release|Win32.Build.0 = Release|Win32
20+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Release|x64.ActiveCfg = Release|x64
21+
{8A1D9BB1-98E6-4FEB-9C63-B9FD014ABDC7}.Release|x64.Build.0 = Release|x64
22+
EndGlobalSection
23+
GlobalSection(SolutionProperties) = preSolution
24+
HideSolutionNode = FALSE
25+
EndGlobalSection
26+
EndGlobal

0 commit comments

Comments
 (0)