diff --git a/.circleci/config.yml b/.circleci/config.yml index 5b6b8de..2c56bc4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,11 +11,13 @@ jobs: - checkout # specify any bash command here prefixed with `run: ` - run: apt update - - run: apt -y install gcc libc6-dev - libx11-dev xorg-dev libxtst-dev libpng++-dev - xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev - libxkbcommon-dev + - run: + apt -y install gcc libc6-dev + libx11-dev xorg-dev libxtst-dev xsel xclip + # libpng++-dev + # xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev + # libxkbcommon-dev - run: apt -y install xvfb # # override: diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 0f509b1..f64bda7 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -22,10 +22,6 @@ jobs: - name: Get dependencies run: | go get -v -t -d ./... - # if [ -f Gopkg.toml ]; then - # curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - # dep ensure - # fi - name: Build run: go build -v . diff --git a/base/bitmap_free_c.h b/base/bitmap_free_c.h new file mode 100644 index 0000000..e4c751f --- /dev/null +++ b/base/bitmap_free_c.h @@ -0,0 +1,41 @@ +#include "MMBitmap.h" +#include +#include + +MMBitmapRef createMMBitmap_c( + uint8_t *buffer, + size_t width, + size_t height, + size_t bytewidth, + uint8_t bitsPerPixel, + uint8_t bytesPerPixel +){ + MMBitmapRef bitmap = malloc(sizeof(MMBitmap)); + if (bitmap == NULL) { return NULL; } + + bitmap->imageBuffer = buffer; + bitmap->width = width; + bitmap->height = height; + bitmap->bytewidth = bytewidth; + bitmap->bitsPerPixel = bitsPerPixel; + bitmap->bytesPerPixel = bytesPerPixel; + + return bitmap; +} + +void destroyMMBitmap(MMBitmapRef bitmap) { + assert(bitmap != NULL); + + if (bitmap->imageBuffer != NULL) { + free(bitmap->imageBuffer); + bitmap->imageBuffer = NULL; + } + + free(bitmap); +} + +void destroyMMBitmapBuffer(char * bitmapBuffer, void * hint) { + if (bitmapBuffer != NULL) { + free(bitmapBuffer); + } +} diff --git a/bitmap/bitmap_class.h b/bitmap/bitmap_class.h deleted file mode 100644 index 1f7f9c0..0000000 --- a/bitmap/bitmap_class.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -// #ifndef BITMAP_CLASS_H -// #define BITMAP_CLASS_H - -#include "../base/MMBitmap.h" - -/* This file defines the class "Bitmap" for dealing with raw bitmaps. */ -struct _BitmapObject { - MMBitmapRef bitmap; - MMPoint point; /* For iterator */ -}; - -typedef struct _BitmapObject BitmapObject; - -// extern PyTypeObject Bitmap_Type; - -/* Returns a newly-initialized BitmapObject from the given MMBitmap. - * The reference to |bitmap| is "stolen"; i.e., only the pointer is copied, and - * the reponsibility for free()'ing the buffer is given to the |BitmapObject|. - * - * Remember to call PyType_Ready() before using this for the first time! */ -BitmapObject BitmapObject_FromMMBitmap(MMBitmapRef bitmap); - -// #endif /* PY_BITMAP_CLASS_H */ \ No newline at end of file diff --git a/bitmap/bitmap_find.h b/bitmap/bitmap_find.h deleted file mode 100644 index 763fa23..0000000 --- a/bitmap/bitmap_find.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#ifndef BITMAP_H -#define BITMAP_H - -// #include "../base/types.h" -#include "../base/MMBitmap.h" -#include "../base/MMPointArray_c.h" - -/* Convenience wrapper around findBitmapInRect(), where |rect| is the bounds - * of |haystack|. */ -#define findBitmapInBitmap(needle, haystack, pointPtr, tol) \ - findBitmapInRect(needle, haystack, pointPtr, MMBitmapGetBounds(haystack), tol) - -/* Returns 0 and sets |point| to the origin of |needle| in |haystack| if - * |needle| was found in |haystack| inside of |rect|, or returns -1 if not. - * - * |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the - * colors in the bitmaps need to match, with 0 being exact and 1 being any. - */ -int findBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, - MMPoint *point, MMRect rect, float tolerance); - -/* Convenience wrapper around findAllBitmapInRect(), where |rect| is the bounds - * of |haystack|. */ -#define findAllBitmapInBitmap(needle, haystack, tolerance) \ - findAllBitmapInRect(needle, haystack, \ - MMBitmapGetBounds(haystack), tolerance) - -/* Returns MMPointArray of all occurrences of |needle| in |haystack| inside of - * |rect|. Note that an is returned regardless of whether |needle| was found; - * check array->count to see if it actually was. - * - * |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the - * colors in the bitmaps need to match, with 0 being exact and 1 being any. - * - * Responsibility for freeing the MMPointArray with destroyMMPointArray() is - * given to the caller. - */ -MMPointArrayRef findAllBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, - MMRect rect, float tolerance); - -// #define MMRGBHexAtPoint(image, x, y) \ -// hexFromMMRGB(MMRGBColorAtPoint(image, x, y)) - -/* Convenience wrapper around countOfBitmapInRect(), where |rect| is the bounds - * of |haystack|. */ -#define countOfBitmapInBitmap(needle, haystack, tolerance) \ - countOfBitmapInRect(needle, haystack, MMBitmapGetBounds(haystack), tolerance) - -/* Returns the number of occurences of |needle| in |haystack| inside - * of |rect|. */ -size_t countOfBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, - MMRect rect, float tolerance); - -#endif /* BITMAP_H */ diff --git a/bitmap/bitmap_find_c.h b/bitmap/bitmap_find_c.h deleted file mode 100644 index 1df90f6..0000000 --- a/bitmap/bitmap_find_c.h +++ /dev/null @@ -1,270 +0,0 @@ -#include "bitmap_find.h" -#include "../base/UTHashTable_c.h" -#include - -/* Node to be used in hash table. */ -struct shiftNode { - UTHashNode_HEAD /* Make structure hashable */ - MMRGBHex color; /* Key */ - MMPoint offset; /* Value */ -}; - -/* --- Hash table helper functions --- */ - -/* Adds hex-color/offset pair to jump table. */ -static void addNodeToTable(UTHashTable *table, MMRGBHex color, MMPoint offset); - -/* Returns node associated with color in jump table, or NULL if it - * doesn't exist. */ -static struct shiftNode *nodeForColor(UTHashTable *table, MMRGBHex color); - -/* Returns nonzero (true) if table has key, or zero (false) if not. */ -#define tableHasKey(table, color) (nodeForColor(table, color) != NULL) - -/* --- Boyer-Moore helper functions --- */ - -/* Calculates the first table for use in a Boyer-Moore search algorithm. - * Table is in the form [colors: shift_values], where colors are those in - * |needle|, and the shift values are each color's distance from the rightmost - * offset. All other colors are assumed to have a shift value equal to the - * length of needle. - */ -static void initBadShiftTable(UTHashTable *jumpTable, MMBitmapRef needle); - -/* Frees memory occupied by calling initBadShiftTable(). - * Currently this is just an alias for destroyHashTable(). */ -#define destroyBadShiftTable(jumpTable) destroyHashTable(jumpTable) - -/* Returns true if |needle| is found in |haystack| at |offset|. */ -static int needleAtOffset(MMBitmapRef needle, MMBitmapRef haystack, - MMPoint offset, float tolerance); -/* --- --- */ - -/* An modification of the Boyer-Moore-Horspool Algorithm, only applied to - * bitmaps and colors instead of strings and characters. - * - * TODO: The Boyer-Moore algorithm (with the second jump table) would probably - * be more efficient, but this was simpler (for now). - * - * The jump table (|badShiftTable|) is passed as a parameter to avoid being - * recalculated each time. It should be a pointer to a UTHashTable init'd with - * initBadShiftTable(). - * - * Returns 0 and sets |point| to the starting point of |needle| in |haystack| - * if |needle| was found in |haystack|, or returns -1 if not. */ -static int findBitmapInRectAt(MMBitmapRef needle, - MMBitmapRef haystack, - MMPoint *point, - MMRect rect, - float tolerance, - MMPoint startPoint, - UTHashTable *badShiftTable) -{ - const size_t scanHeight = rect.size.height - needle->height; - const size_t scanWidth = rect.size.width - needle->width; - MMPoint pointOffset = startPoint; - /* const MMPoint lastPoint = MMPointMake(needle->width - 1, needle->height - 1); */ - - /* Sanity check */ - if (needle->height > haystack->height || needle->width > haystack->width || - !MMBitmapRectInBounds(haystack, rect)) { - return -1; - } - - assert(point != NULL); - assert(needle != NULL); - assert(needle->height > 0 && needle->width > 0); - assert(haystack != NULL); - assert(haystack->height > 0 && haystack->width > 0); - assert(badShiftTable != NULL); - - /* Search |haystack|, while |needle| can still be within it. */ - while (pointOffset.y <= scanHeight) { - /* struct shiftNode *node = NULL; - MMRGBHex lastColor; */ - - while (pointOffset.x <= scanWidth) { - /* Check offset in |haystack| for |needle|. */ - if (needleAtOffset(needle, haystack, pointOffset, tolerance)) { - // ++pointOffset.x; - // ++pointOffset.y; - *point = pointOffset; - return 0; - } - - /* Otherwise, calculate next x offset to check. */ - /* - * Note that here we are getting the skip value based on the last - * color of |needle|, no matter where we didn't match. The - * alternative of pretending that the mismatched color was the previous - * color is slower in the normal case. - */ - /* lastColor = MMRGBHexAtPoint(haystack, pointOffset.x + lastPoint.x, - pointOffset.y + lastPoint.y); */ - - /* TODO: This fails on certain edge cases (issue#7). */ - /* When a color is encountered that does not occur in |needle|, we can - * safely skip ahead for the whole length of |needle|. - * Otherwise, use the value stored in the jump table. */ - /* node = nodeForColor(badShiftTable, lastColor); - pointOffset.x += (node == NULL) ? needle->width : (node->offset).x; */ - - /* For now, be naive. */ - ++pointOffset.x; - } - - pointOffset.x = rect.origin.x; - - /* lastColor = MMRGBHexAtPoint(haystack, pointOffset.x + lastPoint.x, - pointOffset.y + lastPoint.y); - node = nodeForColor(badShiftTable, lastColor); - pointOffset.y += node == NULL ? lastPoint.y : (node->offset).y; */ - - /* TODO: The above commented out code fails at certain edge cases, e.g.: - * Needle: [B, b - * b, b, - * B, b] - * Haystack: [w, w, w, w, w - * w, w, w, w, b - * w, w, w, b, b - * w, w, w, w, b] - * The previous algorithm noticed that the first 3 x 3 block had nothing - * in common with the image, and thus, after scanning the first row, - * skipped three blocks downward to scan the next (which didn't exist, - * so the loop ended). However, the needle was hidden IN-BETWEEN this - * jump -- skipping was appropriate for scanning the column but not - * the row. - * - * I need to figure out a more optimal solution; temporarily I am just - * scanning every single y coordinate, only skipping on x's. This - * always works, but is probably not optimal. - */ - ++pointOffset.y; - } - - return -1; -} - -int findBitmapInRect(MMBitmapRef needle, - MMBitmapRef haystack, - MMPoint *point, - MMRect rect, - float tolerance) -{ - UTHashTable badShiftTable; - int ret; - - initBadShiftTable(&badShiftTable, needle); - ret = findBitmapInRectAt(needle, haystack, point, rect, - tolerance, MMPointZero, &badShiftTable); - destroyBadShiftTable(&badShiftTable); - return ret; -} - -MMPointArrayRef findAllBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, - MMRect rect, float tolerance) -{ - MMPointArrayRef pointArray = createMMPointArray(0); - MMPoint point = MMPointZero; - UTHashTable badShiftTable; - - initBadShiftTable(&badShiftTable, needle); - while (findBitmapInRectAt(needle, haystack, &point, rect, - tolerance, point, &badShiftTable) == 0) { - const size_t scanWidth = (haystack->width - needle->width) + 1; - MMPointArrayAppendPoint(pointArray, point); - ITER_NEXT_POINT(point, scanWidth, 0); - } - destroyBadShiftTable(&badShiftTable); - - return pointArray; -} - -size_t countOfBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, - MMRect rect, float tolerance) -{ - size_t count = 0; - MMPoint point = MMPointZero; - UTHashTable badShiftTable; - - initBadShiftTable(&badShiftTable, needle); - while (findBitmapInRectAt(needle, haystack, &point, rect, - tolerance, point, &badShiftTable) == 0) { - const size_t scanWidth = (haystack->width - needle->width) + 1; - ++count; - ITER_NEXT_POINT(point, scanWidth, 0); - } - destroyBadShiftTable(&badShiftTable); - - return count; -} - -/* --- Boyer-Moore helper functions --- */ - -static void initBadShiftTable(UTHashTable *jumpTable, MMBitmapRef needle) -{ - const MMPoint lastPoint = MMPointMake(needle->width - 1, needle->height - 1); - const size_t maxColors = needle->width * needle->height; - MMPoint scan; - - /* Allocate max size initially to avoid a million calls to malloc(). */ - initHashTable(jumpTable, maxColors, sizeof(struct shiftNode)); - - /* Populate jumpTable with analysis of |needle|. */ - for (scan.y = lastPoint.y; ; --scan.y) { - for (scan.x = lastPoint.x; ; --scan.x) { - MMRGBHex color = MMRGBHexAtPoint(needle, scan.x, scan.y); - if (!tableHasKey(jumpTable, color)) { - addNodeToTable(jumpTable, color, - MMPointMake(needle->width - scan.x, - needle->height - scan.y)); - } - - if (scan.x == 0) break; /* Avoid infinite loop from unsigned type. */ - } - if (scan.y == 0) break; - } -} - -static int needleAtOffset(MMBitmapRef needle, MMBitmapRef haystack, - MMPoint offset, float tolerance) -{ - const MMPoint lastPoint = MMPointMake(needle->width - 1, needle->height - 1); - MMPoint scan; - - /* Note that |needle| is searched backwards, in accordance with the - * Boyer-Moore search algorithm. */ - for (scan.y = lastPoint.y; ; --scan.y) { - for (scan.x = lastPoint.x; ; --scan.x) { - MMRGBHex ncolor = MMRGBHexAtPoint(needle, scan.x, scan.y); - MMRGBHex hcolor = MMRGBHexAtPoint(haystack, offset.x + scan.x, - offset.y + scan.y); - if (!MMRGBHexSimilarToColor(ncolor, hcolor, tolerance)) return 0; - if (scan.x == 0) break; /* Avoid infinite loop from unsigned type. */ - } - if (scan.y == 0) break; - } - - return 1; -} - -/* --- Hash table helper functions --- */ - -static void addNodeToTable(UTHashTable *table, - MMRGBHex hexColor, - MMPoint offset) -{ - struct shiftNode *node = getNewNode(table); - node->color = hexColor; - node->offset = offset; - UTHASHTABLE_ADD_INT(table, color, node, struct shiftNode); -} - -static struct shiftNode *nodeForColor(UTHashTable *table, - MMRGBHex color) -{ - struct shiftNode *uttable = table->uttable; - struct shiftNode *node; - HASH_FIND_INT(uttable, &color, node); - return node; -} diff --git a/bitmap/goBitmap.h b/bitmap/goBitmap.h deleted file mode 100644 index 0a205c3..0000000 --- a/bitmap/goBitmap.h +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// https://github.com/go-vgo/robotgo/blob/master/LICENSE -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#include "bitmap_class.h" -#include "bitmap_find_c.h" -#include "../base/color_find_c.h" -// #include "../screen/screen_c.h" -#include "../base/file_io_c.h" -#include "../base/pasteboard_c.h" -#include "../base/str_io_c.h" -#include -#include - -/* Returns false and sets error if |bitmap| is NULL. */ -bool bitmap_ready(MMBitmapRef bitmap){ - if (bitmap == NULL || bitmap->imageBuffer == NULL) { - return false; - } - return true; -} - -// void bitmap_dealloc(MMBitmapRef bitmap){ -// if (bitmap != NULL) { -// destroyMMBitmap(bitmap); -// bitmap = NULL; -// } -// } - -bool bitmap_copy_to_pboard(MMBitmapRef bitmap){ - MMPasteError err; - - if (!bitmap_ready(bitmap)) return false; - if ((err = copyMMBitmapToPasteboard(bitmap)) != kMMPasteNoError) { - return false; - } - - return true; -} - -MMBitmapRef bitmap_deepcopy(MMBitmapRef bitmap){ - return bitmap == NULL ? NULL : copyMMBitmap(bitmap); -} - -MMPoint find_bitmap(MMBitmapRef bitmap, MMBitmapRef sbit, float tolerance){ - MMPoint point = {-1, -1}; - // printf("tolenrance=%f\n", tolerance); - if (!bitmap_ready(sbit) || !bitmap_ready(bitmap)) { - printf("bitmap is not ready yet!\n"); - return point; - } - - MMRect rect = MMBitmapGetBounds(sbit); - // printf("x=%d, y=%d, width=%d, height=%d\n", rect.origin.x, - // rect.origin.y, rect.size.width, rect.size.height); - - if (findBitmapInRect(bitmap, sbit, &point, rect, tolerance) == 0) { - return point; - } - - return point; -} - -MMPointArrayRef find_every_bitmap(MMBitmapRef bitmap, MMBitmapRef sbit, float tolerance, MMPoint *list){ - if (!bitmap_ready(bitmap) || !bitmap_ready(sbit)) { return NULL; } - - MMPoint point; - MMPointArrayRef pointArray; - MMRect rect = MMBitmapGetBounds(sbit); - - if (findBitmapInRect(bitmap, sbit, &point, rect, tolerance) == 0) { - // return NULL; - } - - pointArray = findAllBitmapInRect(bitmap, sbit, rect, tolerance); - return pointArray; -} - -int count_of_bitmap(MMBitmapRef bitmap, MMBitmapRef sbit, float tolerance){ - if (!bitmap_ready(bitmap) || !bitmap_ready(sbit)) { return 0; } - - MMRect rect = MMBitmapGetBounds(bitmap); - return countOfBitmapInRect(bitmap, sbit, rect, tolerance); -} - -bool point_in_bounds(MMBitmapRef bitmap, MMPoint point){ - if (!bitmap_ready(bitmap)) { - return NULL; - } - - if (MMBitmapPointInBounds(bitmap, point)) { - return true; - } - - return false; -} - -MMBitmapRef bitmap_open(char *path, uint16_t ttype){ - // MMImageType type; - MMBitmapRef bitmap; - MMIOError err; - - bitmap = newMMBitmapFromFile(path, ttype, &err); - // printf("....%zd\n", bitmap->width); - return bitmap; -} - -MMBitmapRef bitmap_from_string(const char *str){ - size_t len = strlen(str); - - MMBitmapRef bitmap; - MMBMPStringError err; - - if ((bitmap = createMMBitmapFromString((unsigned char*)str, len, &err)) - == NULL) { - return NULL; - } - - return bitmap; -} - -char *bitmap_save(MMBitmapRef bitmap, char *path, uint16_t type){ - if (saveMMBitmapToFile(bitmap, path, (MMImageType) type) != 0) { - return "Could not save image to file."; - } - // destroyMMBitmap(bitmap); - return ""; -} - -char *tostring_bitmap(MMBitmapRef bitmap){ - char *buf = NULL; - MMBMPStringError err; - - buf = (char *)createStringFromMMBitmap(bitmap, &err); - return buf; -} - -// char out size 200 is enough -bool bitmap_str(MMBitmapRef bitmap, char *out){ - if (!bitmap_ready(bitmap)) { return false; } - sprintf(out, "", - (unsigned long)bitmap->width, - (unsigned long)bitmap->height, - bitmap->bitsPerPixel, - bitmap->bytesPerPixel); - - return true; -} - -MMBitmapRef get_portion(MMBitmapRef bit_map, MMRect rect){ - // MMRect rect; - MMBitmapRef portion = NULL; - - portion = copyMMBitmapFromPortion(bit_map, rect); - return portion; -} - -MMRGBHex bitmap_get_color(MMBitmapRef bitmap, size_t x, size_t y){ - if (!bitmap_ready(bitmap)) { return 0; } - - MMPoint point; - point = MMPointMake(x, y); - - if (!MMBitmapPointInBounds(bitmap, point)) { - return 0; - } - - return MMRGBHexAtPoint(bitmap, point.x, point.y); -} - -MMPoint bitmap_find_color(MMBitmapRef bitmap, MMRGBHex color, float tolerance){ - MMRect rect = MMBitmapGetBounds(bitmap); - MMPoint point = {-1, -1}; - - if (findColorInRect(bitmap, color, &point, rect, tolerance) == 0) { - return point; - } - - return point; -} - -MMPointArrayRef bitmap_find_every_color(MMBitmapRef bitmap, MMRGBHex color, float tolerance, MMPoint *list){ - if (!bitmap_ready(bitmap)) { return NULL; } - MMRect rect = MMBitmapGetBounds(bitmap); - MMPointArrayRef pointArray; - - pointArray = findAllColorInRect(bitmap, color, rect, tolerance); - return pointArray; -} - -int bitmap_count_of_color(MMBitmapRef bitmap, MMRGBHex color, float tolerance){ - if (!bitmap_ready(bitmap)) return 0; - MMRect rect = MMBitmapGetBounds(bitmap); - - return countOfColorsInRect(bitmap, color, rect, tolerance); -} diff --git a/go.mod b/go.mod index c84c38f..d2f60ef 100644 --- a/go.mod +++ b/go.mod @@ -5,14 +5,14 @@ go 1.17 require ( github.com/lxn/win v0.0.0-20210218163916-a377121e959e github.com/otiai10/gosseract v2.2.1+incompatible - github.com/robotn/gohook v0.31.3 + // github.com/robotn/gohook v0.31.3 github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 github.com/vcaesar/gops v0.21.3 github.com/vcaesar/imgo v0.30.0 github.com/vcaesar/keycode v0.10.0 github.com/vcaesar/tt v0.20.0 - golang.org/x/image v0.0.0-20211028202545-6944b10bf410 + golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect ) diff --git a/go.sum b/go.sum index c501778..4bed75b 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,6 @@ github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/robotn/gohook v0.31.3 h1:kGX8iukJ9ensVRwRKnTtdojAMQOpa6KFnXDi4OA4RaI= -github.com/robotn/gohook v0.31.3/go.mod h1:wyGik0yb4iwCfJjDprtNkTyxkgQWuKoVPQ3hkz6+6js= github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY= github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ= github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk= diff --git a/robotgo.go b/robotgo.go index 21027f5..f62390a 100644 --- a/robotgo.go +++ b/robotgo.go @@ -18,6 +18,7 @@ See Requirements: https://github.com/go-vgo/robotgo#requirements Installation: + With Go module support (Go 1.11+), just import: import "github.com/go-vgo/robotgo" @@ -68,7 +69,7 @@ import ( const ( // Version get the robotgo version - Version = "v0.100.0.1189, MT. Baker!" + Version = "v1.00.0.1189, MT. Baker!" ) // GetVersion get the robotgo version @@ -81,6 +82,9 @@ var ( MouseSleep = 0 // KeySleep set the key default millisecond sleep time KeySleep = 0 + + // DisplayID set the screen display id + DisplayID = -1 ) type ( @@ -199,17 +203,18 @@ func RgbToHex(r, g, b uint8) C.uint32_t { } // GetPxColor get the pixel color return C.MMRGBHex -func GetPxColor(x, y int) C.MMRGBHex { +func GetPxColor(x, y int, displayId ...int) C.MMRGBHex { cx := C.int32_t(x) cy := C.int32_t(y) - color := C.get_px_color(cx, cy) + display := displayIdx(displayId...) + color := C.get_px_color(cx, cy, C.int32_t(display)) return color } // GetPixelColor get the pixel color return string -func GetPixelColor(x, y int) string { - return PadHex(GetPxColor(x, y)) +func GetPixelColor(x, y int, displayId ...int) string { + return PadHex(GetPxColor(x, y, displayId...)) } // GetMouseColor get the mouse pos's color @@ -218,6 +223,18 @@ func GetMouseColor() string { return GetPixelColor(x, y) } +func displayIdx(id ...int) int { + display := -1 + if DisplayID != -1 { + display = DisplayID + } + if len(id) > 0 { + display = id[0] + } + + return display +} + // SysScale get the sys scale func SysScale() float64 { s := C.sys_scale() @@ -244,7 +261,7 @@ func GetScreenSize() (int, int) { // GetScreenRect get the screen rect (x, y, w, h) func GetScreenRect(displayId ...int) Rect { - display := 0 + display := -1 if len(displayId) > 0 { display = displayId[0] } @@ -274,8 +291,16 @@ func GetScaleSize() (int, int) { // use `defer robotgo.FreeBitmap(bitmap)` to free the bitmap // // robotgo.CaptureScreen(x, y, w, h int) -func CaptureScreen(args ...int) C.MMBitmapRef { +func CaptureScreen(args ...int) CBitmap { var x, y, w, h C.int32_t + displayId := -1 + if DisplayID != -1 { + displayId = DisplayID + } + + if len(args) > 4 { + displayId = args[4] + } if len(args) > 3 { x = C.int32_t(args[0]) @@ -284,16 +309,15 @@ func CaptureScreen(args ...int) C.MMBitmapRef { h = C.int32_t(args[3]) } else { // Get the main screen rect. - rect := GetScreenRect() - + rect := GetScreenRect(displayId) x = C.int32_t(rect.X) y = C.int32_t(rect.Y) w = C.int32_t(rect.W) h = C.int32_t(rect.H) } - bit := C.capture_screen(x, y, w, h) - return bit + bit := C.capture_screen(x, y, w, h, C.int32_t(displayId)) + return CBitmap(bit) } // GoCaptureScreen capture the screen and return bitmap(go struct) @@ -313,13 +337,13 @@ func CaptureImg(args ...int) image.Image { } // FreeBitmap free and dealloc the C bitmap -func FreeBitmap(bitmap C.MMBitmapRef) { +func FreeBitmap(bitmap CBitmap) { // C.destroyMMBitmap(bitmap) - C.bitmap_dealloc(bitmap) + C.bitmap_dealloc(C.MMBitmapRef(bitmap)) } // ToBitmap trans C.MMBitmapRef to Bitmap -func ToBitmap(bit C.MMBitmapRef) Bitmap { +func ToBitmap(bit CBitmap) Bitmap { bitmap := Bitmap{ ImgBuf: (*uint8)(bit.imageBuffer), Width: int(bit.width), @@ -332,13 +356,27 @@ func ToBitmap(bit C.MMBitmapRef) Bitmap { return bitmap } +// ToCBitmap trans Bitmap to C.MMBitmapRef +func ToCBitmap(bit Bitmap) CBitmap { + cbitmap := C.createMMBitmap_c( + (*C.uint8_t)(bit.ImgBuf), + C.size_t(bit.Width), + C.size_t(bit.Height), + C.size_t(bit.Bytewidth), + C.uint8_t(bit.BitsPixel), + C.uint8_t(bit.BytesPerPixel), + ) + + return CBitmap(cbitmap) +} + // ToImage convert C.MMBitmapRef to standard image.Image -func ToImage(bit C.MMBitmapRef) image.Image { +func ToImage(bit CBitmap) image.Image { return ToRGBA(bit) } // ToRGBA convert C.MMBitmapRef to standard image.RGBA -func ToRGBA(bit C.MMBitmapRef) *image.RGBA { +func ToRGBA(bit CBitmap) *image.RGBA { bmp1 := ToBitmap(bit) return ToRGBAGo(bmp1) } @@ -536,7 +574,7 @@ func MoveSmooth(x, y int, args ...interface{}) bool { cy := C.int32_t(y) var ( - mouseDelay = 5 + mouseDelay = 1 low C.double high C.double ) diff --git a/robotgo_test.go b/robotgo_test.go index 0a11e8e..142e8ac 100644 --- a/robotgo_test.go +++ b/robotgo_test.go @@ -14,7 +14,6 @@ package robotgo import ( - "fmt" "testing" "github.com/vcaesar/tt" @@ -152,36 +151,6 @@ func TestKeyCode(t *testing.T) { tt.Equal(t, "=", s) } -func TestBitmap(t *testing.T) { - bit := CaptureScreen() - tt.NotNil(t, bit) - e := SaveBitmap(bit, "robot_test.png") - tt.Empty(t, e) - - bit0 := CaptureScreen(10, 10, 20, 20) - x, y := FindBitmap(bit0) - fmt.Println("Find bitmap: ", x, y) - - arr := FindAllBitmap(bit0) - fmt.Println("Find all bitmap:", arr) - tt.Equal(t, 1, len(arr)) - - c1 := CHex(0xAADCDC) - x, y = FindColor(c1) - fmt.Println("Find color: ", x, y) - arr = FindAllColor(c1) - fmt.Println("Find all color: ", arr) - - img := ToImage(bit) - err := SavePng(img, "robot_img.png") - tt.Nil(t, err) - - bit1 := OpenBitmap("robot_test.png") - b := tt.TypeOf(bit, bit1) - tt.True(t, b) - tt.NotNil(t, bit1) -} - func TestPs(t *testing.T) { id, err := Pids() tt.Not(t, "[]", id) diff --git a/screen/goScreen.h b/screen/goScreen.h index a983b35..ce6b117 100644 --- a/screen/goScreen.h +++ b/screen/goScreen.h @@ -45,7 +45,7 @@ uint32_t color_rgb_to_hex(uint8_t r, uint8_t g, uint8_t b){ return RGB_TO_HEX(r, g, b); } -MMRGBHex get_px_color(int32_t x, int32_t y){ +MMRGBHex get_px_color(int32_t x, int32_t y, int32_t display_id) { MMBitmapRef bitmap; MMRGBHex color; @@ -53,7 +53,7 @@ MMRGBHex get_px_color(int32_t x, int32_t y){ return color; } - bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1)); + bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id); // bitmap = MMRectMake(x, y, 1, 1); color = MMRGBHexAtPoint(bitmap, 0, 0); @@ -62,8 +62,8 @@ MMRGBHex get_px_color(int32_t x, int32_t y){ return color; } -char* get_pixel_color(int32_t x, int32_t y){ - MMRGBHex color = get_px_color(x, y); +char* get_pixel_color(int32_t x, int32_t y, int32_t display_id) { + MMRGBHex color = get_px_color(x, y, display_id); char* s = pad_hex(color); return s; @@ -104,16 +104,8 @@ void bitmap_dealloc(MMBitmapRef bitmap){ } // capture_screen capture screen -MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h){ - // if () { - // x = 0; - // y = 0; - // // Get screen size. - // MMSize displaySize = getMainDisplaySize(); - // w = displaySize.width; - // h = displaySize.height; - // } - MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h)); +MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id) { + MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id); // printf("%s\n", bitmap); return bitmap; } diff --git a/screen/screen_c.h b/screen/screen_c.h index bc33e97..9845ff0 100644 --- a/screen/screen_c.h +++ b/screen/screen_c.h @@ -38,7 +38,7 @@ MMSizeInt32 getMainDisplaySize(void){ MMRectInt32 getScreenRect(int32_t display_id) { #if defined(IS_MACOSX) CGDirectDisplayID displayID = (CGDirectDisplayID) display_id; - if (display_id == 0) { + if (display_id == -1) { displayID = CGMainDisplayID(); } CGRect displayRect = CGDisplayBounds(displayID); diff --git a/screen/screengrab.h b/screen/screengrab.h index b40badd..728925a 100644 --- a/screen/screengrab.h +++ b/screen/screengrab.h @@ -3,7 +3,8 @@ #define SCREENGRAB_H #include "../base/types.h" -#include "../base/MMBitmap_c.h" +// #include "../base/MMBitmap_c.h" +#include "../base/bitmap_free_c.h" #ifdef __cplusplus extern "C" @@ -12,7 +13,7 @@ extern "C" /* Returns a raw bitmap of screengrab of the display (to be destroyed()'d by * caller), or NULL on error. */ -MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect); +MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id); #ifdef __cplusplus } diff --git a/screen/screengrab_c.h b/screen/screengrab_c.h index 214d6bf..ebc9b68 100644 --- a/screen/screengrab_c.h +++ b/screen/screengrab_c.h @@ -17,22 +17,24 @@ #include #endif -MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){ +MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id){ #if defined(IS_MACOSX) MMBitmapRef bitmap = NULL; uint8_t *buffer = NULL; size_t bufferSize = 0; - CGDirectDisplayID displayID = CGMainDisplayID(); + CGDirectDisplayID displayID = (CGDirectDisplayID) display_id; + + if (displayID == -1) { + displayID = CGMainDisplayID(); + } CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(rect.origin.x, rect.origin.y, rect.size.w, rect.size.h)); - if (!image) { return NULL; } CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image)); - if (!imageData) { return NULL; } bufferSize = CFDataGetLength(imageData); @@ -40,7 +42,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){ CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer); - bitmap = createMMBitmap(buffer, + bitmap = createMMBitmap_c(buffer, CGImageGetWidth(image),CGImageGetHeight(image), CGImageGetBytesPerRow(image), CGImageGetBitsPerPixel(image), CGImageGetBitsPerPixel(image) / 8); @@ -60,7 +62,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){ XCloseDisplay(display); if (image == NULL) { return NULL; } - bitmap = createMMBitmap((uint8_t *)image->data, + bitmap = createMMBitmap_c((uint8_t *)image->data, rect.size.w, rect.size.h, (size_t)image->bytes_per_line, (uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8); image->data = NULL; /* Steal ownership of bitmap data so we don't have to @@ -109,7 +111,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){ return NULL; } - bitmap = createMMBitmap(NULL, rect.size.w, rect.size.h, 4 * rect.size.w, + bitmap = createMMBitmap_c(NULL, rect.size.w, rect.size.h, 4 * rect.size.w, (uint8_t)bi.bmiHeader.biBitCount, 4); /* Copy the data to our pixel buffer. */