Get browser URL from third application [closed]












0















I am working on MacOS application and I would like to know if there is a way to get url of active browser from it. Application is done in C++.



I would like to get it without having to use AppleScript.



Is that possible?



Thanks










share|improve this question













closed as too broad by Owen Pauling, RedX, mkaes, EdChum, demonplus Nov 28 '18 at 12:17


Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.























    0















    I am working on MacOS application and I would like to know if there is a way to get url of active browser from it. Application is done in C++.



    I would like to get it without having to use AppleScript.



    Is that possible?



    Thanks










    share|improve this question













    closed as too broad by Owen Pauling, RedX, mkaes, EdChum, demonplus Nov 28 '18 at 12:17


    Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.





















      0












      0








      0








      I am working on MacOS application and I would like to know if there is a way to get url of active browser from it. Application is done in C++.



      I would like to get it without having to use AppleScript.



      Is that possible?



      Thanks










      share|improve this question














      I am working on MacOS application and I would like to know if there is a way to get url of active browser from it. Application is done in C++.



      I would like to get it without having to use AppleScript.



      Is that possible?



      Thanks







      c++ macos url applescript






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 28 '18 at 8:26









      RuLoViCRuLoViC

      244114




      244114




      closed as too broad by Owen Pauling, RedX, mkaes, EdChum, demonplus Nov 28 '18 at 12:17


      Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.









      closed as too broad by Owen Pauling, RedX, mkaes, EdChum, demonplus Nov 28 '18 at 12:17


      Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.


























          1 Answer
          1






          active

          oldest

          votes


















          1














          This isn't an easy answer but the good news is "yes, it's possible to do this without having to use AppleScript" and the bad news is "you'll have to use AppleScript to begin with".



          Let me elaborate a bit: browser apps typically have an Applescript dictionary (which you can see by using the "Script Editor" application found in your /Applications/Utilities folder. Here's what the dictionary looks like for Google Chrome:Script Editor Dictionary for Google Chrome
          You'll see I've found the "tab" class and in there you'll see the URL property.



          So what you need to do is work up an AppleScript first to fetch the windows for the browser you're targeting. Then, when that's working, you need to convert the AppleScript to the underlying, raw AppleEvents (which is what AppleScripts compile to). Both AppleScripts and AppleEvents can be done in code.



          The answer you're really looking for (e.g. "can I use some top secret API or send a URL from my code into some open port on my local machine to query the browser?") doesn't exist, as far as I know. AppleScript and AppleEvents are the longtime ways Apple provides to automate most apps and you'll need to leverage that.



          If you decide to go ahead with using AppleScript and possibly converting them to AppleEvents, here's what I would do.



          1) Find publicly available AppleScripts to do the work you want.



          2) Convert the AppleScript to AppleEvents



          3) Code up the AppleEvents.



          For 1, here's a script that goes through every window in Safari, which I got from this tutorial:



          tell application "Safari"

          --Variables
          set windowCount to number of windows
          set docText to ""

          --Repeat for Every Window
          repeat with x from 1 to windowCount
          set tabCount to number of tabs in window x

          --Repeat for Every Tab in Current Window
          repeat with y from 1 to tabCount
          --Get Tab Name & URL
          set tabName to name of tab y of window x
          set tabURL to URL of tab y of window x
          end repeat

          end repeat
          end tell


          For step 2, I think you can use the Accessory View Pane in Script Editor to see the raw events and results produced.



          For step 3, this ancient code that I wrote in C will get the URL for a browser window given a window ID.



          OSStatus CreateTheAppleEventForGetURL( OSType appSignature, long windowid, char **retval) 
          {
          OSErr err = noErr;
          AEAddressDesc targetAddress;
          AEDescList replyDesc = { typeNull, nil };
          AEKeyword keyword;
          DescType desiredClass;
          AEDesc replySingle, theOptionalAttributeDesc, theSeldDesc,theObjSpec,theThirdObjSpec,theSecondObjSpec,theFormDesc,theNullDesc;
          AppleEvent theEvent, reply;
          AEIdleUPP theIdleProc;
          Boolean gotReply = false;
          long errNumber=0;
          long buffer;
          Size actualSize;
          char *result = NULL;

          theIdleProc = NewAEIdleUPP((AEIdleProcPtr)&TheIdleFunction );
          if( NULL != theIdleProc )
          {
          err = AECreateDesc( typeApplSignature, &appSignature, sizeof( appSignature ), &targetAddress );

          if( noErr == err )
          {
          err = AECreateAppleEvent( 'core', 'getd', &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent );
          buffer = 0x10000;
          err = AECreateDesc('magn', &buffer, 4, &theOptionalAttributeDesc);
          if( noErr == err )
          {
          err = AECreateDesc(typeNull, nil, 0, &theNullDesc);
          desiredClass = 'cwin';
          buffer = 'ID ';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          buffer = windowid;
          err = AECreateDesc(typeLongInteger,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theNullDesc,'ID ',&theSeldDesc,true,&theThirdObjSpec);
          buffer = 'docu';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          desiredClass = 'prop';
          err = CreateObjSpecifier(desiredClass,&theThirdObjSpec,'prop',&theSeldDesc,true,&theSecondObjSpec);
          buffer = 'prop';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          err = AECreateDesc(typeNull, nil, 0, &theObjSpec);
          buffer = 'pURL';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theSecondObjSpec,'prop',&theSeldDesc,true,&theObjSpec);
          err = AEPutAttributeDesc(&theEvent,'csig',&theOptionalAttributeDesc);
          err = AEPutParamDesc(&theEvent,keyDirectObject, &theObjSpec);
          }
          if( noErr == err )
          {
          err = AESend( &theEvent, &reply, kAEWaitReply + kAENeverInteract, kAENormalPriority, 120, theIdleProc, NULL );
          if( noErr == err )
          {
          gotReply = true;
          }
          else
          {
          gotReply = false;
          }
          err = AEDisposeDesc(&theObjSpec);
          err = AEDisposeDesc(&theOptionalAttributeDesc);
          err = AEDisposeDesc(&theSeldDesc);
          err = AEDisposeDesc(&theSecondObjSpec);
          err = AEDisposeDesc(&theThirdObjSpec);
          err = AEDisposeDesc(&theFormDesc);
          err = AEDisposeDesc(&theNullDesc);
          }
          }
          err = AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, NULL, &errNumber, sizeof(errNumber), &actualSize);
          if(true == gotReply )
          {
          err = AEGetParamDesc( &reply, keyDirectObject, typeAEList, &replyDesc );

          keyword = typeAEList;
          err = AEGetNthDesc( &replyDesc, 1, typeUnicodeText, &keyword, &replySingle);

          if( noErr == err)
          {
          OSStatus status;
          Size theSize;
          UnicodeMapping iUnicodeMapping;
          UnicodeToTextInfo theInfo;
          UniChar theName[512];
          unsigned char crapola[512]; // a.k.a. a pstring

          iUnicodeMapping.unicodeEncoding = kTextEncodingUnicodeDefault;
          iUnicodeMapping.otherEncoding = kTextEncodingMacRoman;
          iUnicodeMapping.mappingVersion = kUnicodeUseLatestMapping;
          status = CreateUnicodeToTextInfo(&iUnicodeMapping,&theInfo);
          theSize = AEGetDescDataSize(&replySingle);

          err = AEGetDescData(&replySingle,&theName,512);
          if( noErr == err)
          {
          err = ConvertFromUnicodeToPString(theInfo,theSize,theName,crapola);
          if( noErr == err )
          {
          result = malloc( theSize * sizeof( char ));
          if( NULL != result )
          {
          p2cstrcpy(result,crapola);
          printf( "URL returned is %sn", result);
          }
          }
          }
          status = DisposeUnicodeToTextInfo(&theInfo);
          }
          }
          err = AEDisposeDesc( &targetAddress );
          err = AEDisposeDesc( &replySingle );
          DisposeAEIdleUPP( theIdleProc );
          }
          if( NULL != retval )
          *retval = result;
          return(err);
          }


          I'm sure it won't compile, since a number of Carbon API's have been updated and renamed since macOS 10.8, but you get the idea.



          Hopefully this long essay helps you out!






          share|improve this answer
























          • Nice! Really well explained answer! I will dig into it. Thanks

            – RuLoViC
            Nov 28 '18 at 9:48











          • The reason I responded so quickly was because I've done this same kind of work on two separate projects (but this was more than 10 years ago) and it can be incredibly time consuming and frustrating, so hopefully my efforts will help set you on the right path to success. I'll be thrilled (and upvote) if somebody does come and post a better answer than me, in case there actually is a more optimal solution for you.

            – Michael Dautermann
            Nov 28 '18 at 9:51











          • Dauteman: in ay case, your solution needs to have accessibility or automation enabled for your app, right? otherwise it won't work. Am I right?

            – RuLoViC
            Nov 29 '18 at 11:19






          • 1





            No, apps will respond to AppleScript or Apple events regardless of accessibility settings. If the browser is sandboxed, that might be a different story, but I haven’t tested that scenario.

            – Michael Dautermann
            Nov 29 '18 at 11:21


















          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          This isn't an easy answer but the good news is "yes, it's possible to do this without having to use AppleScript" and the bad news is "you'll have to use AppleScript to begin with".



          Let me elaborate a bit: browser apps typically have an Applescript dictionary (which you can see by using the "Script Editor" application found in your /Applications/Utilities folder. Here's what the dictionary looks like for Google Chrome:Script Editor Dictionary for Google Chrome
          You'll see I've found the "tab" class and in there you'll see the URL property.



          So what you need to do is work up an AppleScript first to fetch the windows for the browser you're targeting. Then, when that's working, you need to convert the AppleScript to the underlying, raw AppleEvents (which is what AppleScripts compile to). Both AppleScripts and AppleEvents can be done in code.



          The answer you're really looking for (e.g. "can I use some top secret API or send a URL from my code into some open port on my local machine to query the browser?") doesn't exist, as far as I know. AppleScript and AppleEvents are the longtime ways Apple provides to automate most apps and you'll need to leverage that.



          If you decide to go ahead with using AppleScript and possibly converting them to AppleEvents, here's what I would do.



          1) Find publicly available AppleScripts to do the work you want.



          2) Convert the AppleScript to AppleEvents



          3) Code up the AppleEvents.



          For 1, here's a script that goes through every window in Safari, which I got from this tutorial:



          tell application "Safari"

          --Variables
          set windowCount to number of windows
          set docText to ""

          --Repeat for Every Window
          repeat with x from 1 to windowCount
          set tabCount to number of tabs in window x

          --Repeat for Every Tab in Current Window
          repeat with y from 1 to tabCount
          --Get Tab Name & URL
          set tabName to name of tab y of window x
          set tabURL to URL of tab y of window x
          end repeat

          end repeat
          end tell


          For step 2, I think you can use the Accessory View Pane in Script Editor to see the raw events and results produced.



          For step 3, this ancient code that I wrote in C will get the URL for a browser window given a window ID.



          OSStatus CreateTheAppleEventForGetURL( OSType appSignature, long windowid, char **retval) 
          {
          OSErr err = noErr;
          AEAddressDesc targetAddress;
          AEDescList replyDesc = { typeNull, nil };
          AEKeyword keyword;
          DescType desiredClass;
          AEDesc replySingle, theOptionalAttributeDesc, theSeldDesc,theObjSpec,theThirdObjSpec,theSecondObjSpec,theFormDesc,theNullDesc;
          AppleEvent theEvent, reply;
          AEIdleUPP theIdleProc;
          Boolean gotReply = false;
          long errNumber=0;
          long buffer;
          Size actualSize;
          char *result = NULL;

          theIdleProc = NewAEIdleUPP((AEIdleProcPtr)&TheIdleFunction );
          if( NULL != theIdleProc )
          {
          err = AECreateDesc( typeApplSignature, &appSignature, sizeof( appSignature ), &targetAddress );

          if( noErr == err )
          {
          err = AECreateAppleEvent( 'core', 'getd', &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent );
          buffer = 0x10000;
          err = AECreateDesc('magn', &buffer, 4, &theOptionalAttributeDesc);
          if( noErr == err )
          {
          err = AECreateDesc(typeNull, nil, 0, &theNullDesc);
          desiredClass = 'cwin';
          buffer = 'ID ';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          buffer = windowid;
          err = AECreateDesc(typeLongInteger,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theNullDesc,'ID ',&theSeldDesc,true,&theThirdObjSpec);
          buffer = 'docu';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          desiredClass = 'prop';
          err = CreateObjSpecifier(desiredClass,&theThirdObjSpec,'prop',&theSeldDesc,true,&theSecondObjSpec);
          buffer = 'prop';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          err = AECreateDesc(typeNull, nil, 0, &theObjSpec);
          buffer = 'pURL';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theSecondObjSpec,'prop',&theSeldDesc,true,&theObjSpec);
          err = AEPutAttributeDesc(&theEvent,'csig',&theOptionalAttributeDesc);
          err = AEPutParamDesc(&theEvent,keyDirectObject, &theObjSpec);
          }
          if( noErr == err )
          {
          err = AESend( &theEvent, &reply, kAEWaitReply + kAENeverInteract, kAENormalPriority, 120, theIdleProc, NULL );
          if( noErr == err )
          {
          gotReply = true;
          }
          else
          {
          gotReply = false;
          }
          err = AEDisposeDesc(&theObjSpec);
          err = AEDisposeDesc(&theOptionalAttributeDesc);
          err = AEDisposeDesc(&theSeldDesc);
          err = AEDisposeDesc(&theSecondObjSpec);
          err = AEDisposeDesc(&theThirdObjSpec);
          err = AEDisposeDesc(&theFormDesc);
          err = AEDisposeDesc(&theNullDesc);
          }
          }
          err = AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, NULL, &errNumber, sizeof(errNumber), &actualSize);
          if(true == gotReply )
          {
          err = AEGetParamDesc( &reply, keyDirectObject, typeAEList, &replyDesc );

          keyword = typeAEList;
          err = AEGetNthDesc( &replyDesc, 1, typeUnicodeText, &keyword, &replySingle);

          if( noErr == err)
          {
          OSStatus status;
          Size theSize;
          UnicodeMapping iUnicodeMapping;
          UnicodeToTextInfo theInfo;
          UniChar theName[512];
          unsigned char crapola[512]; // a.k.a. a pstring

          iUnicodeMapping.unicodeEncoding = kTextEncodingUnicodeDefault;
          iUnicodeMapping.otherEncoding = kTextEncodingMacRoman;
          iUnicodeMapping.mappingVersion = kUnicodeUseLatestMapping;
          status = CreateUnicodeToTextInfo(&iUnicodeMapping,&theInfo);
          theSize = AEGetDescDataSize(&replySingle);

          err = AEGetDescData(&replySingle,&theName,512);
          if( noErr == err)
          {
          err = ConvertFromUnicodeToPString(theInfo,theSize,theName,crapola);
          if( noErr == err )
          {
          result = malloc( theSize * sizeof( char ));
          if( NULL != result )
          {
          p2cstrcpy(result,crapola);
          printf( "URL returned is %sn", result);
          }
          }
          }
          status = DisposeUnicodeToTextInfo(&theInfo);
          }
          }
          err = AEDisposeDesc( &targetAddress );
          err = AEDisposeDesc( &replySingle );
          DisposeAEIdleUPP( theIdleProc );
          }
          if( NULL != retval )
          *retval = result;
          return(err);
          }


          I'm sure it won't compile, since a number of Carbon API's have been updated and renamed since macOS 10.8, but you get the idea.



          Hopefully this long essay helps you out!






          share|improve this answer
























          • Nice! Really well explained answer! I will dig into it. Thanks

            – RuLoViC
            Nov 28 '18 at 9:48











          • The reason I responded so quickly was because I've done this same kind of work on two separate projects (but this was more than 10 years ago) and it can be incredibly time consuming and frustrating, so hopefully my efforts will help set you on the right path to success. I'll be thrilled (and upvote) if somebody does come and post a better answer than me, in case there actually is a more optimal solution for you.

            – Michael Dautermann
            Nov 28 '18 at 9:51











          • Dauteman: in ay case, your solution needs to have accessibility or automation enabled for your app, right? otherwise it won't work. Am I right?

            – RuLoViC
            Nov 29 '18 at 11:19






          • 1





            No, apps will respond to AppleScript or Apple events regardless of accessibility settings. If the browser is sandboxed, that might be a different story, but I haven’t tested that scenario.

            – Michael Dautermann
            Nov 29 '18 at 11:21
















          1














          This isn't an easy answer but the good news is "yes, it's possible to do this without having to use AppleScript" and the bad news is "you'll have to use AppleScript to begin with".



          Let me elaborate a bit: browser apps typically have an Applescript dictionary (which you can see by using the "Script Editor" application found in your /Applications/Utilities folder. Here's what the dictionary looks like for Google Chrome:Script Editor Dictionary for Google Chrome
          You'll see I've found the "tab" class and in there you'll see the URL property.



          So what you need to do is work up an AppleScript first to fetch the windows for the browser you're targeting. Then, when that's working, you need to convert the AppleScript to the underlying, raw AppleEvents (which is what AppleScripts compile to). Both AppleScripts and AppleEvents can be done in code.



          The answer you're really looking for (e.g. "can I use some top secret API or send a URL from my code into some open port on my local machine to query the browser?") doesn't exist, as far as I know. AppleScript and AppleEvents are the longtime ways Apple provides to automate most apps and you'll need to leverage that.



          If you decide to go ahead with using AppleScript and possibly converting them to AppleEvents, here's what I would do.



          1) Find publicly available AppleScripts to do the work you want.



          2) Convert the AppleScript to AppleEvents



          3) Code up the AppleEvents.



          For 1, here's a script that goes through every window in Safari, which I got from this tutorial:



          tell application "Safari"

          --Variables
          set windowCount to number of windows
          set docText to ""

          --Repeat for Every Window
          repeat with x from 1 to windowCount
          set tabCount to number of tabs in window x

          --Repeat for Every Tab in Current Window
          repeat with y from 1 to tabCount
          --Get Tab Name & URL
          set tabName to name of tab y of window x
          set tabURL to URL of tab y of window x
          end repeat

          end repeat
          end tell


          For step 2, I think you can use the Accessory View Pane in Script Editor to see the raw events and results produced.



          For step 3, this ancient code that I wrote in C will get the URL for a browser window given a window ID.



          OSStatus CreateTheAppleEventForGetURL( OSType appSignature, long windowid, char **retval) 
          {
          OSErr err = noErr;
          AEAddressDesc targetAddress;
          AEDescList replyDesc = { typeNull, nil };
          AEKeyword keyword;
          DescType desiredClass;
          AEDesc replySingle, theOptionalAttributeDesc, theSeldDesc,theObjSpec,theThirdObjSpec,theSecondObjSpec,theFormDesc,theNullDesc;
          AppleEvent theEvent, reply;
          AEIdleUPP theIdleProc;
          Boolean gotReply = false;
          long errNumber=0;
          long buffer;
          Size actualSize;
          char *result = NULL;

          theIdleProc = NewAEIdleUPP((AEIdleProcPtr)&TheIdleFunction );
          if( NULL != theIdleProc )
          {
          err = AECreateDesc( typeApplSignature, &appSignature, sizeof( appSignature ), &targetAddress );

          if( noErr == err )
          {
          err = AECreateAppleEvent( 'core', 'getd', &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent );
          buffer = 0x10000;
          err = AECreateDesc('magn', &buffer, 4, &theOptionalAttributeDesc);
          if( noErr == err )
          {
          err = AECreateDesc(typeNull, nil, 0, &theNullDesc);
          desiredClass = 'cwin';
          buffer = 'ID ';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          buffer = windowid;
          err = AECreateDesc(typeLongInteger,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theNullDesc,'ID ',&theSeldDesc,true,&theThirdObjSpec);
          buffer = 'docu';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          desiredClass = 'prop';
          err = CreateObjSpecifier(desiredClass,&theThirdObjSpec,'prop',&theSeldDesc,true,&theSecondObjSpec);
          buffer = 'prop';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          err = AECreateDesc(typeNull, nil, 0, &theObjSpec);
          buffer = 'pURL';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theSecondObjSpec,'prop',&theSeldDesc,true,&theObjSpec);
          err = AEPutAttributeDesc(&theEvent,'csig',&theOptionalAttributeDesc);
          err = AEPutParamDesc(&theEvent,keyDirectObject, &theObjSpec);
          }
          if( noErr == err )
          {
          err = AESend( &theEvent, &reply, kAEWaitReply + kAENeverInteract, kAENormalPriority, 120, theIdleProc, NULL );
          if( noErr == err )
          {
          gotReply = true;
          }
          else
          {
          gotReply = false;
          }
          err = AEDisposeDesc(&theObjSpec);
          err = AEDisposeDesc(&theOptionalAttributeDesc);
          err = AEDisposeDesc(&theSeldDesc);
          err = AEDisposeDesc(&theSecondObjSpec);
          err = AEDisposeDesc(&theThirdObjSpec);
          err = AEDisposeDesc(&theFormDesc);
          err = AEDisposeDesc(&theNullDesc);
          }
          }
          err = AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, NULL, &errNumber, sizeof(errNumber), &actualSize);
          if(true == gotReply )
          {
          err = AEGetParamDesc( &reply, keyDirectObject, typeAEList, &replyDesc );

          keyword = typeAEList;
          err = AEGetNthDesc( &replyDesc, 1, typeUnicodeText, &keyword, &replySingle);

          if( noErr == err)
          {
          OSStatus status;
          Size theSize;
          UnicodeMapping iUnicodeMapping;
          UnicodeToTextInfo theInfo;
          UniChar theName[512];
          unsigned char crapola[512]; // a.k.a. a pstring

          iUnicodeMapping.unicodeEncoding = kTextEncodingUnicodeDefault;
          iUnicodeMapping.otherEncoding = kTextEncodingMacRoman;
          iUnicodeMapping.mappingVersion = kUnicodeUseLatestMapping;
          status = CreateUnicodeToTextInfo(&iUnicodeMapping,&theInfo);
          theSize = AEGetDescDataSize(&replySingle);

          err = AEGetDescData(&replySingle,&theName,512);
          if( noErr == err)
          {
          err = ConvertFromUnicodeToPString(theInfo,theSize,theName,crapola);
          if( noErr == err )
          {
          result = malloc( theSize * sizeof( char ));
          if( NULL != result )
          {
          p2cstrcpy(result,crapola);
          printf( "URL returned is %sn", result);
          }
          }
          }
          status = DisposeUnicodeToTextInfo(&theInfo);
          }
          }
          err = AEDisposeDesc( &targetAddress );
          err = AEDisposeDesc( &replySingle );
          DisposeAEIdleUPP( theIdleProc );
          }
          if( NULL != retval )
          *retval = result;
          return(err);
          }


          I'm sure it won't compile, since a number of Carbon API's have been updated and renamed since macOS 10.8, but you get the idea.



          Hopefully this long essay helps you out!






          share|improve this answer
























          • Nice! Really well explained answer! I will dig into it. Thanks

            – RuLoViC
            Nov 28 '18 at 9:48











          • The reason I responded so quickly was because I've done this same kind of work on two separate projects (but this was more than 10 years ago) and it can be incredibly time consuming and frustrating, so hopefully my efforts will help set you on the right path to success. I'll be thrilled (and upvote) if somebody does come and post a better answer than me, in case there actually is a more optimal solution for you.

            – Michael Dautermann
            Nov 28 '18 at 9:51











          • Dauteman: in ay case, your solution needs to have accessibility or automation enabled for your app, right? otherwise it won't work. Am I right?

            – RuLoViC
            Nov 29 '18 at 11:19






          • 1





            No, apps will respond to AppleScript or Apple events regardless of accessibility settings. If the browser is sandboxed, that might be a different story, but I haven’t tested that scenario.

            – Michael Dautermann
            Nov 29 '18 at 11:21














          1












          1








          1







          This isn't an easy answer but the good news is "yes, it's possible to do this without having to use AppleScript" and the bad news is "you'll have to use AppleScript to begin with".



          Let me elaborate a bit: browser apps typically have an Applescript dictionary (which you can see by using the "Script Editor" application found in your /Applications/Utilities folder. Here's what the dictionary looks like for Google Chrome:Script Editor Dictionary for Google Chrome
          You'll see I've found the "tab" class and in there you'll see the URL property.



          So what you need to do is work up an AppleScript first to fetch the windows for the browser you're targeting. Then, when that's working, you need to convert the AppleScript to the underlying, raw AppleEvents (which is what AppleScripts compile to). Both AppleScripts and AppleEvents can be done in code.



          The answer you're really looking for (e.g. "can I use some top secret API or send a URL from my code into some open port on my local machine to query the browser?") doesn't exist, as far as I know. AppleScript and AppleEvents are the longtime ways Apple provides to automate most apps and you'll need to leverage that.



          If you decide to go ahead with using AppleScript and possibly converting them to AppleEvents, here's what I would do.



          1) Find publicly available AppleScripts to do the work you want.



          2) Convert the AppleScript to AppleEvents



          3) Code up the AppleEvents.



          For 1, here's a script that goes through every window in Safari, which I got from this tutorial:



          tell application "Safari"

          --Variables
          set windowCount to number of windows
          set docText to ""

          --Repeat for Every Window
          repeat with x from 1 to windowCount
          set tabCount to number of tabs in window x

          --Repeat for Every Tab in Current Window
          repeat with y from 1 to tabCount
          --Get Tab Name & URL
          set tabName to name of tab y of window x
          set tabURL to URL of tab y of window x
          end repeat

          end repeat
          end tell


          For step 2, I think you can use the Accessory View Pane in Script Editor to see the raw events and results produced.



          For step 3, this ancient code that I wrote in C will get the URL for a browser window given a window ID.



          OSStatus CreateTheAppleEventForGetURL( OSType appSignature, long windowid, char **retval) 
          {
          OSErr err = noErr;
          AEAddressDesc targetAddress;
          AEDescList replyDesc = { typeNull, nil };
          AEKeyword keyword;
          DescType desiredClass;
          AEDesc replySingle, theOptionalAttributeDesc, theSeldDesc,theObjSpec,theThirdObjSpec,theSecondObjSpec,theFormDesc,theNullDesc;
          AppleEvent theEvent, reply;
          AEIdleUPP theIdleProc;
          Boolean gotReply = false;
          long errNumber=0;
          long buffer;
          Size actualSize;
          char *result = NULL;

          theIdleProc = NewAEIdleUPP((AEIdleProcPtr)&TheIdleFunction );
          if( NULL != theIdleProc )
          {
          err = AECreateDesc( typeApplSignature, &appSignature, sizeof( appSignature ), &targetAddress );

          if( noErr == err )
          {
          err = AECreateAppleEvent( 'core', 'getd', &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent );
          buffer = 0x10000;
          err = AECreateDesc('magn', &buffer, 4, &theOptionalAttributeDesc);
          if( noErr == err )
          {
          err = AECreateDesc(typeNull, nil, 0, &theNullDesc);
          desiredClass = 'cwin';
          buffer = 'ID ';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          buffer = windowid;
          err = AECreateDesc(typeLongInteger,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theNullDesc,'ID ',&theSeldDesc,true,&theThirdObjSpec);
          buffer = 'docu';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          desiredClass = 'prop';
          err = CreateObjSpecifier(desiredClass,&theThirdObjSpec,'prop',&theSeldDesc,true,&theSecondObjSpec);
          buffer = 'prop';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          err = AECreateDesc(typeNull, nil, 0, &theObjSpec);
          buffer = 'pURL';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theSecondObjSpec,'prop',&theSeldDesc,true,&theObjSpec);
          err = AEPutAttributeDesc(&theEvent,'csig',&theOptionalAttributeDesc);
          err = AEPutParamDesc(&theEvent,keyDirectObject, &theObjSpec);
          }
          if( noErr == err )
          {
          err = AESend( &theEvent, &reply, kAEWaitReply + kAENeverInteract, kAENormalPriority, 120, theIdleProc, NULL );
          if( noErr == err )
          {
          gotReply = true;
          }
          else
          {
          gotReply = false;
          }
          err = AEDisposeDesc(&theObjSpec);
          err = AEDisposeDesc(&theOptionalAttributeDesc);
          err = AEDisposeDesc(&theSeldDesc);
          err = AEDisposeDesc(&theSecondObjSpec);
          err = AEDisposeDesc(&theThirdObjSpec);
          err = AEDisposeDesc(&theFormDesc);
          err = AEDisposeDesc(&theNullDesc);
          }
          }
          err = AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, NULL, &errNumber, sizeof(errNumber), &actualSize);
          if(true == gotReply )
          {
          err = AEGetParamDesc( &reply, keyDirectObject, typeAEList, &replyDesc );

          keyword = typeAEList;
          err = AEGetNthDesc( &replyDesc, 1, typeUnicodeText, &keyword, &replySingle);

          if( noErr == err)
          {
          OSStatus status;
          Size theSize;
          UnicodeMapping iUnicodeMapping;
          UnicodeToTextInfo theInfo;
          UniChar theName[512];
          unsigned char crapola[512]; // a.k.a. a pstring

          iUnicodeMapping.unicodeEncoding = kTextEncodingUnicodeDefault;
          iUnicodeMapping.otherEncoding = kTextEncodingMacRoman;
          iUnicodeMapping.mappingVersion = kUnicodeUseLatestMapping;
          status = CreateUnicodeToTextInfo(&iUnicodeMapping,&theInfo);
          theSize = AEGetDescDataSize(&replySingle);

          err = AEGetDescData(&replySingle,&theName,512);
          if( noErr == err)
          {
          err = ConvertFromUnicodeToPString(theInfo,theSize,theName,crapola);
          if( noErr == err )
          {
          result = malloc( theSize * sizeof( char ));
          if( NULL != result )
          {
          p2cstrcpy(result,crapola);
          printf( "URL returned is %sn", result);
          }
          }
          }
          status = DisposeUnicodeToTextInfo(&theInfo);
          }
          }
          err = AEDisposeDesc( &targetAddress );
          err = AEDisposeDesc( &replySingle );
          DisposeAEIdleUPP( theIdleProc );
          }
          if( NULL != retval )
          *retval = result;
          return(err);
          }


          I'm sure it won't compile, since a number of Carbon API's have been updated and renamed since macOS 10.8, but you get the idea.



          Hopefully this long essay helps you out!






          share|improve this answer













          This isn't an easy answer but the good news is "yes, it's possible to do this without having to use AppleScript" and the bad news is "you'll have to use AppleScript to begin with".



          Let me elaborate a bit: browser apps typically have an Applescript dictionary (which you can see by using the "Script Editor" application found in your /Applications/Utilities folder. Here's what the dictionary looks like for Google Chrome:Script Editor Dictionary for Google Chrome
          You'll see I've found the "tab" class and in there you'll see the URL property.



          So what you need to do is work up an AppleScript first to fetch the windows for the browser you're targeting. Then, when that's working, you need to convert the AppleScript to the underlying, raw AppleEvents (which is what AppleScripts compile to). Both AppleScripts and AppleEvents can be done in code.



          The answer you're really looking for (e.g. "can I use some top secret API or send a URL from my code into some open port on my local machine to query the browser?") doesn't exist, as far as I know. AppleScript and AppleEvents are the longtime ways Apple provides to automate most apps and you'll need to leverage that.



          If you decide to go ahead with using AppleScript and possibly converting them to AppleEvents, here's what I would do.



          1) Find publicly available AppleScripts to do the work you want.



          2) Convert the AppleScript to AppleEvents



          3) Code up the AppleEvents.



          For 1, here's a script that goes through every window in Safari, which I got from this tutorial:



          tell application "Safari"

          --Variables
          set windowCount to number of windows
          set docText to ""

          --Repeat for Every Window
          repeat with x from 1 to windowCount
          set tabCount to number of tabs in window x

          --Repeat for Every Tab in Current Window
          repeat with y from 1 to tabCount
          --Get Tab Name & URL
          set tabName to name of tab y of window x
          set tabURL to URL of tab y of window x
          end repeat

          end repeat
          end tell


          For step 2, I think you can use the Accessory View Pane in Script Editor to see the raw events and results produced.



          For step 3, this ancient code that I wrote in C will get the URL for a browser window given a window ID.



          OSStatus CreateTheAppleEventForGetURL( OSType appSignature, long windowid, char **retval) 
          {
          OSErr err = noErr;
          AEAddressDesc targetAddress;
          AEDescList replyDesc = { typeNull, nil };
          AEKeyword keyword;
          DescType desiredClass;
          AEDesc replySingle, theOptionalAttributeDesc, theSeldDesc,theObjSpec,theThirdObjSpec,theSecondObjSpec,theFormDesc,theNullDesc;
          AppleEvent theEvent, reply;
          AEIdleUPP theIdleProc;
          Boolean gotReply = false;
          long errNumber=0;
          long buffer;
          Size actualSize;
          char *result = NULL;

          theIdleProc = NewAEIdleUPP((AEIdleProcPtr)&TheIdleFunction );
          if( NULL != theIdleProc )
          {
          err = AECreateDesc( typeApplSignature, &appSignature, sizeof( appSignature ), &targetAddress );

          if( noErr == err )
          {
          err = AECreateAppleEvent( 'core', 'getd', &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent );
          buffer = 0x10000;
          err = AECreateDesc('magn', &buffer, 4, &theOptionalAttributeDesc);
          if( noErr == err )
          {
          err = AECreateDesc(typeNull, nil, 0, &theNullDesc);
          desiredClass = 'cwin';
          buffer = 'ID ';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          buffer = windowid;
          err = AECreateDesc(typeLongInteger,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theNullDesc,'ID ',&theSeldDesc,true,&theThirdObjSpec);
          buffer = 'docu';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          desiredClass = 'prop';
          err = CreateObjSpecifier(desiredClass,&theThirdObjSpec,'prop',&theSeldDesc,true,&theSecondObjSpec);
          buffer = 'prop';
          err = AECreateDesc('enum',&buffer,4,&theFormDesc);
          err = AECreateDesc(typeNull, nil, 0, &theObjSpec);
          buffer = 'pURL';
          err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
          err = CreateObjSpecifier(desiredClass,&theSecondObjSpec,'prop',&theSeldDesc,true,&theObjSpec);
          err = AEPutAttributeDesc(&theEvent,'csig',&theOptionalAttributeDesc);
          err = AEPutParamDesc(&theEvent,keyDirectObject, &theObjSpec);
          }
          if( noErr == err )
          {
          err = AESend( &theEvent, &reply, kAEWaitReply + kAENeverInteract, kAENormalPriority, 120, theIdleProc, NULL );
          if( noErr == err )
          {
          gotReply = true;
          }
          else
          {
          gotReply = false;
          }
          err = AEDisposeDesc(&theObjSpec);
          err = AEDisposeDesc(&theOptionalAttributeDesc);
          err = AEDisposeDesc(&theSeldDesc);
          err = AEDisposeDesc(&theSecondObjSpec);
          err = AEDisposeDesc(&theThirdObjSpec);
          err = AEDisposeDesc(&theFormDesc);
          err = AEDisposeDesc(&theNullDesc);
          }
          }
          err = AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, NULL, &errNumber, sizeof(errNumber), &actualSize);
          if(true == gotReply )
          {
          err = AEGetParamDesc( &reply, keyDirectObject, typeAEList, &replyDesc );

          keyword = typeAEList;
          err = AEGetNthDesc( &replyDesc, 1, typeUnicodeText, &keyword, &replySingle);

          if( noErr == err)
          {
          OSStatus status;
          Size theSize;
          UnicodeMapping iUnicodeMapping;
          UnicodeToTextInfo theInfo;
          UniChar theName[512];
          unsigned char crapola[512]; // a.k.a. a pstring

          iUnicodeMapping.unicodeEncoding = kTextEncodingUnicodeDefault;
          iUnicodeMapping.otherEncoding = kTextEncodingMacRoman;
          iUnicodeMapping.mappingVersion = kUnicodeUseLatestMapping;
          status = CreateUnicodeToTextInfo(&iUnicodeMapping,&theInfo);
          theSize = AEGetDescDataSize(&replySingle);

          err = AEGetDescData(&replySingle,&theName,512);
          if( noErr == err)
          {
          err = ConvertFromUnicodeToPString(theInfo,theSize,theName,crapola);
          if( noErr == err )
          {
          result = malloc( theSize * sizeof( char ));
          if( NULL != result )
          {
          p2cstrcpy(result,crapola);
          printf( "URL returned is %sn", result);
          }
          }
          }
          status = DisposeUnicodeToTextInfo(&theInfo);
          }
          }
          err = AEDisposeDesc( &targetAddress );
          err = AEDisposeDesc( &replySingle );
          DisposeAEIdleUPP( theIdleProc );
          }
          if( NULL != retval )
          *retval = result;
          return(err);
          }


          I'm sure it won't compile, since a number of Carbon API's have been updated and renamed since macOS 10.8, but you get the idea.



          Hopefully this long essay helps you out!







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 28 '18 at 9:40









          Michael DautermannMichael Dautermann

          80.8k15135171




          80.8k15135171













          • Nice! Really well explained answer! I will dig into it. Thanks

            – RuLoViC
            Nov 28 '18 at 9:48











          • The reason I responded so quickly was because I've done this same kind of work on two separate projects (but this was more than 10 years ago) and it can be incredibly time consuming and frustrating, so hopefully my efforts will help set you on the right path to success. I'll be thrilled (and upvote) if somebody does come and post a better answer than me, in case there actually is a more optimal solution for you.

            – Michael Dautermann
            Nov 28 '18 at 9:51











          • Dauteman: in ay case, your solution needs to have accessibility or automation enabled for your app, right? otherwise it won't work. Am I right?

            – RuLoViC
            Nov 29 '18 at 11:19






          • 1





            No, apps will respond to AppleScript or Apple events regardless of accessibility settings. If the browser is sandboxed, that might be a different story, but I haven’t tested that scenario.

            – Michael Dautermann
            Nov 29 '18 at 11:21



















          • Nice! Really well explained answer! I will dig into it. Thanks

            – RuLoViC
            Nov 28 '18 at 9:48











          • The reason I responded so quickly was because I've done this same kind of work on two separate projects (but this was more than 10 years ago) and it can be incredibly time consuming and frustrating, so hopefully my efforts will help set you on the right path to success. I'll be thrilled (and upvote) if somebody does come and post a better answer than me, in case there actually is a more optimal solution for you.

            – Michael Dautermann
            Nov 28 '18 at 9:51











          • Dauteman: in ay case, your solution needs to have accessibility or automation enabled for your app, right? otherwise it won't work. Am I right?

            – RuLoViC
            Nov 29 '18 at 11:19






          • 1





            No, apps will respond to AppleScript or Apple events regardless of accessibility settings. If the browser is sandboxed, that might be a different story, but I haven’t tested that scenario.

            – Michael Dautermann
            Nov 29 '18 at 11:21

















          Nice! Really well explained answer! I will dig into it. Thanks

          – RuLoViC
          Nov 28 '18 at 9:48





          Nice! Really well explained answer! I will dig into it. Thanks

          – RuLoViC
          Nov 28 '18 at 9:48













          The reason I responded so quickly was because I've done this same kind of work on two separate projects (but this was more than 10 years ago) and it can be incredibly time consuming and frustrating, so hopefully my efforts will help set you on the right path to success. I'll be thrilled (and upvote) if somebody does come and post a better answer than me, in case there actually is a more optimal solution for you.

          – Michael Dautermann
          Nov 28 '18 at 9:51





          The reason I responded so quickly was because I've done this same kind of work on two separate projects (but this was more than 10 years ago) and it can be incredibly time consuming and frustrating, so hopefully my efforts will help set you on the right path to success. I'll be thrilled (and upvote) if somebody does come and post a better answer than me, in case there actually is a more optimal solution for you.

          – Michael Dautermann
          Nov 28 '18 at 9:51













          Dauteman: in ay case, your solution needs to have accessibility or automation enabled for your app, right? otherwise it won't work. Am I right?

          – RuLoViC
          Nov 29 '18 at 11:19





          Dauteman: in ay case, your solution needs to have accessibility or automation enabled for your app, right? otherwise it won't work. Am I right?

          – RuLoViC
          Nov 29 '18 at 11:19




          1




          1





          No, apps will respond to AppleScript or Apple events regardless of accessibility settings. If the browser is sandboxed, that might be a different story, but I haven’t tested that scenario.

          – Michael Dautermann
          Nov 29 '18 at 11:21





          No, apps will respond to AppleScript or Apple events regardless of accessibility settings. If the browser is sandboxed, that might be a different story, but I haven’t tested that scenario.

          – Michael Dautermann
          Nov 29 '18 at 11:21





          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)