Swift example script: Get macros and uuids from clipboard
Get Macros and UUIDs from the clipboard.kmmacros (7.6 KB)
Here's an example Swift script I just finished, and a simple macro that runs it. The script is highly commented..
The Swift script does the same thing the AppleScript does, in
/*****************************************************************
GetKMMacrosAndUUIDsFromClipboard
Author: @DanThomas at the Keyboard Maestro forum
Updated: 2016/06/07 19:52 PDT
Language: Swift v2.2.1
PURPOSE:
This script expects the clipboard to contain one or more Keyboard
Maestro Macros. It will return a multi-line string, each line
containing the KM Macro name and UUID of one of these Macros.
If the information isn't on the clipboard, this script returns an
empty string.
NOTES:
1) You can place this script in a Keyboard Maestro "Execute a
Swift script" Action, or you can use it in Xcode. One easy way
to use it in Xcode is to use a Playground, but since you can't
use breakpoints in Playgrounds, I recommend making an OS/X
Console application, and using this there.
2) This script is not only functional, but hopefully will be used
as a learning experience for others who might be new to Swift.
As such, I'm including logic-flow comments that, to more
experienced Swift developers, will seem extreme. Also, since I'm
also new at Swift, cut me some slack. :)
3) I'm well aware that the standard way to write Swift code is to
place the opening script brace ( "{" ) at the end of a line.
However, this script is meant to be used as a learning tool, and
I felt that a little more line spacing would help. Also, I prefer
it this way. So there.
4) I'm also well aware that most people don't name variables with
an underscore prefix. Old habits die hard. This is to distinguish
local variables from parameters.
*******************************************************************/
import Cocoa
// I'm wrapping everything in a class, although all the fuctions
// are static functions ("class" functions) so it isn't strictly
// necessary, but I'm doing it because, well, it just seems right.
class GetKMMacrosAndUUIDsFromClipboard
{
// This method is called from the last line in the script.
// It doesn't need to be called "execute", it's just what I
// decided to name it.
//
// This is a function which returns a string.
class func execute() -> String
{
// This calls a routine (below) to get the KM clipboard
// data we're looking for, or else it returns nil.
let _clipboardResult = getKMMacroArrayFromClipboard()
// This attepts to type cast the result as an NSArray,
// which is what it will be if it was Macros copied
// from KM. If "_aray" was already nil, or if the cast
// fails, the "else" is executed.
if let _array = _clipboardResult as? NSArray
{
return getMacrosAndUUIDs(_array)
}
else
{
return ""
}
}
// Attempts to get the KM Macros from the clipboard. It
// returns nil if they aren't on the clipboard, otherwise
// it returns the deserialized NS object.
class func getKMMacroArrayFromClipboard() -> AnyObject?
{
let _pasteboard = NSPasteboard.generalPasteboard()
// Rather than querying the clipboard for what's on it,
// then extractin it if it's the corrrect format, we go
// ahead and try and grap what we want. But we wrap
// these statements in "guard" statements, so if the
// result is nil, the "else" is executed, and we exit
// this function returning nil.
guard let _clipping = _pasteboard.stringForType("com.stairways.keyboardmaestro.macrosarray") else {return nil}
guard let _data = _clipping.dataUsingEncoding(NSUTF8StringEncoding) else {return nil}
// The next statement we call is marked as being able to
// throw exceptions, so we have to wrap it up to catch
// the exceptions. Since we don't care what the exception
// is, we just return nil.
do
{
return try NSPropertyListSerialization.propertyListWithData(_data, options: NSPropertyListReadOptions.MutableContainersAndLeaves, format: nil)
}
catch
{
return nil
}
}
// This function takes the NSArray data we got from the
// clipboard, parses it and returns a string with info
// about one macro per line.
class func getMacrosAndUUIDs(macros: NSArray) -> String
{
// This is where we'll store our results. Obviously.
var _result = [String]()
// Enumerate through the items in the array. Since
// NSArray is not type-specific, we have to use a
// variable of "AnyObject" for each item of the array.
for _macroObject: AnyObject in macros
{
// From this part on, we pretty-much expect everything
// to be in a specific format. So no more type-checking.
// If something fails it will cause an exception,
// but at that point we'd prefer the exception to
// bubble up so we have some idea of exactly what
// went wrong.
//
// So we use the "as!" constrtuct to say "we know
// what's in here, so give us what we want".
//
// First, we cast the array object as an NSDictionary
let _macro = _macroObject as! NSDictionary
// Then we get the Macro's Name and UUID (UID)
let _name = _macro.valueForKey("Name") as! String
let _uuid = _macro.valueForKey("UID") as! String
// And finally, we stick the info in our result array.
_result.append(_name + "\t" + _uuid)
}
// Return the results as a multi-line string
return _result.joinWithSeparator("\n")
}
}
// Execute our code, and return (display) our results
print(GetKMMacrosAndUUIDsFromClipboard.execute())
//*******************************************************************