Merge pull request #154 from go-vgo/dev

add GetBounds func and update code style
This commit is contained in:
vz 2018-08-13 10:54:45 -04:00 committed by GitHub
commit 1ec411fd39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 325 additions and 95 deletions

View File

@ -62,74 +62,74 @@ struct XSpecialCharacterMapping XSpecialCharacterTable[] = {
#endif
MMKeyCode keyCodeForChar(const char c)
{
#if defined(IS_MACOSX)
/* OS X does not appear to have a built-in function for this, so instead we
* have to write our own. */
static CFMutableDictionaryRef charToCodeDict = NULL;
CGKeyCode code;
UniChar character = c;
CFStringRef charStr = NULL;
MMKeyCode keyCodeForChar(const char c){
#if defined(IS_MACOSX)
/* OS X does not appear to have a built-in function for this, so instead we
* have to write our own. */
static CFMutableDictionaryRef charToCodeDict = NULL;
CGKeyCode code;
UniChar character = c;
CFStringRef charStr = NULL;
/* Generate table of keycodes and characters. */
if (charToCodeDict == NULL) {
size_t i;
charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
128,
&kCFCopyStringDictionaryKeyCallBacks,
NULL);
if (charToCodeDict == NULL) return UINT16_MAX;
/* Generate table of keycodes and characters. */
if (charToCodeDict == NULL) {
size_t i;
charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
128,
&kCFCopyStringDictionaryKeyCallBacks,
NULL);
if (charToCodeDict == NULL) return UINT16_MAX;
/* Loop through every keycode (0 - 127) to find its current mapping. */
for (i = 0; i < 128; ++i) {
CFStringRef string = createStringForKey((CGKeyCode)i);
if (string != NULL) {
CFDictionaryAddValue(charToCodeDict, string, (const void *)i);
CFRelease(string);
/* Loop through every keycode (0 - 127) to find its current mapping. */
for (i = 0; i < 128; ++i) {
CFStringRef string = createStringForKey((CGKeyCode)i);
if (string != NULL) {
CFDictionaryAddValue(charToCodeDict, string, (const void *)i);
CFRelease(string);
}
}
}
}
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
/* Our values may be NULL (0), so we need to use this function. */
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
(const void **)&code)) {
code = UINT16_MAX; /* Error */
}
/* Our values may be NULL (0), so we need to use this function. */
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
(const void **)&code)) {
code = UINT16_MAX; /* Error */
}
CFRelease(charStr);
return (MMKeyCode)code;
#elif defined(IS_WINDOWS)
return VkKeyScan(c);
#elif defined(USE_X11)
MMKeyCode code;
CFRelease(charStr);
return (MMKeyCode)code;
#elif defined(IS_WINDOWS)
return VkKeyScan(c);
#elif defined(USE_X11)
MMKeyCode code;
char buf[2];
buf[0] = c;
buf[1] = '\0';
char buf[2];
buf[0] = c;
buf[1] = '\0';
code = XStringToKeysym(buf);
if (code == NoSymbol) {
/* Some special keys are apparently not handled properly by
* XStringToKeysym() on some systems, so search for them instead in our
* mapping table. */
size_t i;
const size_t specialCharacterCount =
sizeof(XSpecialCharacterTable) / sizeof(XSpecialCharacterTable[0]);
for (i = 0; i < specialCharacterCount; ++i) {
if (c == XSpecialCharacterTable[i].name) {
code = XSpecialCharacterTable[i].code;
break;
code = XStringToKeysym(buf);
if (code == NoSymbol) {
/* Some special keys are apparently not handled properly by
* XStringToKeysym() on some systems, so search for them instead in our
* mapping table. */
size_t i;
const size_t specialCharacterCount =
sizeof(XSpecialCharacterTable) / sizeof(XSpecialCharacterTable[0]);
for (i = 0; i < specialCharacterCount; ++i) {
if (c == XSpecialCharacterTable[i].name) {
code = XSpecialCharacterTable[i].code;
break;
}
}
}
}
return code;
#endif
return code;
#endif
}
#if defined(IS_MACOSX)
CFStringRef createStringForKey(CGKeyCode keyCode){

View File

@ -29,8 +29,7 @@
#endif
#if defined(IS_MACOSX)
static io_connect_t _getAuxiliaryKeyDriver(void)
{
static io_connect_t _getAuxiliaryKeyDriver(void){
static mach_port_t sEventDrvrRef = 0;
mach_port_t masterPort, service, iter;
kern_return_t kr;
@ -52,13 +51,11 @@ static io_connect_t _getAuxiliaryKeyDriver(void)
#endif
#if defined(IS_WINDOWS)
void win32KeyEvent(int key, MMKeyFlags flags)
{
void win32KeyEvent(int key, MMKeyFlags flags){
int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);
/* Set the scan code for extended keys */
switch (key)
{
switch (key){
case VK_RCONTROL:
case VK_SNAPSHOT: /* Print Screen */
case VK_RMENU: /* Right Alt / Alt Gr */
@ -106,8 +103,7 @@ void win32KeyEvent(int key, MMKeyFlags flags)
}
#endif
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags)
{
void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags){
#if defined(IS_MACOSX)
/* The media keys all have 1000 added to them to help us detect them. */
if (code >= 1000) {
@ -156,14 +152,12 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags)
#endif
}
void tapKeyCode(MMKeyCode code, MMKeyFlags flags)
{
void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
toggleKeyCode(code, true, flags);
toggleKeyCode(code, false, flags);
}
void toggleKey(char c, const bool down, MMKeyFlags flags)
{
void toggleKey(char c, const bool down, MMKeyFlags flags){
MMKeyCode keyCode = keyCodeForChar(c);
//Prevent unused variable warning for Mac and Linux.
@ -185,15 +179,13 @@ void toggleKey(char c, const bool down, MMKeyFlags flags)
toggleKeyCode(keyCode, down, flags);
}
void tapKey(char c, MMKeyFlags flags)
{
void tapKey(char c, MMKeyFlags flags){
toggleKey(c, true, flags);
toggleKey(c, false, flags);
}
#if defined(IS_MACOSX)
void toggleUnicode(UniChar ch, const bool down)
{
void toggleUnicode(UniChar ch, const bool down){
/* This function relies on the convenient
* CGEventKeyboardSetUnicodeString(), which allows us to not have to
* convert characters to a keycode, but does not support adding modifier

View File

@ -1398,6 +1398,12 @@ func GetPID() int32 {
return int32(pid)
}
// internalGetBounds get the window bounds
func internalGetBounds(pid int32, hwnd int) (int, int, int, int) {
bounds := C.get_bounds(C.uintptr(pid), C.uintptr(hwnd))
return int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H)
}
// Pids get the all process id
func Pids() ([]int32, error) {
var ret []int32

View File

@ -12,6 +12,16 @@
package robotgo
// GetBounds get the window bounds
func GetBounds(pid int32, args ...int) (int, int, int, int) {
var hwnd int
if len(args) > 0 {
hwnd = args[0]
}
return internalGetBounds(pid, hwnd)
}
// ActivePID active the window by PID,
// If args[0] > 0 on the Windows platform via a window handle to active
func ActivePID(pid int32, args ...int) error {

View File

@ -23,6 +23,24 @@ import (
var xu *xgbutil.XUtil
// GetBounds get the window bounds
func GetBounds(pid int32, args ...int) (int, int, int, int) {
var hwnd int
if len(args) > 0 {
hwnd = args[0]
return internalGetBounds(pid, hwnd)
}
xid, err := GetXId(xu, pid)
if err != nil {
log.Println("GetXidFromPid errors is: ", err)
return 0, 0, 0, 0
}
return internalGetBounds(int32(xid), hwnd)
}
// ActivePIDC active the window by PID,
// If args[0] > 0 on the unix platform via a xid to active
func ActivePIDC(pid int32, args ...int) {
@ -34,18 +52,9 @@ func ActivePIDC(pid int32, args ...int) {
return
}
if xu == nil {
var err error
xu, err = xgbutil.NewConn()
if err != nil {
log.Println("xgbutil.NewConn errors is: ", err)
return
}
}
xid, err := getXidFromPid(xu, pid)
xid, err := GetXId(xu, pid)
if err != nil {
log.Println("getXidFromPid errors is: ", err)
log.Println("GetXidFromPid errors is: ", err)
return
}
@ -73,7 +82,8 @@ func ActivePID(pid int32, args ...int) error {
return nil
}
xid, err := getXidFromPid(xu, pid)
// get xid from pid
xid, err := GetXidFromPid(xu, pid)
if err != nil {
return err
}
@ -86,7 +96,23 @@ func ActivePID(pid int32, args ...int) error {
return nil
}
func getXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
// GetXId get the xid
func GetXId(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
if xu == nil {
var err error
xu, err = xgbutil.NewConn()
if err != nil {
// log.Println("xgbutil.NewConn errors is: ", err)
return 0, err
}
}
xid, err := GetXidFromPid(xu, pid)
return xid, err
}
// GetXidFromPid get the xide from pid
func GetXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
windows, err := ewmh.ClientListGet(xu)
if err != nil {
return 0, err
@ -102,5 +128,5 @@ func getXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
}
}
return 0, errors.New("failed to find a window with a matching pid")
return 0, errors.New("failed to find a window with a matching pid.")
}

View File

@ -11,6 +11,7 @@
#include "alert_c.h"
#include "window.h"
#include "win32.h"
#include "win_sys.h"
int show_alert(const char *title, const char *msg,
const char *defaultButton, const char *cancelButton){

View File

@ -26,6 +26,15 @@ typedef struct _MData MData;
MData mData;
struct _Bounds{
int32 X; // Top left X coordinate
int32 Y; // Top left Y coordinate
int32 W; // Total bounds width
int32 H; // Total bounds height
};
typedef struct _Bounds Bounds;
#if defined(IS_MACOSX)
static Boolean(*gAXIsProcessTrustedWithOptions) (CFDictionaryRef);
@ -255,6 +264,30 @@ MData mData;
}
}
static Bounds GetFrame(MData win){
Bounds frame;
// Retrieve frame bounds
if (WM_EXTENTS != None) {
long* result; uint32 nItems = 0;
// Get the window extents property
result = (long*) GetWindowProperty(win, WM_EXTENTS, &nItems);
// Verify the results
if (result != NULL) {
if (nItems == 4) {
frame.X = (int32) result[0];
frame.Y = (int32) result[2];
frame.W = (int32) result[0] + (int32) result[1];
frame.H = (int32) result[2] + (int32) result[3];
}
XFree(result);
}
}
return frame;
}
#elif defined(IS_WINDOWS)
//

162
window/win_sys.h Normal file
View File

@ -0,0 +1,162 @@
// #include "../base/os.h"
Bounds get_client(uintptr pid, uintptr isHwnd);
Bounds get_bounds(uintptr pid, uintptr isHwnd){
// Check if the window is valid
Bounds bounds;
if (!IsValid()) { return bounds; }
#if defined(IS_MACOSX)
// Bounds bounds;
AXValueRef axp = NULL;
AXValueRef axs = NULL;
AXUIElementRef AxID = AXUIElementCreateApplication(pid);
// Determine the current point of the window
if (AXUIElementCopyAttributeValue(AxID,
kAXPositionAttribute, (CFTypeRef*) &axp)
!= kAXErrorSuccess || axp == NULL){
goto exit;
}
// Determine the current size of the window
if (AXUIElementCopyAttributeValue(AxID,
kAXSizeAttribute, (CFTypeRef*) &axs)
!= kAXErrorSuccess || axs == NULL){
goto exit;
}
CGPoint p; CGSize s;
// Attempt to convert both values into atomic types
if (AXValueGetValue(axp, kAXValueCGPointType, &p) &&
AXValueGetValue(axs, kAXValueCGSizeType, &s)){
bounds.X = p.x;
bounds.Y = p.y;
bounds.W = s.width;
bounds.H = s.height;
}
exit:
if (axp != NULL) { CFRelease(axp); }
if (axs != NULL) { CFRelease(axs); }
return bounds;
#elif defined(USE_X11)
// Ignore X errors
XDismissErrors();
MData win;
win.XWin = (Window)pid;
Bounds client = get_client(pid, isHwnd);
Bounds frame = GetFrame(win);
bounds.X = client.X - frame.X;
bounds.Y = client.Y - frame.Y;
bounds.W = client.W + frame.W;
bounds.H = client.H + frame.H;
return bounds;
#elif defined(IS_WINDOWS)
HWND hwnd;
if (isHwnd == 0) {
hwnd= GetHwndByPId(pid);
} else {
hwnd = (HWND)pid;
}
RECT rect = { 0 };
GetWindowRect(hwnd, &rect);
bounds.X = rect.left;
bounds.Y = rect.top;
bounds.W = rect.right - rect.left;
bounds.H = rect.bottom - rect.top;
return bounds;
#endif
}
Bounds get_client(uintptr pid, uintptr isHwnd){
// Check if the window is valid
Bounds bounds;
if (!IsValid()) { return bounds; }
#if defined(IS_MACOSX)
return get_bounds(pid, isHwnd);
#elif defined(USE_X11)
Display *rDisplay = XOpenDisplay(NULL);
// Ignore X errors
XDismissErrors();
MData win;
win.XWin = (Window)pid;
// Property variables
Window root, parent;
Window* children;
unsigned int count;
int32 x = 0, y = 0;
// Check if the window is the root
XQueryTree(rDisplay, win.XWin,
&root, &parent, &children, &count);
if (children) { XFree(children); }
// Retrieve window attributes
XWindowAttributes attr = { 0 };
XGetWindowAttributes(rDisplay, win.XWin, &attr);
// Coordinates must be translated
if (parent != attr.root){
XTranslateCoordinates(rDisplay, win.XWin, attr.root, attr.x,
attr.y, &x, &y, &parent);
}
// Coordinates can be left alone
else {
x = attr.x;
y = attr.y;
}
// Return resulting window bounds
bounds.X = x;
bounds.Y = y;
bounds.W = attr.width;
bounds.H = attr.height;
return bounds;
#elif defined(IS_WINDOWS)
HWND hwnd;
if (isHwnd == 0) {
hwnd= GetHwndByPId(pid);
} else {
hwnd = (HWND)pid;
}
RECT rect = { 0 };
GetClientRect(hwnd, &rect);
POINT point;
point.x = rect.left;
point.y = rect.top;
// Convert the client point to screen
ClientToScreen(hwnd, &point);
bounds.X = point.x;
bounds.Y = point.y;
bounds.W = rect.right - rect.left;
bounds.H = rect.bottom - rect.top;
return bounds;
#endif
}

View File

@ -170,8 +170,8 @@ bool setHandle(uintptr handle){
mData.AxID = 0;
if (handle == 0){
return 0;
// return true;
// return 0;
return true;
}
// Retrieve the window element
@ -275,7 +275,7 @@ bool IsMinimized(void){
// Ignore X errors
// XDismissErrors();
// return GetState (mData.XWin, STATE_MINIMIZE);
// return GetState(mData.XWin, STATE_MINIMIZE);
#elif defined(IS_WINDOWS)
@ -298,7 +298,7 @@ bool IsMaximized(void){
// Ignore X errors
// XDismissErrors();
// return GetState (mData.XWin, STATE_MAXIMIZE);
// return GetState(mData.XWin, STATE_MAXIMIZE);
#elif defined(IS_WINDOWS)
@ -447,7 +447,7 @@ MData GetActive(void){
// Get the current active window
result.XWin = XDefaultRootWindow(rDisplay);
void* active = GetWindowProperty(result,WM_ACTIVE,NULL);
void* active = GetWindowProperty(result, WM_ACTIVE, NULL);
// Check result value
if (active != NULL) {
@ -607,8 +607,9 @@ char *GetTitle(){
#elif defined(IS_WINDOWS)
return GetWindowText
(mData.HWnd, mData.Title, 512) > 0 ? mData.Title : "";
return GetWindowText(
mData.HWnd, mData.Title, 512) > 0 ?
mData.Title : "";
// return GetWindowText
// (mData.HWnd, name, 512) > 0 ?
// _UTF8Encode(name) : "null";
@ -624,10 +625,9 @@ int32 WGetPID(void){
pid_t pid = 0;
// Attempt to retrieve the window pid
if (AXUIElementGetPid(mData.AxID, &pid)
== kAXErrorSuccess) {
return pid;
}
if (AXUIElementGetPid(mData.AxID, &pid)== kAXErrorSuccess) {
return pid;
}
return 0;