Skip to content

Commit 2a05b57

Browse files
authored
Merge pull request #16 from AHS12/dev
RC-1.0.4: hook rewrite, support all mouse button, fix multi instance issue
2 parents 9457ffa + c0b9783 commit 2a05b57

File tree

19 files changed

+1481
-874
lines changed

19 files changed

+1481
-874
lines changed

build/build.conf

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
# Build Configuration
2-
VERSION=1.0.3
3-
COMPANY_NAME=Click Guardian Project
4-
PRODUCT_NAME=Click Guardian
5-
DESCRIPTION=Prevents accidental double-clicks with configurable delay protection
6-
COPYRIGHT=© 2025 Azizul Hakim
7-
8-
# Build settings
9-
BUILD_OUTPUT_DIR=dist
10-
BUILD_TEMP_DIR=build/temp
11-
12-
# Code signing settings (optional - set these if you have a certificate)
13-
# SIGN_CERT_FILE=path/to/certificate.p12
14-
# SIGN_CERT_PASSWORD=your_password
15-
# SIGN_TIMESTAMP_URL=http://timestamp.digicert.com
16-
17-
# Advanced build options
18-
ENABLE_UPX_COMPRESSION=false
19-
ENABLE_DEBUG_SYMBOLS=false
20-
ENABLE_VERBOSE_BUILD=false
1+
# Build Configuration
2+
VERSION=1.0.4
3+
COMPANY_NAME=Click Guardian Project
4+
PRODUCT_NAME=Click Guardian
5+
DESCRIPTION=Prevents accidental double-clicks with configurable delay protection
6+
COPYRIGHT=© 2025 Azizul Hakim
7+
8+
# Build settings
9+
BUILD_OUTPUT_DIR=dist
10+
BUILD_TEMP_DIR=build/temp
11+
12+
# Code signing settings (optional - set these if you have a certificate)
13+
# SIGN_CERT_FILE=path/to/certificate.p12
14+
# SIGN_CERT_PASSWORD=your_password
15+
# SIGN_TIMESTAMP_URL=http://timestamp.digicert.com
16+
17+
# Advanced build options
18+
ENABLE_UPX_COMPRESSION=false
19+
ENABLE_DEBUG_SYMBOLS=false
20+
ENABLE_VERBOSE_BUILD=false

build/windows/app-manifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3-
<assemblyIdentity version="1.0.3.0" processorArchitecture="*" name="ClickGuardian" type="win32" />
3+
<assemblyIdentity version="1.0.4.0" processorArchitecture="*" name="ClickGuardian" type="win32" />
44
<!-- Application information -->
55
<description>Click Guardian - Double-Click Protection</description>
66
<!-- UAC settings - run as normal user -->

build/windows/app.rc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
ICON_ID ICON "app-icon.ico"
44

55
1 VERSIONINFO
6-
FILEVERSION 1,0,3,0
7-
PRODUCTVERSION 1,0,3,0
6+
FILEVERSION 1,0,4,0
7+
PRODUCTVERSION 1,0,4,0
88
FILEFLAGSMASK 0x3fL
99
#ifdef _DEBUG
1010
FILEFLAGS 0x1L
@@ -21,12 +21,12 @@ BEGIN
2121
BEGIN
2222
VALUE "CompanyName", "Click Guardian Project"
2323
VALUE "FileDescription", "Click Guardian - Double-Click Protection"
24-
VALUE "FileVersion", "1.0.3"
24+
VALUE "FileVersion", "1.0.4"
2525
VALUE "InternalName", "click-guardian"
2626
VALUE "LegalCopyright", "© 2025 Azizul hakim"
2727
VALUE "OriginalFilename", "click-guardian.exe"
2828
VALUE "ProductName", "Click Guardian"
29-
VALUE "ProductVersion", "1.0.3"
29+
VALUE "ProductVersion", "1.0.4"
3030
VALUE "Comments", "Prevents accidental double-clicks with configurable delay protection"
3131
END
3232
END

cmd/click-guardian/main.go

Lines changed: 107 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,107 @@
1-
package main
2-
3-
import (
4-
"fmt"
5-
"os"
6-
7-
"click-guardian/internal/gui"
8-
"click-guardian/internal/version"
9-
)
10-
11-
func main() {
12-
// Check for command line arguments
13-
startMinimized := false
14-
autoProtect := false
15-
16-
for _, arg := range os.Args[1:] {
17-
switch arg {
18-
case "--minimized":
19-
startMinimized = true
20-
case "--auto-protect":
21-
autoProtect = true
22-
case "--version", "-v":
23-
fmt.Println(version.GetFullVersionString())
24-
return
25-
case "--help", "-h":
26-
showHelp()
27-
return
28-
}
29-
}
30-
31-
app := gui.NewApplication()
32-
if startMinimized {
33-
app.RunMinimized()
34-
} else {
35-
if autoProtect {
36-
app.RunWithAutoProtect()
37-
} else {
38-
app.Run()
39-
}
40-
}
41-
}
42-
43-
// showHelp displays command-line usage information
44-
func showHelp() {
45-
info := version.GetAppInfo()
46-
fmt.Printf("%s v%s\n", info.Name, info.Version)
47-
fmt.Printf("%s\n\n", info.Description)
48-
49-
fmt.Println("Usage:")
50-
fmt.Printf(" %s [options]\n\n", os.Args[0])
51-
52-
fmt.Println("Options:")
53-
fmt.Println(" --minimized Start minimized to system tray")
54-
fmt.Println(" --auto-protect Start with protection automatically enabled")
55-
fmt.Println(" --version, -v Show version information")
56-
fmt.Println(" --help, -h Show this help message")
57-
fmt.Println()
58-
59-
fmt.Println("Examples:")
60-
fmt.Printf(" %s # Start normally\n", os.Args[0])
61-
fmt.Printf(" %s --minimized # Start minimized to tray\n", os.Args[0])
62-
fmt.Printf(" %s --auto-protect # Start with protection enabled\n", os.Args[0])
63-
fmt.Println()
64-
65-
fmt.Printf("%s\n", info.Copyright)
66-
}
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"time"
7+
8+
"click-guardian/internal/gui"
9+
"click-guardian/internal/version"
10+
"click-guardian/pkg/platform"
11+
12+
"github.com/juju/mutex/v2"
13+
)
14+
15+
// realClock implements mutex.Clock using the real system clock
16+
type realClock struct{}
17+
18+
// After waits for the duration to elapse and then sends the current time on the returned channel
19+
func (realClock) After(d time.Duration) <-chan time.Time {
20+
return time.After(d)
21+
}
22+
23+
// Now returns the current clock time
24+
func (realClock) Now() time.Time {
25+
return time.Now()
26+
}
27+
28+
func main() {
29+
// Check for command line arguments
30+
startMinimized := false
31+
autoProtect := false
32+
33+
for _, arg := range os.Args[1:] {
34+
switch arg {
35+
case "--minimized":
36+
startMinimized = true
37+
case "--auto-protect":
38+
autoProtect = true
39+
case "--version", "-v":
40+
fmt.Println(version.GetFullVersionString())
41+
return
42+
case "--help", "-h":
43+
showHelp()
44+
return
45+
}
46+
}
47+
48+
// Define a unique name for your app's mutex
49+
spec := mutex.Spec{
50+
Name: "click-guardian-single-instance", // Must be unique per app (valid format)
51+
Clock: realClock{}, // Use real-time clock
52+
Delay: 500 * time.Millisecond, // Polling interval
53+
Timeout: 1 * time.Second, // How long to wait for the mutex
54+
}
55+
56+
// Try to acquire the mutex
57+
releaser, err := mutex.Acquire(spec)
58+
if err != nil {
59+
// If mutex acquisition fails, another instance is running
60+
showAlreadyRunningMessage()
61+
os.Exit(1)
62+
}
63+
defer releaser.Release() // Release mutex when the app exits
64+
65+
// If we reach here, this is the only instance
66+
app := gui.NewApplication()
67+
if startMinimized {
68+
app.RunMinimized()
69+
} else {
70+
if autoProtect {
71+
app.RunWithAutoProtect()
72+
} else {
73+
app.Run()
74+
}
75+
}
76+
}
77+
78+
// showAlreadyRunningMessage shows a dialog informing the user that another instance is running
79+
func showAlreadyRunningMessage() {
80+
// Show a native Windows message box
81+
platform.ShowMessageBox("Click Guardian", "Click Guardian is already running.\n\nLook for the icon in your system tray or check your taskbar.")
82+
}
83+
84+
// showHelp displays command-line usage information
85+
func showHelp() {
86+
info := version.GetAppInfo()
87+
fmt.Printf("%s v%s\n", info.Name, info.Version)
88+
fmt.Printf("%s\n\n", info.Description)
89+
90+
fmt.Println("Usage:")
91+
fmt.Printf(" %s [options]\n\n", os.Args[0])
92+
93+
fmt.Println("Options:")
94+
fmt.Println(" --minimized Start minimized to system tray")
95+
fmt.Println(" --auto-protect Start with protection automatically enabled")
96+
fmt.Println(" --version, -v Show version information")
97+
fmt.Println(" --help, -h Show this help message")
98+
fmt.Println()
99+
100+
fmt.Println("Examples:")
101+
fmt.Printf(" %s # Start normally\n", os.Args[0])
102+
fmt.Printf(" %s --minimized # Start minimized to tray\n", os.Args[0])
103+
fmt.Printf(" %s --auto-protect # Start with protection enabled\n", os.Args[0])
104+
fmt.Println()
105+
106+
fmt.Printf("%s\n", info.Copyright)
107+
}

cmd/click-guardian/main_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/juju/mutex/v2"
8+
)
9+
10+
// TestSingleInstanceMutex tests that we can acquire and release the mutex
11+
func TestSingleInstanceMutex(t *testing.T) {
12+
spec := mutex.Spec{
13+
Name: "click-guardian-test-single-instance", // Valid name for testing
14+
Clock: realClock{}, // Use real-time clock
15+
Delay: 100 * time.Millisecond, // Short polling interval for testing
16+
Timeout: 500 * time.Millisecond, // Short timeout for testing
17+
}
18+
19+
// Acquire the mutex
20+
releaser, err := mutex.Acquire(spec)
21+
if err != nil {
22+
t.Fatalf("Failed to acquire mutex: %v", err)
23+
}
24+
25+
// Try to acquire the mutex again - this should fail
26+
_, err = mutex.Acquire(spec)
27+
if err == nil {
28+
t.Fatal("Expected to fail when acquiring mutex again, but succeeded")
29+
}
30+
31+
// Release the mutex
32+
releaser.Release()
33+
34+
// Now we should be able to acquire it again
35+
releaser2, err := mutex.Acquire(spec)
36+
if err != nil {
37+
t.Fatalf("Failed to acquire mutex after releasing: %v", err)
38+
}
39+
defer releaser2.Release()
40+
}

0 commit comments

Comments
 (0)