// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #include "ScreenUtilities.h" #include "Engine/Core/Math/Vector2.h" #include "Engine/Core/Delegate.h" #include "Engine/Core/Log.h" #include "Engine/Profiler/ProfilerCPU.h" Delegate ScreenUtilities::PickColorDone; #if PLATFORM_WINDOWS #include #pragma comment(lib, "Gdi32.lib") static HHOOK MouseCallbackHook; LRESULT CALLBACK OnScreenUtilsMouseCallback(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam) { if (nCode >= 0 && wParam == WM_LBUTTONDOWN) { UnhookWindowsHookEx(MouseCallbackHook); // Push event with the picked color const Float2 cursorPos = Platform::GetMousePosition(); const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos); ScreenUtilities::PickColorDone(colorPicked); return 1; } return CallNextHookEx(NULL, nCode, wParam, lParam); } Color32 ScreenUtilities::GetColorAt(const Float2& pos) { PROFILE_CPU(); HDC deviceContext = GetDC(NULL); COLORREF color = GetPixel(deviceContext, (int)pos.X, (int)pos.Y); ReleaseDC(NULL, deviceContext); return Color32(GetRValue(color), GetGValue(color), GetBValue(color), 255); } void ScreenUtilities::PickColor() { MouseCallbackHook = SetWindowsHookEx(WH_MOUSE_LL, OnScreenUtilsMouseCallback, NULL, NULL); if (MouseCallbackHook == NULL) { LOG(Warning, "Failed to set mouse hook."); LOG(Warning, "Error: {0}", GetLastError()); } } #elif PLATFORM_LINUX #include "Engine/Platform/Linux/LinuxPlatform.h" #include "Engine/Platform/Linux/IncludeX11.h" Color32 ScreenUtilities::GetColorAt(const Float2& pos) { X11::XColor color; X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay(); int defaultScreen = X11::XDefaultScreen(display); X11::XImage* image; image = X11::XGetImage(display, X11::XRootWindow(display, defaultScreen), (int)pos.X, (int)pos.Y, 1, 1, AllPlanes, XYPixmap); color.pixel = XGetPixel(image, 0, 0); X11::XFree(image); X11::XQueryColor(display, X11::XDefaultColormap(display, defaultScreen), &color); Color32 outputColor; outputColor.R = color.red / 256; outputColor.G = color.green / 256; outputColor.B = color.blue / 256; outputColor.A = 255; return outputColor; } void OnScreenUtilsXEventCallback(void* eventPtr) { X11::XEvent* event = (X11::XEvent*) eventPtr; X11::Display* display = (X11::Display*)LinuxPlatform::GetXDisplay(); if (event->type == ButtonPress) { const Float2 cursorPos = Platform::GetMousePosition(); const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos); X11::XUngrabPointer(display, CurrentTime); ScreenUtilities::PickColorDone(colorPicked); LinuxPlatform::xEventRecieved.Unbind(OnScreenUtilsXEventCallback); } } void ScreenUtilities::PickColor() { PROFILE_CPU(); X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay(); X11::Window rootWindow = X11::XRootWindow(display, X11::XDefaultScreen(display)); X11::Cursor cursor = XCreateFontCursor(display, 130); int grabbedPointer = X11::XGrabPointer(display, rootWindow, 0, ButtonPressMask, GrabModeAsync, GrabModeAsync, rootWindow, cursor, CurrentTime); if (grabbedPointer != GrabSuccess) { LOG(Error, "Failed to grab cursor for events."); X11::XFreeCursor(display, cursor); return; } X11::XFreeCursor(display, cursor); LinuxPlatform::xEventRecieved.Bind(OnScreenUtilsXEventCallback); } #elif PLATFORM_MAC #include #include Color32 ScreenUtilities::GetColorAt(const Float2& pos) { // TODO: implement ScreenUtilities for macOS return { 0, 0, 0, 255 }; } void ScreenUtilities::PickColor() { // This is what C# calls to start the color picking sequence // This should stop mouse clicks from working for one click, and that click is on the selected color // There is a class called NSColorSample that might implement that for you, but maybe not. } #endif