Skip to content

Commit d933e03

Browse files
Kingminer7km7devkammatcool
authored
A few various improvements (#62)
* better keyboard input * Drag button for mobile, fix touch issues in some mods (texture loader drag nodes and qolmod ball), some other minor changes * actually save button position, oops * mobile ime support * minor android fix * hide in game/editor * Fix some indentation/mistakes in spacing * searching (please review i dont trust myself) * style changes and other changes * oops * clamp button position, fix crash --------- Co-authored-by: km7dev <[email protected]> Co-authored-by: kam <[email protected]> Co-authored-by: matcool <[email protected]>
1 parent a18550d commit d933e03

File tree

12 files changed

+451
-42
lines changed

12 files changed

+451
-42
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ endif()
99

1010
project(DevTools VERSION 1.0.0)
1111

12-
file(GLOB_RECURSE SOURCES
12+
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS
1313
src/*.cpp
1414
)
1515

mod.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,10 @@
2626
"description": "Determines if the DevTools should use a custom GD window or not. Required to disable for some exotic configurations (MacOS Wine).",
2727
"default": true
2828
}
29+
},
30+
"resources": {
31+
"sprites": [
32+
"resources/*.png"
33+
]
2934
}
3035
}

resources/devtools.png

6.2 KB
Loading

src/DevTools.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <Geode/loader/Log.hpp>
1010
#include <Geode/loader/Mod.hpp>
1111
#include "ImGui.hpp"
12+
#include "nodes/DragButton.hpp"
1213

1314
template<>
1415
struct matjson::Serialize<Settings> {
@@ -26,7 +27,13 @@ struct matjson::Serialize<Settings> {
2627
.showMemoryViewer = value["show_memory_viewer"].asBool().unwrapOr(std::move(defaults.showMemoryViewer)),
2728
.showModGraph = value["show_mod_graph"].asBool().unwrapOr(std::move(defaults.showModGraph)),
2829
.theme = value["theme"].asString().unwrapOr(std::move(defaults.theme)),
29-
.themeColor = value["theme_color"].as<ccColor4B>().isOk() ? value["theme_color"].as<ccColor4B>().unwrap() : std::move(defaults.themeColor)
30+
.themeColor = value["theme_color"].as<ccColor4B>().isOk() ? value["theme_color"].as<ccColor4B>().unwrap() : std::move(defaults.themeColor),
31+
.buttonPos = CCPoint{
32+
value["button_x"].as<float>().isOk() ? value["button_x"].as<float>().unwrap() : std::move(defaults.buttonPos.x),
33+
value["button_y"].as<float>().isOk() ? value["button_y"].as<float>().unwrap() : std::move(defaults.buttonPos.y)
34+
},
35+
.buttonInEditor = value["button_editor"].asBool().isOk() ? value["button_editor"].asBool().unwrap() : std::move(defaults.buttonInEditor),
36+
.buttonInGame = value["button_game"].asBool().isOk() ? value["button_game"].asBool().unwrap() : std::move(defaults.buttonInGame)
3037
});
3138
}
3239

@@ -43,6 +50,10 @@ struct matjson::Serialize<Settings> {
4350
{ "show_mod_graph", settings.showModGraph },
4451
{ "theme", settings.theme },
4552
{ "theme_color", settings.themeColor },
53+
{ "button_x", settings.buttonPos.x },
54+
{ "button_y", settings.buttonPos.y },
55+
{ "button_editor", settings.buttonInEditor },
56+
{ "button_game", settings.buttonInGame },
4657
});
4758
}
4859
};
@@ -55,7 +66,10 @@ DevTools* DevTools::get() {
5566
}
5667

5768
void DevTools::loadSettings() { m_settings = Mod::get()->getSavedValue<Settings>("settings"); }
58-
void DevTools::saveSettings() { Mod::get()->setSavedValue("settings", m_settings); }
69+
void DevTools::saveSettings() {
70+
m_settings.buttonPos = DragButton::get()->getPosition();
71+
Mod::get()->setSavedValue("settings", m_settings);
72+
}
5973
Settings DevTools::getSettings() { return m_settings; }
6074

6175
bool DevTools::shouldPopGame() const {

src/DevTools.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ struct Settings {
2929
bool showModGraph = false;
3030
std::string theme = DARK_THEME;
3131
ccColor4B themeColor = {2, 119, 189, 255};
32+
CCPoint buttonPos = {50, 50};
33+
bool buttonInEditor = false;
34+
bool buttonInGame = false;
3235
};
3336

3437
class DevTools {
@@ -49,6 +52,9 @@ class DevTools {
4952
Ref<CCNode> m_selectedNode;
5053
std::vector<std::pair<CCNode*, HighlightMode>> m_toHighlight;
5154
std::vector<std::function<void(CCNode*)>> m_customCallbacks;
55+
std::string m_searchQuery;
56+
std::string m_prevQuery;
57+
std::unordered_map<CCNode*, bool> m_nodeOpen;
5258

5359
void setupFonts();
5460
void setupPlatform();
@@ -84,6 +90,8 @@ class DevTools {
8490
void renderDrawData(ImDrawData*);
8591
void renderDrawDataFallback(ImDrawData*);
8692

93+
bool searchBranch(CCNode* node);
94+
8795
bool hasExtension(const std::string& ext) const;
8896

8997
DevTools() { loadSettings(); }

src/backend.cpp

Lines changed: 191 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#include <cocos2d.h>
22
#include <Geode/modify/CCTouchDispatcher.hpp>
33
#include <Geode/modify/CCMouseDispatcher.hpp>
4+
#include <Geode/modify/CCKeyboardDispatcher.hpp>
45
#include <Geode/modify/CCIMEDispatcher.hpp>
6+
#include "Geode/cocos/text_input_node/CCIMEDelegate.h"
7+
#include "Geode/platform/cplatform.h"
58
#include "platform/platform.hpp"
69
#include "DevTools.hpp"
710
#include "ImGui.hpp"
@@ -66,6 +69,65 @@ void DevTools::setupPlatform() {
6669
#endif
6770
}
6871

72+
#ifdef GEODE_IS_MOBILE
73+
74+
class DevToolsIMEDelegate : public CCIMEDelegate {
75+
protected:
76+
bool m_attached = false;
77+
std::string m_text;
78+
public:
79+
bool attachWithIME() override {
80+
if (CCIMEDelegate::attachWithIME()) {
81+
// being anywhere but end of line ends up messing up the text, so this sends it to the end of the line
82+
#ifdef GEODE_IS_ANDROID
83+
ImGui::GetIO().AddKeyEvent(ImGuiKey_End, true);
84+
ImGui::GetIO().AddKeyEvent(ImGuiKey_End, false);
85+
#endif
86+
m_attached = true;
87+
CCEGLView::get()->setIMEKeyboardState(true);
88+
return true;
89+
}
90+
return false;
91+
}
92+
93+
bool detachWithIME() override {
94+
if (CCIMEDelegate::detachWithIME()) {
95+
m_attached = false;
96+
CCEGLView::get()->setIMEKeyboardState(false);
97+
ImGui::ClearActiveID();
98+
return true;
99+
}
100+
return false;
101+
}
102+
103+
bool canAttachWithIME() override {
104+
return true;
105+
}
106+
107+
bool canDetachWithIME() override {
108+
return true;
109+
}
110+
111+
char const* getContentText() override {
112+
m_text = "";
113+
for (auto str : ImGui::GetInputTextState(ImGui::GetFocusID())->TextA) {
114+
m_text += str;
115+
}
116+
return m_text.c_str();
117+
}
118+
119+
bool isAttached() {
120+
return m_attached;
121+
}
122+
123+
static DevToolsIMEDelegate* get() {
124+
static DevToolsIMEDelegate* instance = new DevToolsIMEDelegate();
125+
return instance;
126+
}
127+
};
128+
129+
#endif
130+
69131
void DevTools::newFrame() {
70132
auto& io = ImGui::GetIO();
71133

@@ -94,6 +156,15 @@ void DevTools::newFrame() {
94156
io.KeyAlt = kb->getAltKeyPressed() || kb->getCommandKeyPressed(); // look
95157
io.KeyCtrl = kb->getControlKeyPressed();
96158
io.KeyShift = kb->getShiftKeyPressed();
159+
160+
#ifdef GEODE_IS_MOBILE
161+
auto ime = DevToolsIMEDelegate::get();
162+
if (io.WantTextInput && !ime->isAttached()) {
163+
ime->attachWithIME();
164+
} else if (!io.WantTextInput && ime->isAttached()) {
165+
ime->detachWithIME();
166+
}
167+
#endif
97168
}
98169

99170
void DevTools::render(GLRenderCtx* ctx) {
@@ -278,6 +349,18 @@ class $modify(CCMouseDispatcher) {
278349
#endif
279350

280351
class $modify(CCTouchDispatcher) {
352+
static void onModify(auto& self) {
353+
/*
354+
* some mods hook this instead of using normal touch delegates for some reason
355+
* for example QOLMod, even in the rewrite
356+
* so i added hook priority
357+
*/
358+
Result<> res = self.setHookPriorityPre("cocos2d::CCTouchDispatcher::touches", Priority::First);
359+
if (!res) {
360+
geode::log::warn("Failed to set hook priority for CCTouchDispatcher::touches: {}", res.unwrapErr());
361+
}
362+
}
363+
281364
void touches(CCSet* touches, CCEvent* event, unsigned int type) {
282365
auto& io = ImGui::GetIO();
283366
auto* touch = static_cast<CCTouch*>(touches->anyObject());
@@ -290,6 +373,7 @@ class $modify(CCTouchDispatcher) {
290373
}
291374

292375
const auto pos = toVec2(touch->getLocation());
376+
GEODE_MOBILE(io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);)
293377
io.AddMousePosEvent(pos.x, pos.y);
294378
if (io.WantCaptureMouse) {
295379
bool didGDSwallow = false;
@@ -306,7 +390,12 @@ class $modify(CCTouchDispatcher) {
306390
auto y = (1.f - relativePos.y / gdRect.GetHeight()) * win.y;
307391

308392
auto pos = toCocos(ImVec2(x, y));
309-
touch->setTouchInfo(touch->getID(), pos.x, pos.y);
393+
// setTouchInfo messes up the previous location (causes issues like texturer loader's draggable nodes breaking)
394+
touch->m_point = pos;
395+
if (type == CCTOUCHBEGAN) {
396+
// makes the start location in the touch correct
397+
touch->m_startPoint = pos;
398+
}
310399
CCTouchDispatcher::touches(touches, event, type);
311400

312401
ImGui::SetWindowFocus("Geometry Dash");
@@ -318,6 +407,7 @@ class $modify(CCTouchDispatcher) {
318407
// TODO: dragging out of gd makes it click in imgui
319408
if (!didGDSwallow) {
320409
if (type == CCTOUCHBEGAN || type == CCTOUCHMOVED) {
410+
GEODE_MOBILE(io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);)
321411
io.AddMouseButtonEvent(0, true);
322412
}
323413
else {
@@ -356,3 +446,103 @@ class $modify(CCIMEDispatcher) {
356446
io.AddKeyEvent(ImGuiKey_Backspace, false);
357447
}
358448
};
449+
450+
ImGuiKey cocosToImGuiKey(cocos2d::enumKeyCodes key) {
451+
if (key >= KEY_A && key <= KEY_Z) {
452+
return static_cast<ImGuiKey>(ImGuiKey_A + (key - KEY_A));
453+
}
454+
if (key >= KEY_Zero && key <= KEY_Nine) {
455+
return static_cast<ImGuiKey>(ImGuiKey_0 + (key - KEY_Zero));
456+
}
457+
switch (key) {
458+
case KEY_Up: return ImGuiKey_UpArrow;
459+
case KEY_Down: return ImGuiKey_DownArrow;
460+
case KEY_Left: return ImGuiKey_LeftArrow;
461+
case KEY_Right: return ImGuiKey_RightArrow;
462+
463+
case KEY_Control: return ImGuiKey_ModCtrl;
464+
case KEY_LeftWindowsKey: return ImGuiKey_ModSuper;
465+
case KEY_Shift: return ImGuiKey_ModShift;
466+
case KEY_Alt: return ImGuiKey_ModAlt;
467+
case KEY_Enter: return ImGuiKey_Enter;
468+
469+
case KEY_Home: return ImGuiKey_Home;
470+
case KEY_End: return ImGuiKey_End;
471+
// macos uses delete instead of backspace for some reason
472+
#ifndef GEODE_IS_MACOS
473+
case KEY_Delete: return ImGuiKey_Delete;
474+
#endif
475+
case KEY_Escape: return ImGuiKey_Escape;
476+
477+
// KEY_Control and KEY_Shift aren't called on android like windows or mac
478+
#ifdef GEODE_IS_ANDROID
479+
case KEY_LeftControl: return ImGuiKey_ModCtrl;
480+
case KEY_RightContol: return ImGuiKey_ModCtrl;
481+
case KEY_LeftShift: return ImGuiKey_ModShift;
482+
case KEY_RightShift: return ImGuiKey_ModShift;
483+
#endif
484+
485+
default: return ImGuiKey_None;
486+
}
487+
}
488+
489+
class $modify(CCKeyboardDispatcher) {
490+
bool dispatchKeyboardMSG(enumKeyCodes key, bool down, bool repeat) {
491+
auto& io = ImGui::GetIO();
492+
const auto imKey = cocosToImGuiKey(key);
493+
if (imKey != ImGuiKey_None) {
494+
io.AddKeyEvent(imKey, down);
495+
}
496+
497+
// CCIMEDispatcher stuff only gets called on mobile if the virtual keyboard would be up.
498+
// Similarly, CCKeyboardDispatcher doesn't get called if the virtual keyboard would be up.
499+
#ifdef GEODE_IS_MOBILE
500+
if (down) {
501+
char c = 0;
502+
if (key >= KEY_A && key <= KEY_Z) {
503+
c = static_cast<char>(key);
504+
if (!io.KeyShift) {
505+
c = static_cast<char>(tolower(c));
506+
}
507+
} else if (key >= KEY_Zero && key <= KEY_Nine) {
508+
c = static_cast<char>('0' + (key - KEY_Zero));
509+
} else if (key == KEY_Space) {
510+
c = ' ';
511+
}
512+
513+
if (c != 0) {
514+
std::string str(1, c);
515+
io.AddInputCharactersUTF8(str.c_str());
516+
}
517+
}
518+
if (key == KEY_Backspace) {
519+
io.AddKeyEvent(ImGuiKey_Backspace, true);
520+
io.AddKeyEvent(ImGuiKey_Backspace, false);
521+
}
522+
#endif
523+
524+
if (io.WantCaptureKeyboard) {
525+
return false;
526+
} else {
527+
return CCKeyboardDispatcher::dispatchKeyboardMSG(key, down, repeat);
528+
}
529+
}
530+
531+
#if defined(GEODE_IS_MACOS) || defined(GEODE_IS_IOS)
532+
static void onModify(auto& self) {
533+
Result<> res = self.setHookPriorityBeforePre("CCKeyboardDispatcher::updateModifierKeys", "geode.custom-keybinds");
534+
if (!res) {
535+
geode::log::warn("Failed to set hook priority for CCKeyboardDispatcher::updateModifierKeys: {}", res.unwrapErr());
536+
}
537+
}
538+
539+
void updateModifierKeys(bool shft, bool ctrl, bool alt, bool cmd) {
540+
auto& io = ImGui::GetIO();
541+
io.AddKeyEvent(ImGuiKey_ModShift, shft);
542+
io.AddKeyEvent(ImGuiKey_ModCtrl, ctrl);
543+
io.AddKeyEvent(ImGuiKey_ModAlt, alt);
544+
io.AddKeyEvent(ImGuiKey_ModSuper, cmd);
545+
CCKeyboardDispatcher::updateModifierKeys(shft, ctrl, alt, cmd);
546+
}
547+
#endif
548+
};

0 commit comments

Comments
 (0)