Parcourir la source

Merge pull request #108624 from bruvzg/mac_emb

[macOS] Fix mouse enter/exit event and custom cursor shape in embedded game mode.
Thaddeus Crews il y a 3 mois
Parent
commit
ca374f91a2

+ 8 - 1
platform/macos/display_server_embedded.mm

@@ -811,7 +811,14 @@ DisplayServer::CursorShape DisplayServerEmbedded::cursor_get_shape() const {
 }
 
 void DisplayServerEmbedded::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
-	WARN_PRINT_ONCE("Custom cursor images are not supported in embedded mode.");
+	PackedByteArray data;
+	if (p_cursor.is_valid()) {
+		Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
+		if (image.is_valid()) {
+			data = image->save_png_to_buffer();
+		}
+	}
+	EngineDebugger::get_singleton()->send_message("game_view:cursor_set_custom_image", { data, p_shape, p_hotspot });
 }
 
 void DisplayServerEmbedded::swap_buffers() {

+ 1 - 0
platform/macos/editor/embedded_game_view_plugin.h

@@ -52,6 +52,7 @@ class GameViewDebuggerMacOS : public GameViewDebugger {
 
 	bool _msg_set_context_id(const Array &p_args);
 	bool _msg_cursor_set_shape(const Array &p_args);
+	bool _msg_cursor_set_custom_image(const Array &p_args);
 	bool _msg_mouse_set_mode(const Array &p_args);
 	bool _msg_window_set_ime_active(const Array &p_args);
 	bool _msg_window_set_ime_position(const Array &p_args);

+ 18 - 0
platform/macos/editor/embedded_game_view_plugin.mm

@@ -53,6 +53,23 @@ bool GameViewDebuggerMacOS::_msg_cursor_set_shape(const Array &p_args) {
 	return true;
 }
 
+bool GameViewDebuggerMacOS::_msg_cursor_set_custom_image(const Array &p_args) {
+	ERR_FAIL_COND_V_MSG(p_args.size() != 3, false, "cursor_set_custom_image: invalid number of arguments");
+
+	Ref<Image> image;
+	image.instantiate();
+	PackedByteArray cursor_data = p_args[0];
+	if (!cursor_data.is_empty()) {
+		image->load_png_from_buffer(cursor_data);
+	}
+	DisplayServer::CursorShape shape = DisplayServer::CursorShape(p_args[1]);
+	Vector2 hotspot = p_args[2];
+
+	embedded_process->get_layer_host()->cursor_set_custom_image(image, shape, hotspot);
+
+	return true;
+}
+
 bool GameViewDebuggerMacOS::_msg_mouse_set_mode(const Array &p_args) {
 	ERR_FAIL_COND_V_MSG(p_args.size() != 1, false, "mouse_set_mode: invalid number of arguments");
 
@@ -102,6 +119,7 @@ bool GameViewDebuggerMacOS::_msg_joy_stop(const Array &p_args) {
 void GameViewDebuggerMacOS::_init_capture_message_handlers() {
 	parse_message_handlers["game_view:set_context_id"] = &GameViewDebuggerMacOS::_msg_set_context_id;
 	parse_message_handlers["game_view:cursor_set_shape"] = &GameViewDebuggerMacOS::_msg_cursor_set_shape;
+	parse_message_handlers["game_view:cursor_set_custom_image"] = &GameViewDebuggerMacOS::_msg_cursor_set_custom_image;
 	parse_message_handlers["game_view:mouse_set_mode"] = &GameViewDebuggerMacOS::_msg_mouse_set_mode;
 	parse_message_handlers["game_view:window_set_ime_active"] = &GameViewDebuggerMacOS::_msg_window_set_ime_active;
 	parse_message_handlers["game_view:window_set_ime_position"] = &GameViewDebuggerMacOS::_msg_window_set_ime_position;

+ 12 - 0
platform/macos/editor/embedded_process_macos.h

@@ -41,12 +41,24 @@ class LayerHost final : public Control {
 	ScriptEditorDebugger *script_debugger = nullptr;
 	EmbeddedProcessMacOS *process = nullptr;
 
+	struct CustomCursor {
+		Ref<Image> image;
+		Vector2 hotspot;
+		CustomCursor() {}
+		CustomCursor(const Ref<Image> &p_image, const Vector2 &p_hotspot) {
+			image = p_image;
+			hotspot = p_hotspot;
+		}
+	};
+	HashMap<DisplayServer::CursorShape, CustomCursor> custom_cursors;
+
 	virtual void gui_input(const Ref<InputEvent> &p_event) override;
 
 protected:
 	void _notification(int p_what);
 
 public:
+	void cursor_set_custom_image(const Ref<Image> &p_image, DisplayServer::CursorShape p_shape, const Vector2 &p_hotspot);
 	void set_script_debugger(ScriptEditorDebugger *p_debugger) {
 		script_debugger = p_debugger;
 	}

+ 27 - 2
platform/macos/editor/embedded_process_macos.mm

@@ -233,10 +233,16 @@ EmbeddedProcessMacOS::~EmbeddedProcessMacOS() {
 
 void LayerHost::_notification(int p_what) {
 	switch (p_what) {
-		case NOTIFICATION_FOCUS_ENTER: {
+		case NOTIFICATION_MOUSE_ENTER: {
+			DisplayServer *ds = DisplayServer::get_singleton();
+			for (const KeyValue<DisplayServer::CursorShape, CustomCursor> &E : custom_cursors) {
+				ds->cursor_set_custom_image(E.value.image, E.key, E.value.hotspot);
+			}
 			if (script_debugger) {
 				script_debugger->send_message("embed:win_event", { DisplayServer::WINDOW_EVENT_MOUSE_ENTER });
 			}
+		} break;
+		case NOTIFICATION_FOCUS_ENTER: {
 			// Restore mouse capture, if necessary.
 			DisplayServer *ds = DisplayServer::get_singleton();
 			if (process->get_mouse_mode() != ds->mouse_get_mode()) {
@@ -244,10 +250,16 @@ void LayerHost::_notification(int p_what) {
 				ds->mouse_set_mode(process->get_mouse_mode());
 			}
 		} break;
-		case NOTIFICATION_FOCUS_EXIT: {
+		case NOTIFICATION_MOUSE_EXIT: {
+			DisplayServer *ds = DisplayServer::get_singleton();
+			for (int i = 0; i < DisplayServer::CURSOR_MAX; i++) {
+				ds->cursor_set_custom_image(Ref<Resource>(), (DisplayServer::CursorShape)i, Vector2());
+			}
 			if (script_debugger) {
 				script_debugger->send_message("embed:win_event", { DisplayServer::WINDOW_EVENT_MOUSE_EXIT });
 			}
+		} break;
+		case NOTIFICATION_FOCUS_EXIT: {
 			// Temporarily set mouse state back to visible, so the user can interact with the editor.
 			DisplayServer *ds = DisplayServer::get_singleton();
 			if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_VISIBLE) {
@@ -261,9 +273,22 @@ void LayerHost::_notification(int p_what) {
 				script_debugger->send_message("embed:ime_update", { ime_text, ime_selection });
 			}
 		} break;
+		case NOTIFICATION_EXIT_TREE:
+		case NOTIFICATION_VISIBILITY_CHANGED: {
+			if (!is_visible_in_tree()) {
+				DisplayServer *ds = DisplayServer::get_singleton();
+				for (int i = 0; i < DisplayServer::CURSOR_MAX; i++) {
+					ds->cursor_set_custom_image(Ref<Resource>(), (DisplayServer::CursorShape)i, Vector2());
+				}
+			}
+		} break;
 	}
 }
 
+void LayerHost::cursor_set_custom_image(const Ref<Image> &p_image, DisplayServer::CursorShape p_shape, const Vector2 &p_hotspot) {
+	custom_cursors[p_shape] = CustomCursor(p_image, p_hotspot);
+}
+
 void LayerHost::gui_input(const Ref<InputEvent> &p_event) {
 	if (!process->is_embedding_completed()) {
 		return;