2012-03-18 1 views
1

Я пытаюсь использовать некоторые события Apple в моем проекте Cocoa, чтобы получить доступ к приложению терминала. Я не хотел использовать встроенные AppleScripts или любые скомпилированные скрипты, поэтому я начал изучать NSAppleEventDescriptor.Получение свойства AppleScript объекта NSAppleEventDescriptor

Мне удалось создать новое окно с помощью команды do script, и мне удалось получить окно из возвращаемого значения. Единственное, что я хочу сделать прямо сейчас, это получить свойство этого окна.

У меня возникла идея, как получить такое свойство, поэтому я начал поиски в Интернете. К сожалению, не так много хороших примеров использования Apple Events, и я не смог найти то, что искал.

Итак, я начал копать глубже. И первое, что я сделал, это поиск кода для команды get в файле терминала .sdef. Я не смог найти его, поэтому я сделал grep в моем каталоге /System/, и я нашел /System/Library/Frameworks/AppleScriptKit.framework/Versions/A/Resources/AppleScriptKit.sdef. Я, очевидно, нашел ядро ​​синтаксиса AppleScript. У этого файла действительно был код с четырьмя символами getd.

Итак, теперь я знаю, что я должен использовать событие getd из Core Suite. Однако аргумент этой команды get был objectSpecifier. Я искал высокий и низкий для примера, который использует kAEGetData. Но мне не удалось найти код, из которого я мог бы чему-либо научиться.

Итак, я спрашиваю здесь: Как создать такой дескриптор objectSpecifier?

Это то, что я уже получил:

код, чтобы создать и получить дескриптор вкладки

NSAppleEventDescriptor *createEvent; 
NSAppleEventDescriptor *scriptParam; 
AppleEvent aeReply; 
OSErr err; 

/* Make the do script event */ 
createEvent = [NSAppleEventDescriptor 
       appleEventWithEventClass:kAECoreSuite 
       eventID:kAEDoScript 
       targetDescriptor:_applicationDescriptor 
       returnID:kAutoGenerateReturnID 
       transactionID:kAnyTransactionID]; 
if(createEvent == nil) { 
    NSLog(@"%s Failed to create a do script event", 
      __PRETTY_FUNCTION__); 
    return nil; 
} 

/* Make script parameter */ 
scriptParam = [NSAppleEventDescriptor descriptorWithString:@"echo Hello World"]; 
if(scriptParam == nil) { 
    NSLog(@"%s Failed to create the script parameter", 
      __PRETTY_FUNCTION__); 
    return nil; 
} 

/* Set parameter */ 
[createEvent setParamDescriptor:scriptParam forKeyword:keyDirectObject]; 

/* Send event */ 
err = AESendMessage([createEvent aeDesc], &aeReply, 
        kAEWaitReply | kAENeverInteract, kAEDefaultTimeout); 
if(err != noErr) { 
    NSLog(@"%s Failed to send the create command", 
      __PRETTY_FUNCTION__); 
    return nil; 
} 

/* Retrieve information */ 
{ 
    /* SEE BELOW TO SEE HOW I GET THE WINDOW DESCRIPTOR */ 
} 

Сейчас я стараюсь и преуспеть в получении окна этой вкладки

// NSAppleEventDescriptor *ansr is set to the result of the code above 

NSAppleEventDescriptor *mainObj; 
NSAppleEventDescriptor *desiredClass; 
NSAppleEventDescriptor *window; 

mainObj = [ansr paramDescriptorForKeyword:keyDirectObject]; 
if([mainObj descriptorType] != typeObjectSpecifier) { 
    NSLog(@"%s Main object was not an object specifier", 
      __PRETTY_FUNCTION__); 
    return nil; 
} 

desiredClass = [mainObj paramDescriptorForKeyword:keyAEDesiredClass]; 
if([desiredClass typeCodeValue] != kAETerminalTab) { 
    NSLog(@"%s Main object's desired class was not a Terminal tab", 
      __PRETTY_FUNCTION__); 
    return nil; 
} 

window = [mainObj paramDescriptorForKeyword:keyAEContainer]; 
if(window == nil) { 
    NSLog(@"%s Couldn't get container of the tab", 
      __PRETTY_FUNCTION__); 
    return nil; 
} 

desiredClass = [window paramDescriptorForKeyword:keyAEDesiredClass]; 
if([desiredClass typeCodeValue] != cWindow) { 
    NSLog(@"%s The container of the tab was not a window", 
      __PRETTY_FUNCTION__); 
    return nil; 
} 

return window; 

И теперь я терплю неудачу в getti нг, скажем, свойство границы

// _windowDescriptor is the result of the code above 

NSAppleEventDescriptor *getEvent; 
NSAppleEventDescriptor *prop; 
AppleEvent aeReply; 
NSAppleEventDescriptor *reply; 
FourCharCode propName; 
OSErr err; 

propName = keyAEBounds; 

/* Create get event */ 
getEvent = [NSAppleEventDescriptor 
      appleEventWithEventClass:kAECoreSuite 
      eventID:kAEGetData 
      targetDescriptor:_windowDescriptor 
      returnID:kAutoGenerateReturnID 
      transactionID:kAnyTransactionID]; 
if(getEvent == nil) { 
    NSLog(@"%s Failed to create a get event", 
      __PRETTY_FUNCTION__); 
    return NSZeroRect; 
} 

/* Get property */ 
prop = [NSAppleEventDescriptor 
     descriptorWithDescriptorType:typeProperty 
     bytes:&propName length:sizeof(propName)]; 
if(prop == nil) { 
    NSLog(@"%s Failed to create the bounds property", 
      __PRETTY_FUNCTION__); 
    return; 
} 

/* Set parameter */ 
[getEvent setParamDescriptor:prop forKeyword:keyDirectObject]; 

/* Exectue */ 
err = AESendMessage([getEvent aeDesc], &aeReply, 
        kAEWaitReply | kAENeverInteract, kAEDefaultTimeout); 
if(err != noErr) { 
    NSLog(@"%s Failed to send the get message", 
      __PRETTY_FUNCTION__); 
    return; 
} 

reply = [[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&aeReply]; 
[reply autorelease]; 

NSLog(@"Bounds: %@", reply); 

Как пояснялось, приведенный выше код не работает, только до последнего блока.
Заранее спасибо за помощь.

ответ

2

Благодаря Робу Кенигеру я преуспел в том, чего хотел.

Видимо, мне пришлось создать дескриптор записи, установить мои требуемые свойства и затем coerce это typeObjectSpecifier.

Кроме того, я был не прав в настройке дескриптора окна в качестве получателя моего события Apple.Вы всегда должны обращаться к самому приложению и устанавливать свойство from (keyAEContainer) прямого объекта в нужное вам окно.

Вот рабочий код, с немного NSLog -statements:

- (NSRect)bounds { 

    // ! ! ! 
    // _windowDescriptor is an instance variable which points to a valid 
    // window NSAppleEventDescriptor 
    // ! ! ! 

    NSAppleEventDescriptor *getEvent; 
    NSAppleEventDescriptor *objSpec; 
    NSAppleEventDescriptor *propEnum, *propType, *propSeld; 
    AppleEvent aeReply; 
    NSAppleEventDescriptor *reply; 
    FourCharCode propName; 
    OSErr err; 

    propName = keyAEBounds; 

    /* Create get event */ 
    getEvent = [NSAppleEventDescriptor 
       appleEventWithEventClass:kAECoreSuite 
       eventID:kAEGetData 
       targetDescriptor:[[FTMTerminalApp sharedApp] AEDescriptor] 
       returnID:kAutoGenerateReturnID 
       transactionID:kAnyTransactionID]; 
    if(getEvent == nil) { 
     NSLog(@"%s Failed to create a get event", 
       __PRETTY_FUNCTION__); 
     return NSZeroRect; 
    } 

    /* Get property */ 
    /* create object specifier main ojcect */ 
    objSpec = [[[NSAppleEventDescriptor alloc] initRecordDescriptor] 
       autorelease]; 
    if(objSpec == nil) { 
     NSLog(@"%s Failed to create the object specifier", 
       __PRETTY_FUNCTION__); 
     return NSZeroRect; 
    } 
    NSLog(@"%s Created object specifier %@", 
      __PRETTY_FUNCTION__, objSpec); 

    /* create property enum, we want a property */ 
    propEnum = [NSAppleEventDescriptor 
       descriptorWithEnumCode:formPropertyID]; 
    if(propEnum == nil) { 
     NSLog(@"%s Failed to create the property enum", 
       __PRETTY_FUNCTION__); 
     return NSZeroRect; 
    } 
    NSLog(@"%s Created property enum %@", 
      __PRETTY_FUNCTION__, propEnum); 
    [objSpec setDescriptor:propEnum forKeyword:keyAEKeyForm]; 

    /* create prop type */ 
    propType = [NSAppleEventDescriptor 
       descriptorWithTypeCode:typeProperty]; 
    if(propType == nil) { 
     NSLog(@"%s Failed to create the property type", 
       __PRETTY_FUNCTION__); 
     return NSZeroRect; 
    } 
    NSLog(@"%s Created property type %@", 
      __PRETTY_FUNCTION__, propType); 
    [objSpec setDescriptor:propType forKeyword:keyAEDesiredClass]; 

    /* create property key data */ 
    propSeld = [NSAppleEventDescriptor 
       descriptorWithTypeCode:keyAEBounds]; 
    if(propSeld == nil) { 
     NSLog(@"%s Failed to create the bounds property type", 
       __PRETTY_FUNCTION__); 
     return NSZeroRect; 
    } 
    NSLog(@"%s Created property key data %@", 
      __PRETTY_FUNCTION__, propSeld); 
    [objSpec setDescriptor:propSeld forKeyword:keyAEKeyData]; 

    /* Set destination */ 
    NSLog(@"%s Setting from key %@", 
      __PRETTY_FUNCTION__, _windowDescriptor); 
    [objSpec setDescriptor:_windowDescriptor forKeyword:keyAEContainer]; 

    /* Send message */ 
    objSpec = [objSpec coerceToDescriptorType:typeObjectSpecifier]; 
    NSLog(@"Coerced: %@", objSpec); 
    [getEvent setParamDescriptor:objSpec forKeyword:keyDirectObject]; 
    err = AESendMessage([getEvent aeDesc], &aeReply, 
         kAEWaitReply | kAENeverInteract, kAEDefaultTimeout); 
    if(err != noErr) { 
     NSLog(@"%s Failed to send the message (event = %@)", 
       __PRETTY_FUNCTION__, getEvent); 
     return NSZeroRect; 
    } 

    reply = [[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&aeReply]; 
    NSLog(@"BOUNDS = %@", reply); 
    [reply autorelease]; 

    return NSZeroRect; 
} 

Я надеюсь, что это поможет кому-то.

1

События Apple сложны в использовании. Если вы действительно не хотите тратить время на работу с запутанным и вообще неприятным API, я рекомендую вам сэкономить много времени и душевной боли, используя отличный класс Майкла Эша AEVTBuilder.

Это прекрасная обертка для какао для всего неприятного кода события Apple Carbon Apple.

+0

На самом деле, я бы очень хотел использовать ядро ​​API событий Apple. – v1Axvw

+0

Отлично, я рад, что смог немного помочь. –