Skip to content

Commit 42e5956

Browse files
refactor: The whole project (#6)
* feat: Use system-wide Escape key for exiting * chore: updated github project structure * fix: go module * refactor: refactored wayland package * refactor: added models package * refactor: added stroke package * refactor: added shaders package * feat: better shader implementation * refactor: added config package * refactor: added execute package * refactor: added default dpackage * refactor: added gesture package * chore: updated gitignore * refactor: all the project * chore: handled unhandled error * chore: updated deprecated functions * feat: embedded the shader files * chore: deleted fornow package * fix: added result/ to gitignore for nix build * Update manual build instructions in readme * Correctly ignore Nix build output --------- Co-authored-by: Andromeda <stroev.andrew@gmail.com>
1 parent 72a14b4 commit 42e5956

34 files changed

Lines changed: 2586 additions & 2166 deletions
File renamed without changes.
File renamed without changes.
File renamed without changes.

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
result/
2-
hexecute
1+
# go build -o bin ./...
2+
bin/
3+
4+
# nix build (produces a symlink)
5+
result

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A gesture-based launcher for Wayland. Launch apps by casting spells! 🪄
44

5-
![Demo GIF](assets/demo.gif)
5+
![Demo GIF](.github/assets/demo.gif)
66

77
## Installation
88

@@ -58,8 +58,9 @@ If you have [Nix](https://nixos.org/) installed, simply run `nix build`.
5858

5959
Otherwise, make sure you have Go (and all dependent Wayland (and X11!?) libs) installed, then run:
6060
```bash
61-
go build
62-
./hexecute
61+
mkdir -p bin
62+
go build -o bin ./...
63+
./bin/hexecute
6364
```
6465

6566
## Usage

cmd/hexecute/main.go

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"log"
7+
"os"
8+
"runtime"
9+
"time"
10+
11+
"github.com/ThatOtherAndrew/Hexecute/internal/config"
12+
"github.com/ThatOtherAndrew/Hexecute/internal/draw"
13+
"github.com/ThatOtherAndrew/Hexecute/internal/execute"
14+
gestures "github.com/ThatOtherAndrew/Hexecute/internal/gesture"
15+
"github.com/ThatOtherAndrew/Hexecute/internal/models"
16+
"github.com/ThatOtherAndrew/Hexecute/internal/opengl"
17+
"github.com/ThatOtherAndrew/Hexecute/internal/spawn"
18+
"github.com/ThatOtherAndrew/Hexecute/internal/stroke"
19+
"github.com/ThatOtherAndrew/Hexecute/internal/update"
20+
"github.com/ThatOtherAndrew/Hexecute/pkg/wayland"
21+
"github.com/go-gl/gl/v4.1-core/gl"
22+
)
23+
24+
func init() {
25+
runtime.LockOSThread()
26+
}
27+
28+
type App struct {
29+
*models.App
30+
}
31+
32+
func main() {
33+
learnCommand := flag.String("learn", "", "Learn a new gesture for the specified command")
34+
listGestures := flag.Bool("list", false, "List all registered gestures")
35+
removeGesture := flag.String("remove", "", "Remove a gesture by command name")
36+
flag.Parse()
37+
38+
if flag.NArg() > 0 {
39+
log.Fatalf("Unknown arguments: %v", flag.Args())
40+
}
41+
42+
if *listGestures {
43+
gestures, err := gestures.LoadGestures()
44+
if err != nil {
45+
log.Fatal("Failed to load gestures:", err)
46+
}
47+
if len(gestures) == 0 {
48+
println("No gestures registered")
49+
} else {
50+
println("Registered gestures:")
51+
for _, g := range gestures {
52+
println(" ", g.Command)
53+
}
54+
}
55+
return
56+
}
57+
58+
if *removeGesture != "" {
59+
gestures, err := gestures.LoadGestures()
60+
if err != nil {
61+
log.Fatal("Failed to load gestures:", err)
62+
}
63+
64+
found := false
65+
for i, g := range gestures {
66+
if g.Command == *removeGesture {
67+
gestures = append(gestures[:i], gestures[i+1:]...)
68+
found = true
69+
break
70+
}
71+
}
72+
73+
if !found {
74+
log.Fatalf("Gesture not found: %s", *removeGesture)
75+
}
76+
77+
configFile, err := config.GetPath()
78+
if err != nil {
79+
log.Fatal("Failed to get config path:", err)
80+
}
81+
82+
data, err := json.Marshal(gestures)
83+
if err != nil {
84+
log.Fatal("Failed to marshal gestures:", err)
85+
}
86+
87+
if err := os.WriteFile(configFile, data, 0644); err != nil {
88+
log.Fatal("Failed to save gestures:", err)
89+
}
90+
91+
println("Removed gesture:", *removeGesture)
92+
return
93+
}
94+
95+
window, err := wayland.NewWaylandWindow()
96+
if err != nil {
97+
log.Fatal("Failed to create Wayland window:", err)
98+
}
99+
defer window.Destroy()
100+
101+
app := &models.App{StartTime: time.Now()}
102+
103+
if *learnCommand != "" {
104+
app.LearnMode = true
105+
app.LearnCommand = *learnCommand
106+
log.Printf("Learn mode: Draw the gesture 3 times for command '%s'", *learnCommand)
107+
} else {
108+
gestures, err := gestures.LoadGestures()
109+
if err != nil {
110+
log.Fatal("Failed to load gestures:", err)
111+
}
112+
app.SavedGestures = gestures
113+
log.Printf("Loaded %d gesture(s)", len(gestures))
114+
}
115+
116+
opengl := opengl.New(app)
117+
if err := opengl.InitGL(); err != nil {
118+
log.Fatal("Failed to initialize OpenGL:", err)
119+
}
120+
121+
gl.ClearColor(0, 0, 0, 0)
122+
123+
for range 5 {
124+
window.PollEvents()
125+
gl.Clear(gl.COLOR_BUFFER_BIT)
126+
window.SwapBuffers()
127+
}
128+
129+
x, y := window.GetCursorPos()
130+
app.LastCursorX = float32(x)
131+
app.LastCursorY = float32(y)
132+
133+
lastTime := time.Now()
134+
var wasPressed bool
135+
136+
for !window.ShouldClose() {
137+
now := time.Now()
138+
dt := float32(now.Sub(lastTime).Seconds())
139+
lastTime = now
140+
141+
window.PollEvents()
142+
update := update.New(app)
143+
update.UpdateCursor(window)
144+
145+
if key, state, hasKey := window.GetLastKey(); hasKey {
146+
if state == 1 && key == 0xff1b {
147+
if !app.IsExiting {
148+
app.IsExiting = true
149+
app.ExitStartTime = time.Now()
150+
window.DisableInput()
151+
x, y := window.GetCursorPos()
152+
spawn := spawn.New(app)
153+
spawn.SpawnExitWisps(float32(x), float32(y))
154+
}
155+
}
156+
window.ClearLastKey()
157+
}
158+
159+
if app.IsExiting {
160+
if time.Since(app.ExitStartTime).Seconds() > 0.8 {
161+
break
162+
}
163+
}
164+
isPressed := window.GetMouseButton()
165+
if isPressed && !wasPressed {
166+
app.IsDrawing = true
167+
} else if !isPressed && wasPressed {
168+
app.IsDrawing = false
169+
170+
if app.LearnMode && len(app.Points) > 0 {
171+
processed := stroke.ProcessStroke(app.Points)
172+
app.LearnGestures = append(app.LearnGestures, processed)
173+
app.LearnCount++
174+
log.Printf("Captured gesture %d/3", app.LearnCount)
175+
176+
app.Points = nil
177+
178+
if app.LearnCount >= 3 {
179+
if err := gestures.SaveGesture(app.LearnCommand, app.LearnGestures); err != nil {
180+
log.Fatal("Failed to save gesture:", err)
181+
}
182+
log.Printf("Gesture saved for command: %s", app.LearnCommand)
183+
184+
app.IsExiting = true
185+
app.ExitStartTime = time.Now()
186+
window.DisableInput()
187+
x, y := window.GetCursorPos()
188+
spawn := spawn.New(app)
189+
spawn.SpawnExitWisps(float32(x), float32(y))
190+
}
191+
} else if !app.LearnMode && len(app.Points) > 0 {
192+
x, y := window.GetCursorPos()
193+
exec := execute.New(app)
194+
exec.RecognizeAndExecute(window, float32(x), float32(y))
195+
app.Points = nil
196+
}
197+
}
198+
wasPressed = isPressed
199+
200+
if app.IsDrawing {
201+
x, y := window.GetCursorPos()
202+
gesture := gestures.New(app)
203+
gesture.AddPoint(float32(x), float32(y))
204+
205+
spawn := spawn.New(app)
206+
spawn.SpawnCursorSparkles(float32(x), float32(y))
207+
}
208+
209+
update.UpdateParticles(dt)
210+
drawer := draw.New(app)
211+
drawer.Draw(window)
212+
window.SwapBuffers()
213+
}
214+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module hexecute
1+
module github.com/ThatOtherAndrew/Hexecute
22

33
go 1.25.1
44

internal/config/config.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package config
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
)
7+
8+
func GetPath() (string, error) {
9+
homeDir, err := os.UserHomeDir()
10+
if err != nil {
11+
return "", err
12+
}
13+
configDir := filepath.Join(homeDir, ".config", "hexecute")
14+
if err := os.MkdirAll(configDir, 0755); err != nil {
15+
return "", err
16+
}
17+
return filepath.Join(configDir, "gestures.json"), nil
18+
}

0 commit comments

Comments
 (0)