summaryrefslogtreecommitdiffstats
path: root/src/menu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/menu.cpp')
-rw-r--r--src/menu.cpp133
1 files changed, 47 insertions, 86 deletions
diff --git a/src/menu.cpp b/src/menu.cpp
index c62db47..6dccf1c 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -26,55 +26,6 @@ void init_conmsg() {
26 if (h) 26 if (h)
27 g_conmsg = (decltype(g_conmsg))dlsym(h, "_Z6ConMsgPKcz"); 27 g_conmsg = (decltype(g_conmsg))dlsym(h, "_Z6ConMsgPKcz");
28} 28}
29
30// ---------------------------------------------------------------------------
31// X11 middle mouse (for climb feature)
32// ---------------------------------------------------------------------------
33
34static struct {
35 void *handle = nullptr;
36 void *dpy = nullptr;
37 int (*query)(void *, unsigned long, unsigned long *, unsigned long *, int *,
38 int *, int *, int *, unsigned int *) = nullptr;
39 int (*default_screen)(void *) = nullptr;
40 unsigned long (*root_window)(void *, int) = nullptr;
41 bool ok = false;
42} g_x11;
43
44static constexpr unsigned int BUTTON2_MASK = 1u << 9; // X11 Button2Mask
45
46void init_x11() {
47 g_x11.handle = dlopen("libX11.so.6", RTLD_LAZY | RTLD_GLOBAL);
48 if (!g_x11.handle)
49 return;
50 g_x11.query = (decltype(g_x11.query))dlsym(g_x11.handle, "XQueryPointer");
51 g_x11.default_screen =
52 (decltype(g_x11.default_screen))dlsym(g_x11.handle, "XDefaultScreen");
53 g_x11.root_window =
54 (decltype(g_x11.root_window))dlsym(g_x11.handle, "XRootWindow");
55 auto open_display =
56 (void *(*)(const char *))dlsym(g_x11.handle, "XOpenDisplay");
57 if (!g_x11.query || !g_x11.default_screen || !g_x11.root_window ||
58 !open_display)
59 return;
60 g_x11.dpy = open_display(nullptr);
61 if (g_x11.dpy)
62 g_x11.ok = true;
63}
64
65bool middle_mouse_down() {
66 if (!g_x11.ok)
67 return false;
68 unsigned long root =
69 g_x11.root_window(g_x11.dpy, g_x11.default_screen(g_x11.dpy));
70 unsigned long rret, cret;
71 int rx, ry, wx, wy;
72 unsigned int mask = 0;
73 if (!g_x11.query(g_x11.dpy, root, &rret, &cret, &rx, &ry, &wx, &wy, &mask))
74 return false;
75 return (mask & BUTTON2_MASK) != 0;
76}
77
78// --------------------------------------------------------------------------- 29// ---------------------------------------------------------------------------
79// menu tree structure 30// menu tree structure
80// --------------------------------------------------------------------------- 31// ---------------------------------------------------------------------------
@@ -100,15 +51,11 @@ struct FeatureState {
100 int bind; // SDL scancode, 0 = none 51 int bind; // SDL scancode, 0 = none
101}; 52};
102 53
103static FeatureState g_climb{true, 0};
104static FeatureState g_bhop{true, 0}; 54static FeatureState g_bhop{true, 0};
105static FeatureState g_abh{true, 0}; 55static FeatureState g_abh{true, 0};
106 56
107// tree 57// tree
108static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr}; 58static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr};
109static MenuNode g_climb_feat{NODE_FEATURE, "Climb", true, 2, {}, nullptr, nullptr, nullptr};
110static MenuNode g_climb_active{NODE_TOGGLE, "Active", false, 0, {}, &g_climb.active, nullptr, nullptr};
111static MenuNode g_climb_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_climb.bind, "None"};
112static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr}; 59static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr};
113static MenuNode g_bhop_active{NODE_TOGGLE, "Active", false, 0, {}, &g_bhop.active, nullptr, nullptr}; 60static MenuNode g_bhop_active{NODE_TOGGLE, "Active", false, 0, {}, &g_bhop.active, nullptr, nullptr};
114static MenuNode g_abh_feat{NODE_FEATURE, "ABH", true, 1, {}, nullptr, nullptr, nullptr}; 61static MenuNode g_abh_feat{NODE_FEATURE, "ABH", true, 1, {}, nullptr, nullptr, nullptr};
@@ -123,14 +70,11 @@ bool g_menu_open = false;
123static bool g_bind_mode = false; // true = waiting for key press 70static bool g_bind_mode = false; // true = waiting for key press
124 71
125static void build_tree() { 72static void build_tree() {
126 g_climb_feat.children[0] = &g_climb_active;
127 g_climb_feat.children[1] = &g_climb_bind;
128 g_bhop_feat.children[0] = &g_bhop_active; 73 g_bhop_feat.children[0] = &g_bhop_active;
129 g_abh_feat.children[0] = &g_abh_active; 74 g_abh_feat.children[0] = &g_abh_active;
130 g_root.children[0] = &g_climb_feat; 75 g_root.children[0] = &g_bhop_feat;
131 g_root.children[1] = &g_bhop_feat; 76 g_root.children[1] = &g_abh_feat;
132 g_root.children[2] = &g_abh_feat; 77 g_root.child_count = 2;
133 g_root.child_count = 3;
134} 78}
135 79
136static int g_depth[16]; // depth of each visible row (for indentation) 80static int g_depth[16]; // depth of each visible row (for indentation)
@@ -190,7 +134,6 @@ static void config_save() {
190 FILE *f = fopen(config_path().c_str(), "w"); 134 FILE *f = fopen(config_path().c_str(), "w");
191 if (!f) 135 if (!f)
192 return; 136 return;
193 fprintf(f, "[climb]\nactive=%d\nbind=%d\n", g_climb.active, g_climb.bind);
194 fprintf(f, "[bhop]\nactive=%d\nbind=%d\n", g_bhop.active, g_bhop.bind); 137 fprintf(f, "[bhop]\nactive=%d\nbind=%d\n", g_bhop.active, g_bhop.bind);
195 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); 138 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind);
196 fclose(f); 139 fclose(f);
@@ -205,9 +148,7 @@ static void config_load() {
205 while (fgets(line, sizeof(line), f)) { 148 while (fgets(line, sizeof(line), f)) {
206 line[strcspn(line, "\r\n")] = 0; 149 line[strcspn(line, "\r\n")] = 0;
207 if (line[0] == '[') { 150 if (line[0] == '[') {
208 if (strstr(line, "[climb]")) 151 if (strstr(line, "[bhop]"))
209 cur = &g_climb;
210 else if (strstr(line, "[bhop]"))
211 cur = &g_bhop; 152 cur = &g_bhop;
212 else if (strstr(line, "[abh]")) 153 else if (strstr(line, "[abh]"))
213 cur = &g_abh; 154 cur = &g_abh;
@@ -265,18 +206,42 @@ static const char *scancode_name(int sc) {
265 case 87: return "F1"; case 88: return "F2"; case 89: return "F3"; 206 case 87: return "F1"; case 88: return "F2"; case 89: return "F3";
266 case 90: return "F4"; case 91: return "F5"; case 92: return "F6"; 207 case 90: return "F4"; case 91: return "F5"; case 92: return "F6";
267 case 93: return "F7"; case 94: return "F8"; 208 case 93: return "F7"; case 94: return "F8";
209 case 600: return "MouseL"; case 601: return "MouseR";
210 case 602: return "MouseM"; case 603: return "Mouse4";
211 case 604: return "Mouse5";
268 default: return scancode_name(0); // "None" for unmapped 212 default: return scancode_name(0); // "None" for unmapped
269 } 213 }
270} 214}
271 215
272// get a snapshot of key states: returns array of currently-held scancodes 216// get a snapshot of key states: returns array of currently-held scancodes
273static bool g_prev_key_state[512] = {}; 217static bool g_prev_key_state[608] = {};
274static bool g_key_down[512] = {}; // true for ONE frame on press 218static bool g_key_down[608] = {}; // true for ONE frame on press
275 219
276// read SDL_GetKeyboardState — the game's own SDL is in-process 220// read SDL_GetKeyboardState — the game's own SDL is in-process
277using SDL_GetKeyboardState_fn = const uint8_t *(*)(int *); 221using SDL_GetKeyboardState_fn = const uint8_t *(*)(int *);
278static SDL_GetKeyboardState_fn SDL_GetKeyboardState_real = nullptr; 222static SDL_GetKeyboardState_fn SDL_GetKeyboardState_real = nullptr;
279 223
224// mouse buttons map to pseudo-scancodes 600..604
225static constexpr int MOUSE_BASE = 600; // 600=L 601=R 602=M 603=X1 604=X2
226using SDL_GetMouseState_fn = unsigned (*)(int *, int *);
227static SDL_GetMouseState_fn SDL_GetMouseState_real = nullptr;
228
229static void poll_mouse() {
230 if (!SDL_GetMouseState_real)
231 SDL_GetMouseState_real =
232 (SDL_GetMouseState_fn)dlsym(RTLD_DEFAULT, "SDL_GetMouseState");
233 if (!SDL_GetMouseState_real)
234 return;
235 int mx, my;
236 unsigned mask = SDL_GetMouseState_real(&mx, &my);
237 for (int b = 0; b < 5; b++) {
238 bool down = (mask & (1u << b)) != 0; // SDL buttons 1..5 = bits 0..4
239 int sc = MOUSE_BASE + b;
240 g_key_down[sc] = down && !g_prev_key_state[sc];
241 g_prev_key_state[sc] = down;
242 }
243}
244
280static void poll_keyboard() { 245static void poll_keyboard() {
281 if (!SDL_GetKeyboardState_real) 246 if (!SDL_GetKeyboardState_real)
282 SDL_GetKeyboardState_real = 247 SDL_GetKeyboardState_real =
@@ -285,36 +250,32 @@ static void poll_keyboard() {
285 return; 250 return;
286 int numkeys = 0; 251 int numkeys = 0;
287 const uint8_t *state = SDL_GetKeyboardState_real(&numkeys); 252 const uint8_t *state = SDL_GetKeyboardState_real(&numkeys);
288 if (!state) 253 if (state)
289 return; 254 for (int i = 0; i < numkeys && i < MOUSE_BASE; i++) {
290 for (int i = 0; i < numkeys && i < 512; i++) { 255 g_key_down[i] = state[i] && !g_prev_key_state[i];
291 g_key_down[i] = state[i] && !g_prev_key_state[i]; 256 g_prev_key_state[i] = state[i];
292 g_prev_key_state[i] = state[i]; 257 }
293 } 258 poll_mouse();
294} 259}
295 260
296static bool key_pressed(int sc) { 261static bool key_pressed(int sc) {
297 return sc >= 0 && sc < 512 && g_key_down[sc]; 262 return sc >= 0 && sc < MOUSE_BASE + 5 && g_key_down[sc];
298} 263}
299 264
300[[maybe_unused]] static bool key_held(int sc) { 265[[maybe_unused]] static bool key_held(int sc) {
301 return sc >= 0 && sc < 512 && g_prev_key_state[sc]; 266 return sc >= 0 && sc < MOUSE_BASE + 5 && g_prev_key_state[sc];
302} 267}
303 268
304// feature gate queried from hl2h.cpp do_move(): feature must be Active AND 269// feature gate queried from hl2h.cpp do_move(): feature must be Active AND
305// the activation condition met. Climb activates on its bind key held (falls 270// its bind key held (always-on when unbound).
306// back to the historic middle-mouse behavior when unbound); other features
307// activate on their bind key held, or are always-on when unbound.
308bool feature_active(int feature) { 271bool feature_active(int feature) {
309 static FeatureState *feats[3] = {&g_climb, &g_bhop, &g_abh}; 272 static FeatureState *feats[2] = {&g_bhop, &g_abh};
310 if (feature < 0 || feature > 2) 273 if (feature < 0 || feature > 1)
311 return false; 274 return false;
312 FeatureState *f = feats[feature]; 275 FeatureState *f = feats[feature];
313 if (!f->active) 276 if (!f->active)
314 return false; 277 return false;
315 if (f->bind == 0) 278 return f->bind == 0 || key_held(f->bind);
316 return feature == FEAT_CLIMB ? middle_mouse_down() : true;
317 return key_held(f->bind);
318} 279}
319 280
320static void menu_handle_input() { 281static void menu_handle_input() {
@@ -333,7 +294,7 @@ static void menu_handle_input() {
333 // menu is open 294 // menu is open
334 if (g_bind_mode) { 295 if (g_bind_mode) {
335 // wait for any key press (except Insert, Up, Down, Escape, Enter) 296 // wait for any key press (except Insert, Up, Down, Escape, Enter)
336 for (int i = 0; i < 512; i++) { 297 for (int i = 0; i < MOUSE_BASE + 5; i++) {
337 if (!g_key_down[i]) 298 if (!g_key_down[i])
338 continue; 299 continue;
339 if (i == SCAN_INSERT || i == SCAN_UP || i == SCAN_DOWN || 300 if (i == SCAN_INSERT || i == SCAN_UP || i == SCAN_DOWN ||
@@ -359,7 +320,7 @@ static void menu_handle_input() {
359 MenuNode *n = g_visible[g_selected]; 320 MenuNode *n = g_visible[g_selected];
360 if (n->bind_ptr) { 321 if (n->bind_ptr) {
361 // clear same bind from other features 322 // clear same bind from other features
362 FeatureState *features[] = {&g_climb, &g_bhop, &g_abh}; 323 FeatureState *features[] = {&g_bhop, &g_abh};
363 for (auto *f : features) 324 for (auto *f : features)
364 if (&f->bind != n->bind_ptr && f->bind == i) 325 if (&f->bind != n->bind_ptr && f->bind == i)
365 f->bind = 0; 326 f->bind = 0;
@@ -549,10 +510,10 @@ void outer_draw() {
549 draw_text(200, 10 + i * 20, "[press key]"); 510 draw_text(200, 10 + i * 20, "[press key]");
550 else { 511 else {
551 /* stable name for current bind */ 512 /* stable name for current bind */
552 static char bn[3][32]; 513 static char bn[2][32];
553 static FeatureState *feats[] = {&g_climb, &g_bhop, &g_abh}; 514 static FeatureState *feats[] = {&g_bhop, &g_abh};
554 int fi = 0; 515 int fi = 0;
555 for (int k = 0; k < 3; k++) 516 for (int k = 0; k < 2; k++)
556 if (n->bind_ptr == &feats[k]->bind) 517 if (n->bind_ptr == &feats[k]->bind)
557 fi = k; 518 fi = k;
558 snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr)); 519 snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr));