انقل النوافذ الأخرى على نظام التشغيل Mac OS X باستخدام Accessibility API

StackOverflow https://stackoverflow.com//questions/21069066

سؤال

أحاول استخدام Accessibility API لتغيير موضع نوافذ التطبيقات الأخرى. ما أرغب في فعله هو الحصول على جميع النوافذ التي تظهر على الشاشة من جميع التطبيقات، ثم نقلها جميعها بإزاحة معينة (على سبيل المثال 5 أو 10 أو أي قيمة).أواجه صعوبات في القيام بذلك لأن هذا هو اليوم الأول من البرمجة في Objective-C بالنسبة لي.

هذا ما أفعله الآن.أولاً، أجد قائمة النوافذ ومعرفات PID الخاصة بها التي تستخدمها CGWindowListCopyWindowInfo.ثم لكل نافذة أستخدمها AXUIElementCreateApplication للحصول على AXUIElementRef من خلال النافذة.بعد ذلك، يجب أن أستخدم AXUIElementCopyAttributeValue مع السمة kAXPositionAttribute (والذي أفشل في الحصول على الموضع المناسب، دائما الحصول على الأصفار).أخيرًا، يجب أن أضيف الإزاحة المطلوبة إلى الموضع والاستخدام AXUIElementSetAttributeValue مع السمة kAXPositionAttribute ونقطة الموضع الجديدة (التي أحصل على أخطاء وقت التشغيل حتى لو قمت بتعيين قيم مطلقة مثل 0،0).

هل يمكن لأحد أن يساعدني بمقتطف للقيام بما وصفته أعلاه، حيث أنني جربت أشياء كثيرة دون أي حظ.أيضًا، لا ينبغي أن يكون الأمر تمامًا كما قررت تنفيذه أعلاه.إذا كانت هناك طريقة أفضل للقيام بذلك، فسأكون سعيدًا بتغييرها.

تحديث:كما هو مطلوب في التعليق، إليك مقتطف التعليمات البرمجية لإحدى المحاولات:

// Get all the windows
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
NSArray* arr = CFBridgingRelease(windowList);
// Loop through the windows
for (NSMutableDictionary* entry in arr)
{
    // Get window PID
    pid_t pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
    // Get AXUIElement using PID
    AXUIElementRef elementRef = AXUIElementCreateApplication(pid);
    CFTypeRef position;
    CGPoint point;
    // Get the position attribute of the window (maybe something is wrong?)
    AXUIElementCopyAttributeValue(elementRef, kAXPositionAttribute, (CFTypeRef *)&position);
    AXValueGetValue(position, kAXValueCGPointType, &point);
    // Debugging (always zeros?)
    NSLog(@"point=%@", point);
    // Create a point
    NSPoint newPoint;
    newPoint.x = 0;
    newPoint.y = 0;
    position = (CFTypeRef)(AXValueCreate(kAXValueCGPointType, (const void *)&newPoint));
    // Set the position attribute of the window (runtime error over here)
    AXUIElementSetAttributeValue(elementRef, kAXPositionAttribute, (CFTypeRef *)&position);
}
هل كانت مفيدة؟

المحلول

استنادًا إلى نموذج التعليمات البرمجية الخاص بك (الذي تم تعديله قليلاً، نظرًا لأن ما نشرته لا يتم تجميعه وسيتعطل دون تعديل)، فقد أجريت بعض التجارب.

وهنا بعض التحذيرات:

  • أنت تقوم باسترجاع طلب بواسطة PID، ولكن بعد ذلك يتم التصرف عليه كما لو كان نافذة.هذا هو جوهر مشكلتك، لكنه مجرد بداية الحل.
  • ستحتاج إلى الاطلاع على قائمة النوافذ الخاصة بكائن تطبيق إمكانية الوصول للعثور على النوافذ القابلة لإعادة تحديد موقعها والتي يمكنك نقلها باستخدام Accessibility Framework.
  • CGWindowListCopyWindowInfo سيعرض نوافذ "كل ما يظهر على الشاشة" عند سؤالك عن الطريقة التي تسميها بها، لكنه لا يضمن أن تكون هذه إما "نوافذ مستخدم" أو نوافذ ذات إمكانية الوصول.تحتوي معظم عناصر شريط القائمة على نافذة جذر "على الشاشة" ولا يمكن الوصول إلى معظمها (والتي تظهر عندما تحاول السير في شجرة إمكانية الوصول لمعرفات PID التي تسترجعها).
  • قد تجد أن اختبار AXRole مفيد، أو قد تجد سمات إمكانية الوصول الأخرى للنافذة أكثر فائدة في تحديد ما إذا كان سيتم نقل النوافذ أم لا.

لقد قمت بتضمين تعديلات على التعليمات البرمجية الخاصة بك هنا (سيتم تشغيل هذا دون تعطل)، والتي ستلتقط معلومات النافذة ذات الصلة من التطبيقات التي تستردها عبر PID ثم تحرك النوافذ.لدي بيان نوم حتى أتمكن من إيقاف التنفيذ، حيث كنت أختبر تأثير الحركة للتو:

#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <ApplicationServices/ApplicationServices.h>

int main(int argc, char *argv[]) {
    @autoreleasepool {
    // Get all the windows
    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
    NSArray* arr = CFBridgingRelease(windowList);
    // Loop through the windows
    for (NSMutableDictionary* entry in arr)
    {
        // Get window PID
        pid_t pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
        // Get AXUIElement using PID
        AXUIElementRef appRef = AXUIElementCreateApplication(pid);
        NSLog(@"Ref = %@",appRef);

        // Get the windows
        CFArrayRef windowList;
        AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute, (CFTypeRef *)&windowList);
        NSLog(@"WindowList = %@", windowList);
        if ((!windowList) || CFArrayGetCount(windowList)<1)
            continue;


        // get just the first window for now
        AXUIElementRef windowRef = (AXUIElementRef) CFArrayGetValueAtIndex( windowList, 0);
        CFTypeRef role;
        AXUIElementCopyAttributeValue(windowRef, kAXRoleAttribute, (CFTypeRef *)&role);         
        CFTypeRef position;
        CGPoint point;

        // Get the position attribute of the window (maybe something is wrong?)
        AXUIElementCopyAttributeValue(windowRef, kAXPositionAttribute, (CFTypeRef *)&position);
        AXValueGetValue(position, kAXValueCGPointType, &point);
        // Debugging (always zeros?)
        NSLog(@"point=%f,%f", point.x,point.y);
        // Create a point
        CGPoint newPoint;
        newPoint.x = 0;
        newPoint.y = 0;
        NSLog(@"Create");
        position = (CFTypeRef)(AXValueCreate(kAXValueCGPointType, (const void *)&newPoint));
        // Set the position attribute of the window (runtime error over here)
        NSLog(@"SetAttribute");
        AXUIElementSetAttributeValue(windowRef, kAXPositionAttribute, position);
        sleep(5);
    }       
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top