From ee143dfb8778717acfd92f6505a70ca3831c5c98 Mon Sep 17 00:00:00 2001 From: Simon Hofmann Date: Tue, 7 May 2024 17:43:50 +0200 Subject: [PATCH 1/2] Bugfix/macos screengrab (#1) * Ported fix from bolt to libnut * Updated ci workflows with npm auth * Increase timeout between window switches --- .github/workflows/ci.yaml | 7 ++- .github/workflows/snapshot_release.yaml | 7 ++- .github/workflows/tagged_release.yaml | 7 ++- src/macos/screengrab.m | 81 ++++++++----------------- test/window-integration-tests/test.js | 1 + 5 files changed, 41 insertions(+), 62 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7014222..2a3e369 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,6 +12,8 @@ jobs: matrix: os: [ ubuntu-20.04, macos-11, windows-2019 ] node: [ 18 ] + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} runs-on: ${{matrix.os}} steps: - name: Set up Git repository @@ -20,6 +22,7 @@ jobs: uses: actions/setup-node@v4.0.2 with: node-version: ${{matrix.node}} + registry-url: https://registry.npmjs.org - name: Configure Linux environment if: ${{matrix.os == 'ubuntu-20.04'}} run: sudo apt-get install -y cmake libx11-dev zlib1g-dev libpng-dev libxtst-dev build-essential @@ -28,12 +31,12 @@ jobs: - name: Build run: npm run build:release - name: Run tests - uses: GabrielBB/xvfb-action@v1 + uses: coactions/setup-xvfb@v1 with: working-directory: ./test/ run: npm cit - name: Run window tests - uses: GabrielBB/xvfb-action@v1 + uses: coactions/setup-xvfb@v1 with: working-directory: ./test/window-integration-tests run: npm cit diff --git a/.github/workflows/snapshot_release.yaml b/.github/workflows/snapshot_release.yaml index db8ca59..5d3d9bf 100644 --- a/.github/workflows/snapshot_release.yaml +++ b/.github/workflows/snapshot_release.yaml @@ -16,6 +16,8 @@ jobs: matrix: os: [ ubuntu-20.04, macos-11, windows-2019 ] node: [ 18 ] + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} runs-on: ${{matrix.os}} steps: - name: Set up Git repository @@ -24,6 +26,7 @@ jobs: uses: actions/setup-node@v4.0.2 with: node-version: ${{matrix.node}} + registry-url: https://registry.npmjs.org - name: Configure Linux environment if: ${{matrix.os == 'ubuntu-20.04'}} run: sudo apt-get install -y cmake libx11-dev zlib1g-dev libpng-dev libxtst-dev build-essential @@ -32,12 +35,12 @@ jobs: - name: Build run: npm run build:release - name: Run tests - uses: GabrielBB/xvfb-action@v1 + uses: coactions/setup-xvfb@v1 with: working-directory: ./test/ run: npm cit - name: Run window tests - uses: GabrielBB/xvfb-action@v1 + uses: coactions/setup-xvfb@v1 with: working-directory: ./test/window-integration-tests run: npm cit diff --git a/.github/workflows/tagged_release.yaml b/.github/workflows/tagged_release.yaml index d4b9546..5a14350 100644 --- a/.github/workflows/tagged_release.yaml +++ b/.github/workflows/tagged_release.yaml @@ -11,6 +11,8 @@ jobs: os: [ ubuntu-20.04, macos-11, windows-2019 ] node: [ 18 ] runs-on: ${{matrix.os}} + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} steps: - name: Set up Git repository uses: actions/checkout@v4.1.1 @@ -18,6 +20,7 @@ jobs: uses: actions/setup-node@v4.0.2 with: node-version: ${{matrix.node}} + registry-url: https://registry.npmjs.org - name: Configure Linux environment if: ${{matrix.os == 'ubuntu-20.04'}} run: sudo apt-get install -y cmake libx11-dev zlib1g-dev libpng-dev libxtst-dev build-essential @@ -26,12 +29,12 @@ jobs: - name: Build run: npm run build:release - name: Run tests - uses: GabrielBB/xvfb-action@v1 + uses: coactions/setup-xvfb@v1 with: working-directory: ./test/ run: npm cit - name: Run window tests - uses: GabrielBB/xvfb-action@v1 + uses: coactions/setup-xvfb@v1 with: working-directory: ./test/window-integration-tests run: npm cit diff --git a/src/macos/screengrab.m b/src/macos/screengrab.m index b84f0d2..8ac6350 100644 --- a/src/macos/screengrab.m +++ b/src/macos/screengrab.m @@ -1,23 +1,11 @@ #include "../screengrab.h" #include "../endian.h" #include /* malloc() */ +#include /* printf() */ #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(); @@ -33,56 +21,37 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect) { if (!image) { return NULL; } - CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image)); + size_t width = CGImageGetWidth(image); + size_t height = CGImageGetHeight(image); + CGDataProviderRef provider = CGImageGetDataProvider(image); + + CFDataRef imageData = CGDataProviderCopyData(provider); 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); + size_t bitsPerPixel = CGImageGetBitsPerPixel(image); + size_t bytesPerPixel = bitsPerPixel / 8; + size_t bytesPerRow = CGImageGetBytesPerRow(image); + size_t actualBytesPerRow = width * bytesPerPixel; + const UInt8 *dataPointer = CFDataGetBytePtr(imageData); - const uint8_t *dataPointer = CFDataGetBytePtr(imageData); - size_t parts = bufferSize / reportedByteWidth; + uint8_t *imageDataWithoutPadding = malloc(height * actualBytesPerRow); - 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); + for (size_t y = 0; y < height; ++y) { + const UInt8 *rowPtr = dataPointer + y * bytesPerRow; + memcpy(imageDataWithoutPadding + y * actualBytesPerRow, rowPtr, actualBytesPerRow); + } - CFRelease(imageData); + MMBitmapRef bitmap = createMMBitmap(imageDataWithoutPadding, + width, + height, + actualBytesPerRow, + bitsPerPixel, + bytesPerPixel); - CGImageRelease(image); + CFRelease(imageData); + CGImageRelease(image); - return bitmap; - } + return bitmap; } diff --git a/test/window-integration-tests/test.js b/test/window-integration-tests/test.js index 57c9543..73e5ef9 100644 --- a/test/window-integration-tests/test.js +++ b/test/window-integration-tests/test.js @@ -111,6 +111,7 @@ describe("focusWindow", () => { win.focus(); }); + await sleep(3000); const result = libnut.focusWindow(openWindowHandle); // THEN From 2c1e9d4b8720a399b9a5c252b09ff7ea97f17663 Mon Sep 17 00:00:00 2001 From: Simon Hofmann Date: Fri, 31 May 2024 18:20:18 +0200 Subject: [PATCH 2/2] (NT-133) Allow meta and right_meta as modifier keys --- src/main.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cc b/src/main.cc index 4aa858a..44c7610 100644 --- a/src/main.cc +++ b/src/main.cc @@ -416,10 +416,10 @@ int CheckKeyFlags(std::string &flagString, MMKeyFlags *flags) { if (flagString == "alt" || flagString == "right_alt") { *flags = MOD_ALT; #if defined(IS_MACOSX) - } else if (flagString == "command" || flagString == "cmd" || flagString == "right_cmd") { + } else if (flagString == "meta" || flagString == "right_meta" || flagString == "cmd" || flagString == "right_cmd") { *flags = MOD_META; #else - } else if (flagString == "command" || flagString == "win" || flagString == "right_win") { + } else if (flagString == "meta" || flagString == "right_meta" || flagString == "win" || flagString == "right_win") { *flags = MOD_META; #endif } else if (flagString == "control" || flagString == "right_control") {