diff --git a/robotgo.go b/robotgo.go index c4528b4..806d92c 100644 --- a/robotgo.go +++ b/robotgo.go @@ -426,3 +426,39 @@ func ShowAlert(title, msg string, args ...string) int { ibool := int(cbool) return ibool } + +func IsValid() bool { + abool := C.aIsValid() + gbool := bool(abool) + // Println("bool---------", gbool) + return gbool +} + +func GetActive() C.MData { + mdata := C.aGetActive() + // Println("active----", mdata) + return mdata +} + +func CloseWindow() { + C.aCloseWindow() +} + +func GetHandle() int { + hwnd := C.aGetHandle() + ghwnd := int(hwnd) + // Println("gethwnd---", ghwnd) + return ghwnd +} + +// func SetHandle(hwnd int) { +// chwnd := C.uintptr(hwnd) +// C.aSetHandle(chwnd) +// } + +func GetTitle() string { + title := C.aGetTitle() + gtittle := C.GoString(title) + // Println("title...", gtittle) + return gtittle +} diff --git a/window/goWindow.h b/window/goWindow.h index 29552b4..187945d 100644 --- a/window/goWindow.h +++ b/window/goWindow.h @@ -9,7 +9,7 @@ // except according to those terms. #include "alert_c.h" -// #include "window.h" +#include "window.h" int aShowAlert(const char *title, const char *msg, const char *defaultButton, const char *cancelButton){ @@ -17,3 +17,34 @@ int aShowAlert(const char *title, const char *msg, const char *defaultButton, return alert; } + +bool aIsValid(){ + bool abool=IsValid(); + return abool; +} + +int aFindwindow(char* name){ + int z=findwindow(name); + return z; +} + +void aCloseWindow(void){ + CloseWin(); +} + +uintptr aGetHandle(){ + uintptr hwnd=getHandle(); + return hwnd; +} + +MData aGetActive(){ + MData mdata=GetActive(); + return mdata; +} + +char* aGetTitle(){ + ////3 + char* title=GetTitle(); + // printf("title::::%s\n",title ); + return title; +} diff --git a/window/window.h b/window/window.h index ad1272b..344da8a 100644 --- a/window/window.h +++ b/window/window.h @@ -8,10 +8,752 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// #include "../base/os.h" +// #include + #if defined(IS_MACOSX) -// + #if defined (__x86_64__) + #define RobotGo_64 + #else + #define RobotGo_32 + #endif + + #include + #include + // #include + // #include + + #ifdef MAC_OS_X_VERSION_10_11 + #define kAXValueCGPointType kAXValueTypeCGPoint + #define kAXValueCGSizeType kAXValueTypeCGSize + #endif #elif defined(USE_X11) -// + #if defined (__x86_64__) + #define RobotGo_64 + #else + #define RobotGo_32 + #endif + #include + #include + + #ifndef X_HAVE_UTF8_STRING + #error It appears that X_HAVE_UTF8_STRING is not defined - \ + please verify that your version of XLib is supported + #endif #elif defined(IS_WINDOWS) -// -#endif \ No newline at end of file + #if defined (_WIN64) + #define RobotGo_64 + #else + #define RobotGo_32 + #endif + + #include + //#include + #include +#endif + +typedef signed char int8; // Signed 8-Bit integer +typedef signed short int16; // Signed 16-Bit integer +typedef signed int int32; // Signed 32-Bit integer +typedef signed long long int64; // Signed 64-Bit integer + +typedef unsigned char uint8; // Unsigned 8-Bit integer +typedef unsigned short uint16; // Unsigned 16-Bit integer +typedef unsigned int uint32; // Unsigned 32-Bit integer +typedef unsigned long long uint64; // Unsigned 64-Bit integer + +typedef float real32; // 32-Bit float value +typedef double real64; // 64-Bit float value + +#ifdef RobotGo_64 + + typedef int64 intptr; // Signed pointer integer + typedef uint64 uintptr; // Unsigned pointer integer + +#else + + typedef int32 intptr; // Signed pointer integer + typedef uint32 uintptr; // Unsigned pointer integer + +#endif + +struct _MData{ +#if defined(IS_MACOSX) + CGWindowID CgID; // Handle to a CGWindowID + AXUIElementRef AxID; // Handle to a AXUIElementRef +#elif defined(USE_X11) + Window XWin; // Handle to an X11 window +#elif defined(IS_WINDOWS) + HWND HWnd; // Handle to a window HWND +#endif +}; + +typedef struct _MData MData; + +MData mData; + +bool setHandle(uintptr handle); +bool IsValid(); +bool IsAxEnabled(bool options); +MData GetActive (void); +void aWindow(); + +#if defined(IS_MACOSX) + + static Boolean (*gAXIsProcessTrustedWithOptions) (CFDictionaryRef); + + static CFStringRef* gkAXTrustedCheckOptionPrompt; + + AXError _AXUIElementGetWindow (AXUIElementRef, CGWindowID* out); + + static AXUIElementRef GetUIElement (CGWindowID win){ + intptr pid = 0; + // double_t pid=0; + + // Create array storing window + CGWindowID window[1] = { win }; + CFArrayRef wlist = CFArrayCreate (NULL, + (const void**) window, 1, NULL); + + // Get window info + CFArrayRef info =CGWindowListCreateDescriptionFromArray (wlist); + CFRelease (wlist); + + // Check whether the resulting array is populated + if (info != NULL && CFArrayGetCount (info) > 0){ + // Retrieve description from info array + CFDictionaryRef desc = (CFDictionaryRef) CFArrayGetValueAtIndex (info, 0); + + // Get window PID + CFNumberRef data =(CFNumberRef) + CFDictionaryGetValue (desc, kCGWindowOwnerPID); + + if (data != NULL) + CFNumberGetValue (data, kCFNumberIntType, &pid); + + // Return result + CFRelease (info); + } + + // Check if PID was retrieved + if (pid <= 0) return NULL; + + // Create an accessibility object using retrieved PID + AXUIElementRef application = AXUIElementCreateApplication (pid); + + if (application == 0) return NULL; + + CFArrayRef windows = NULL; + // Get all windows associated with the app + AXUIElementCopyAttributeValues (application, + kAXWindowsAttribute, 0, 1024, &windows); + + // Reference to resulting value + AXUIElementRef result = NULL; + + if (windows != NULL){ + int count = CFArrayGetCount (windows); + // Loop all windows in the process + for (CFIndex i = 0; i < count; ++i){ + // Get the element at the index + AXUIElementRef element = (AXUIElementRef) + CFArrayGetValueAtIndex (windows, i); + + CGWindowID temp = 0; + // Use undocumented API to get WindowID + _AXUIElementGetWindow (element, &temp); + + // Check results + if (temp == win){ + // Retain element + CFRetain (element); + result = element; + break; + } + } + + CFRelease (windows); + } + + CFRelease (application); + return result; + } +#elif defined(USE_X11) + + // Error Handling + + typedef int (*XErrorHandler) (Display*, XErrorEvent*); + + static int XHandleError (Display* dp, XErrorEvent* e) { return 0; } + + XErrorHandler mOld; + + void XDismissErrors (void){ + Display *rDisplay = XOpenDisplay(NULL); + // Save old handler and dismiss errors + mOld = XSetErrorHandler (XHandleError); + // Flush output buffer + XSync (rDisplay, False); + + // Reinstate old handler + XSetErrorHandler (mOld); + } + + // Definitions + + struct Hints + { + unsigned long Flags; + unsigned long Funcs; + unsigned long Decorations; + signed long Mode; + unsigned long Stat; + }; + + static Atom WM_STATE = None; + static Atom WM_ABOVE = None; + static Atom WM_HIDDEN = None; + static Atom WM_HMAX = None; + static Atom WM_VMAX = None; + + static Atom WM_DESKTOP = None; + static Atom WM_CURDESK = None; + + static Atom WM_NAME = None; + static Atom WM_UTF8 = None; + static Atom WM_PID = None; + static Atom WM_ACTIVE = None; + static Atom WM_HINTS = None; + static Atom WM_EXTENTS = None; + + //////////////////////////////////////////////////////////////////////////////// + + static void LoadAtoms (void) + { + Display *rDisplay = XOpenDisplay(NULL); + WM_STATE = XInternAtom (rDisplay, "_NET_WM_STATE", True); + WM_ABOVE = XInternAtom (rDisplay, "_NET_WM_STATE_ABOVE", True); + WM_HIDDEN = XInternAtom (rDisplay, "_NET_WM_STATE_HIDDEN", True); + WM_HMAX = XInternAtom (rDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", True); + WM_VMAX = XInternAtom (rDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", True); + + WM_DESKTOP = XInternAtom (rDisplay, "_NET_WM_DESKTOP", True); + WM_CURDESK = XInternAtom (rDisplay, "_NET_CURRENT_DESKTOP", True); + + WM_NAME = XInternAtom (rDisplay, "_NET_WM_NAME", True); + WM_UTF8 = XInternAtom (rDisplay, "UTF8_STRING", True); + WM_PID = XInternAtom (rDisplay, "_NET_WM_PID", True); + WM_ACTIVE = XInternAtom (rDisplay, "_NET_ACTIVE_WINDOW", True); + WM_HINTS = XInternAtom (rDisplay, "_MOTIF_WM_HINTS", True); + WM_EXTENTS = XInternAtom (rDisplay, "_NET_FRAME_EXTENTS", True); + } + + + + // Functions + static void* GetWindowProperty (MData win, Atom atom, uint32* items) + { + // Property variables + Atom type; int format; + unsigned long nItems; + unsigned long bAfter; + unsigned char* result = NULL; + + Display *rDisplay = XOpenDisplay(NULL); + // Check the atom + if (atom != None) + { + // Retrieve and validate the specified property + if (!XGetWindowProperty (rDisplay, win.XWin, atom, 0, + BUFSIZ, False, AnyPropertyType, &type, &format, + &nItems, &bAfter, &result) && result && nItems) + { + // Copy items result + if (items != NULL) + *items = (uint32) nItems; + + return result; + } + } + + // Reset the items result if valid + if (items != NULL) *items = 0; + + // Free the result if it got allocated + if (result != NULL) XFree (result); + return NULL; + } + + //////////////////////////////////////////////////////////////////////////////// + + #define STATE_TOPMOST 0 + #define STATE_MINIMIZE 1 + #define STATE_MAXIMIZE 2 + + +#elif defined(IS_WINDOWS) + // +#endif + +//int findwindow() + +uintptr ahandle = 0; + +void aWindow(uintptr handle){ +#if defined(IS_MACOSX) + + mData.CgID = 0; + mData.AxID = 0; + +#elif defined(USE_X11) + Display *rDisplay = XOpenDisplay(NULL); + // If atoms loaded + if (WM_PID == None){ + // Load all necessary atom properties + if (rDisplay != NULL) LoadAtoms(); + } + + mData.XWin = 0; + +#elif defined(IS_WINDOWS) + + mData.HWnd = 0; + +#endif + + setHandle(handle); +} + +bool IsValid (){ + aWindow(ahandle); + if(!IsAxEnabled(true))printf("%s\n", "Window:Accessibility API is disabled!\nFailed to enable access for assistive devices."); + MData actdata=GetActive(); + +#if defined(IS_MACOSX) + + mData.CgID=actdata.CgID; + mData.AxID=actdata.AxID; + + if (mData.CgID == 0 || mData.AxID == 0)return false; + + CFTypeRef r = NULL; + + // Attempt to get the window role + if (AXUIElementCopyAttributeValue(mData.AxID, + kAXRoleAttribute,&r) == kAXErrorSuccess && r){ + CFRelease (r); + return true; + } + + return false; + +#elif defined(USE_X11) + mData.XWin=actdata.XWin; + if (mData.XWin == 0)return false; + + Display *rDisplay = XOpenDisplay(NULL); + // Check for a valid X-Window display + if (rDisplay == NULL) return false; + + // Ignore X errors + XDismissErrors(); + + // Get the window PID property + void* result = GetWindowProperty(mData, WM_PID,NULL); + if (result == NULL) return false; + + // Free result and return true + XFree (result); return true; + +#elif defined(IS_WINDOWS) + mData.HWnd=actdata.HWnd; + + if (mData.HWnd == 0) + return false; + + return IsWindow (mData.HWnd) != 0; + +#endif +} + +bool IsAxEnabled (bool options){ +#if defined(IS_MACOSX) + + // Statically load all required functions one time + static dispatch_once_t once; dispatch_once (&once, + ^{ + // Open the framework + void* handle = dlopen + ("/System/Library/Frameworks/Application" + "Services.framework/ApplicationServices", RTLD_LAZY); + + // Validate the handle + if (handle != NULL){ + *(void**) (&gAXIsProcessTrustedWithOptions) = + dlsym (handle, "AXIsProcessTrustedWithOptions"); + + gkAXTrustedCheckOptionPrompt = (CFStringRef*) + dlsym (handle, "kAXTrustedCheckOptionPrompt"); + } + }); + + // Check for new OSX 10.9 function + if (gAXIsProcessTrustedWithOptions){ + // Check whether to show prompt + CFBooleanRef displayPrompt = options ? + kCFBooleanTrue : kCFBooleanFalse; + + // Convert display prompt value into a dictionary + const void* k[] = { *gkAXTrustedCheckOptionPrompt }; + const void* v[] = { displayPrompt }; + CFDictionaryRef o = CFDictionaryCreate + (NULL, k, v, 1, NULL, NULL); + + // Determine whether the process is actually trusted + bool result = (*gAXIsProcessTrustedWithOptions) (o); + + // Free memory + CFRelease (o); + return result; + }else{ + // Ignore deprecated warnings + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated-declarations" + + // Check whether we have accessibility access + return AXAPIEnabled() || AXIsProcessTrusted(); + #pragma clang diagnostic pop + } + +#elif defined(USE_X11) + + return true; + +#elif defined(IS_WINDOWS) + + return true; + +#endif +} + +// int +bool setHandle (uintptr handle){ +#if defined(IS_MACOSX) + // Release the AX element + if (mData.AxID != NULL)CFRelease (mData.AxID); + + // Reset both values + mData.CgID = 0; + mData.AxID = 0; + + if (handle == 0)return 0; + // return true; + + // Retrieve the window element + CGWindowID cgID = (CGWindowID) handle; + AXUIElementRef axID = GetUIElement (cgID); + + if (axID != NULL){ + mData.CgID = cgID; + mData.AxID = axID; + // return 0; + return true; + } + + // return 1; + return false; + +#elif defined(USE_X11) + + mData.XWin = (Window) handle; + + if (handle == 0) + return true; + + if (IsValid()) + return true; + + mData.XWin = 0; + return false; +#elif defined(IS_WINDOWS) + + mData.HWnd = (HWND) handle; + + if (handle == 0) + return true; + + if (IsValid()) + return true; + + mData.HWnd = 0; + return false; + +#endif +} + +//uint32 uintptr +uintptr getHandle(){ +#if defined(IS_MACOSX) + return (uintptr) mData.CgID; + +#elif defined(USE_X11) + return (uintptr) mData.XWin; + +#elif defined(IS_WINDOWS) + return (uintptr) mData.HWnd; + +#endif +} + +bool IsTopMost (void){ + // Check the window validity + if (!IsValid()) return false; +#if defined(IS_MACOSX) + + return false; // WARNING: Unavailable + +#elif defined(USE_X11) + + // Ignore X errors + // XDismissErrors (); + // return GetState (mData.XWin, STATE_TOPMOST); + +#elif defined(IS_WINDOWS) + + return (GetWindowLongPtr (mData.HWnd, + GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; + +#endif +} + +MData GetActive (void){ +#if defined(IS_MACOSX) + + MData result; + // Ignore deprecated warnings + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated-declarations" + + ProcessSerialNumber psn; pid_t pid; + // Attempt to retrieve the front process + if (GetFrontProcess (&psn ) != 0 || + GetProcessPID (&psn, &pid) != 0) + return result; + + #pragma clang diagnostic pop + + // Create accessibility object using focused PID + AXUIElementRef focused = AXUIElementCreateApplication (pid); + if (focused == NULL) return result; // Verify + + AXUIElementRef element; + // Retrieve the currently focused window + if (AXUIElementCopyAttributeValue (focused, + kAXFocusedWindowAttribute, (CFTypeRef*) + &element) == kAXErrorSuccess && element) + { + CGWindowID win = 0; + // Use undocumented API to get WID + if (_AXUIElementGetWindow (element, + &win) == kAXErrorSuccess && win) + { + // Manually set internals + result.CgID = win; + result.AxID = element; + } + + // Something went wrong + else CFRelease (element); + } + + CFRelease (focused); + + return result; + +#elif defined(USE_X11) + + MData result; + Display *rDisplay = XOpenDisplay(NULL); + // Check X-Window display + if (WM_ACTIVE == None || + rDisplay == NULL) + return result; + + // Ignore X errors + XDismissErrors(); + + // Get the current active window + result.XWin=XDefaultRootWindow (rDisplay); + void* active = GetWindowProperty(result,WM_ACTIVE,NULL); + + // Check result value + if (active != NULL) + { + // Extract window from the result + long window = *((long*) active); + XFree (active); if (window != 0) + { + // Set and return the foreground window + result.XWin = (Window) window; + return result; + } + } + + // Use input focus instead + Window window = None; + int revert = RevertToNone; + XGetInputFocus (rDisplay, + &window, &revert); + + // Return foreground window + result.XWin = window; + return result; + +#elif defined(IS_WINDOWS) + + // Attempt to get the foreground window multiple times in case + MData result; + + uint8 times = 0; + while (++times < 20) + { + HWND handle; + handle = GetForegroundWindow(); + if (handle != NULL){ + // mData.HWnd=(uintptr) handle; + result.HWnd= (HWND)handle; + return result; + } + Sleep (20); + } + + return result; + +#endif +} + + +void SetTopMost (bool state){ + // Check window validity + if (!IsValid()) return; +#if defined(IS_MACOSX) + + // WARNING: Unavailable + +#elif defined(USE_X11) + + // Ignore X errors + // XDismissErrors (); + // SetState (mData.XWin, STATE_TOPMOST, state); + +#elif defined(IS_WINDOWS) + + SetWindowPos (mData.HWnd, state ? + HWND_TOPMOST : HWND_NOTOPMOST, 0, + 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + +#endif +} + +//CloseWindow +void CloseWin(void){ + // Check window validity + if (!IsValid()) return; +#if defined(IS_MACOSX) + AXUIElementRef b = NULL; + + // Retrieve the close button of this window + if (AXUIElementCopyAttributeValue (mData.AxID, + kAXCloseButtonAttribute, (CFTypeRef*) &b) + == kAXErrorSuccess && b != NULL) + { + // Simulate button press on the close button + AXUIElementPerformAction (b, kAXPressAction); + CFRelease (b); + } + +#elif defined(USE_X11) + + Display *rDisplay = XOpenDisplay(NULL); + + // Ignore X errors + XDismissErrors(); + + // Close the window + XDestroyWindow (rDisplay, mData.XWin); + +#elif defined(IS_WINDOWS) + + PostMessage (mData.HWnd, WM_CLOSE, 0, 0); + +#endif +} + +char *GetTitle(){ + // Check if the window is valid + if (!IsValid()) return "IsValid failed."; + +#if defined(IS_MACOSX) + + CFStringRef data = NULL; + + // Determine the current title of the window + if (AXUIElementCopyAttributeValue (mData.AxID, + kAXTitleAttribute, (CFTypeRef*) &data) + == kAXErrorSuccess && data != NULL) + { + char conv[512]; + // Convert result to a C-String + CFStringGetCString (data, conv, + 512, kCFStringEncodingUTF8); + CFRelease (data); + char* s=(char*)calloc(100,sizeof(char*)); + if(s)strcpy(s,conv); + // return (char *)&conv; + return s; + } + + return "null"; + +#elif defined(USE_X11) + + void* result; + // Ignore X errors + XDismissErrors(); + + // Get window title (UTF-8) + result = GetWindowProperty(mData, WM_NAME,NULL); + + // Check result value + if (result != NULL){ + // Convert result to a string + char *name=(char*) result; + XFree (result); + + if (name!=NULL)return name; + } + + // Get window title (ASCII) + result = GetWindowProperty(mData, XA_WM_NAME,NULL); + + // Check result value + if (result != NULL){ + // Convert result to a string + char *name =(char*) result; + XFree (result); return name; + } + + return "null"; + +#elif defined(IS_WINDOWS) + + TCHAR name[512]; + return GetWindowText + (mData.HWnd, name, 512) > 0 ? name : "null"; + // return GetWindowText + // (mData.HWnd, name, 512) > 0 ? + // _UTF8Encode (name) : "null"; + +#endif +} +