diff --git a/CMakeLists.txt b/CMakeLists.txt index d42dffb..6488720 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,30 +4,60 @@ set(CMAKE_CXX_STANDARD 17) project(libnut) # Source -set(SOURCE_FILES "src/main.cc" "src/deadbeef_rand.c" "src/MMBitmap.c") +set(SOURCE_FILES + src/main.cc + src/deadbeef_rand.c + src/MMBitmap.c + ) + if (UNIX AND NOT APPLE) - set(SOURCE_FILES "${SOURCE_FILES}" "src/linux/keycode.c" "src/linux/keypress.c" "src/linux/mouse.c" "src/linux/screen.c" "src/linux/screengrab.c" "src/linux/xdisplay.c" "src/linux/highlightwindow.c" "src/linux/window_manager.cc") + list(APPEND SOURCE_FILES + src/linux/keycode.c + src/linux/keypress.c + src/linux/mouse.c + src/linux/screen.c + src/linux/screengrab.c + src/linux/xdisplay.c + src/linux/highlightwindow.c + src/linux/window_manager.cc + ) elseif (UNIX AND APPLE) - set(SOURCE_FILES "${SOURCE_FILES}" "src/macos/keycode.c" "src/macos/keypress.c" "src/macos/mouse.c" "src/macos/mouse_utils.mm" "src/macos/screen.c" "src/macos/screengrab.c" "src/macos/highlightwindow.m" "src/macos/window_manager.mm") + list(APPEND SOURCE_FILES + src/macos/keycode.c + src/macos/keypress.c + src/macos/mouse.c + src/macos/mouse_utils.mm + src/macos/screen.c + src/macos/screengrab.m + src/macos/highlightwindow.m + src/macos/window_manager.mm + ) elseif (WIN32) - set(SOURCE_FILES "${SOURCE_FILES}" "src/win32/keycode.c" "src/win32/keypress.c" "src/win32/mouse.c" "src/win32/screen.c" "src/win32/screengrab.c" "src/win32/highlightwindow.c" "src/win32/window_manager.cc") + list(APPEND SOURCE_FILES + src/win32/keycode.c + src/win32/keypress.c + src/win32/mouse.c + src/win32/screen.c + src/win32/screengrab.c + src/win32/highlightwindow.c + src/win32/window_manager.cc + ) endif() + add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC}) +# External libs set(LIBS "") set(INCLUDES "") -# External libs if (UNIX AND APPLE) message(STATUS "macOS build") - set(LIBS "${LIBS}" "-framework ApplicationServices") - set(LIBS "${LIBS}" "-framework Cocoa") + list(APPEND LIBS "-framework ApplicationServices" "-framework Cocoa") elseif (WIN32) message(STATUS "Windows build") elseif (UNIX AND NOT APPLE) message(STATUS "Linux build") - set(LIBS "${LIBS}" "-lX11") - set(LIBS "${LIBS}" "-lXtst") + list(APPEND LIBS "-lX11" "-lXtst") endif() if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") @@ -39,27 +69,27 @@ else() endif() if (WIN32) - # Copy runtime distributable - add_custom_command( - TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_SOURCE_DIR}/3rdparty/win32/msvcp140.dll - ${CMAKE_SOURCE_DIR}/3rdparty/win32/vcruntime140.dll - ${CMAKE_SOURCE_DIR}/3rdparty/win32/vcruntime140_1.dll - ${CMAKE_SOURCE_DIR}/3rdparty/win32/api-ms-win-crt-heap-l1-1-0.dll - ${CMAKE_SOURCE_DIR}/3rdparty/win32/api-ms-win-crt-runtime-l1-1-0.dll - ${CMAKE_SOURCE_DIR}/3rdparty/win32/api-ms-win-crt-string-l1-1-0.dll - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ - ) + # Copy runtime distributable + add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/3rdparty/win32/msvcp140.dll + ${CMAKE_SOURCE_DIR}/3rdparty/win32/vcruntime140.dll + ${CMAKE_SOURCE_DIR}/3rdparty/win32/vcruntime140_1.dll + ${CMAKE_SOURCE_DIR}/3rdparty/win32/api-ms-win-crt-heap-l1-1-0.dll + ${CMAKE_SOURCE_DIR}/3rdparty/win32/api-ms-win-crt-runtime-l1-1-0.dll + ${CMAKE_SOURCE_DIR}/3rdparty/win32/api-ms-win-crt-string-l1-1-0.dll + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ + ) endif() add_compile_definitions(NAPI_CPP_EXCEPTIONS) add_compile_definitions(NAPI_VERSION=3) # cmake-js -set(INCLUDES ${INCLUDES} ${CMAKE_JS_INC}) +list(APPEND INCLUDES ${CMAKE_JS_INC}) message(STATUS "Includes: ${INCLUDES}") -set(LIBS ${LIBS} ${CMAKE_JS_LIB}) +list(APPEND LIBS ${CMAKE_JS_LIB}) message(STATUS "Libs: ${LIBS}") # N-API diff --git a/src/macos/screengrab.c b/src/macos/screengrab.c deleted file mode 100644 index d0d8d86..0000000 --- a/src/macos/screengrab.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "../screengrab.h" -#include "../endian.h" -#include /* malloc() */ - -#include - -MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect) -{ - MMBitmapRef bitmap = NULL; - uint8_t *buffer = NULL; - size_t bufferSize = 0; - - CGDirectDisplayID displayID = CGMainDisplayID(); - - CGImageRef image = CGDisplayCreateImageForRect(displayID, - CGRectMake(rect.origin.x, - rect.origin.y, - rect.size.width, - rect.size.height)); - - if (!image) { return NULL; } - - CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image)); - - if (!imageData) { return NULL; } - - bufferSize = CFDataGetLength(imageData); - buffer = malloc(bufferSize); - - CFDataGetBytes(imageData, CFRangeMake(0,bufferSize), buffer); - - bitmap = createMMBitmap(buffer, - CGImageGetWidth(image), - CGImageGetHeight(image), - CGImageGetBytesPerRow(image), - CGImageGetBitsPerPixel(image), - CGImageGetBitsPerPixel(image) / 8); - - CFRelease(imageData); - - CGImageRelease(image); - - return bitmap; -} diff --git a/src/macos/screengrab.m b/src/macos/screengrab.m new file mode 100644 index 0000000..b84f0d2 --- /dev/null +++ b/src/macos/screengrab.m @@ -0,0 +1,88 @@ +#include "../screengrab.h" +#include "../endian.h" +#include /* malloc() */ + +#include +#import + +static double getPixelDensity() { + @autoreleasepool + { + NSScreen * mainScreen = [NSScreen + mainScreen]; + if (mainScreen) { + return mainScreen.backingScaleFactor; + } else { + return 1.0; + } + } +} + +MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect) { + + CGDirectDisplayID displayID = CGMainDisplayID(); + + CGImageRef image = CGDisplayCreateImageForRect(displayID, + CGRectMake( + rect.origin.x, + rect.origin.y, + rect.size.width, + rect.size.height + ) + ); + + if (!image) { return NULL; } + + CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image)); + + if (!imageData) { return NULL; } + + long bufferSize = CFDataGetLength(imageData); + size_t bytesPerPixel = (size_t) (CGImageGetBitsPerPixel(image) / 8); + double pixelDensity = getPixelDensity(); + long expectedBufferSize = rect.size.width * pixelDensity * rect.size.height * pixelDensity * bytesPerPixel; + + if (expectedBufferSize < bufferSize) { + size_t reportedByteWidth = CGImageGetBytesPerRow(image); + size_t expectedByteWidth = expectedBufferSize / (rect.size.height * pixelDensity); + + uint8_t *buffer = malloc(expectedBufferSize); + + const uint8_t *dataPointer = CFDataGetBytePtr(imageData); + size_t parts = bufferSize / reportedByteWidth; + + for (size_t idx = 0; idx < parts - 1; ++idx) { + memcpy(buffer + (idx * expectedByteWidth), + dataPointer + (idx * reportedByteWidth), + expectedByteWidth + ); + } + + MMBitmapRef bitmap = createMMBitmap(buffer, + rect.size.width * pixelDensity, + rect.size.height * pixelDensity, + expectedByteWidth, + CGImageGetBitsPerPixel(image), + CGImageGetBitsPerPixel(image) / 8); + + CFRelease(imageData); + CGImageRelease(image); + + return bitmap; + } else { + uint8_t *buffer = malloc(bufferSize); + CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer); + MMBitmapRef bitmap = createMMBitmap(buffer, + CGImageGetWidth(image), + CGImageGetHeight(image), + CGImageGetBytesPerRow(image), + CGImageGetBitsPerPixel(image), + CGImageGetBitsPerPixel(image) / 8); + + CFRelease(imageData); + + CGImageRelease(image); + + return bitmap; + } +}