How to translate this slider value change from AppleScript to JavaScript - applescript

This bit of AppleScript works. If I have the System Preferences Sound panel open, and run it in the Script Editor app, it changes the volume to be at 50%.
tell application "System Events"
tell process "System Preferences"
set v to value of slider 0 of window 0
log v
set value of slider 0 of window 0 to 0.5
end tell
end tell
This, which tries to be the same thing, fails. Anyone know how to fix it?
var se = Application("System Events");
var spp = se.processes["System Preferences"];
spp.windows[0].sliders[0].value = 0.5
var curr = spp.windows[0].sliders[0].value();
console.log("Current value: " + curr + " - " + typeof(curr));
It ends up setting it to 0. It seems I can only set the volume to 0 or 1. In reality I'm trying to script another application, but this boils down the problem.

As I noted in my comment, I'm 90% sure this is a bug.
Here's a workaround:
app = Application.currentApplication();
app.includeStandardAdditions = true;
try {
app.doShellScript('osascript -e \'tell application "System Events" to set value of slider 0 of window 0 of process "System Preferences" to 0.2\'');
} catch (error ) {
-1;
}

Related

Mac Shortcuts App boots scripts slowly with delay

I create shortcuts in Shortcuts.app (macOS 12) to resizing/moving the current window by JavaScript.
The question is: there is a delay time (about 0.2~0.3 sec) after I press the keyboard shortcut to launch the scripts. It's quite annoying. How can I improve that?
I used Hammerspoon with Lua scripts to do the same jobs, and it responds very quickly/instantly without any delay.
Shortcuts implementation
Move current window to top left corner (using hotkey ⌘⇧⌥← & you can download this shortcut here):
function run(input, parameters) {
var frontAppName = Application("System Events").processes.whose({frontmost: {'=': true}})[0].name();
var frontApp = Application(frontAppName);
var topWindow = frontApp.windows[0];
var windowBounds = topWindow.bounds();
windowBounds.x = 0;
windowBounds.y = 0;
topWindow.bounds = windowBounds;
}
Move current window to top right corner (using hotkey ⌘⇧⌥→ & you can download this shortcut here):
function run(input, parameters) {
var frontAppName = Application("System Events").processes.whose({frontmost: {'=': true}})[0].name();
var frontApp = Application(frontAppName);
var topWindow = frontApp.windows[0];
var windowBounds = topWindow.bounds();
var desktopBounds = Application("Finder").desktop.window().bounds();
windowBounds.x = desktopBounds.width - windowBounds.width;
windowBounds.y = 0;
topWindow.bounds = windowBounds;
}

How to handle optional windows in Autoit?

I am automating a software installation in Windows7 using AutoIt.
During the installation, in between if a error window appears. I want to click ENTER.
If the error window not appears then I should NOT do anything. Simply its should go to the next section.
I have tried "WinActive and WinWaitActive" But its waiting for the window to appear. If window not appears its not going to the next screen.
Any idea how to handle this situation?
Do a while loop:
$w = 0
While($w = 0)
If(WinActive("ERROR WINDOW"))Then
Send("{ENTER}")
$w = 1
ElseIf(ControlGetText("YOUR WINDOW", "", "[CLASS:Static; INSTANCE:2]") <> "SOME TEXT") Then
$w = 1
;and something else
EndIf
Sleep(1000)
WEnd
AdlibRegister() is the right choice. From the help file:
"... typically to check for unforeseen errors. For example, you could use adlib in a script which causes an error window to pop up unpredictably."
Each 100 ms (may be adjusted) the function is called to check the appearing of your error dialog:
Global $sErrorWindow = 'ErrorDialogName'
Global $iDelayHowOftenDoTheFunctionCall = 100
AdlibRegister('_isErrorWindowDisplayed', $iDelayHowOftenDoTheFunctionCall)
Func _isErrorWindowDisplayed()
If WinActive($sErrorWindow) <> 0 Then
WinActivate($sErrorWindow) ; just to be sure that the ENTER command is on the correct window/dialog
; either do
Send('{ENTER}')
; or
ControlClick('title', 'text', 'controlID')
EndIf
EndFunc
; do your software installation processing here
; ...
; ...
; don't forget to unregister the function at the end
AdlibUnRegister('_isErrorWindowDisplayed')

Photoshop Javascript: How to get / set current tool?

How does one get / set the current tool using Javascript in Photoshop?
#target photoshop
if (app.currentTool == BRUSH_TOOL) {
app.currentTool = ERASE_TOOL;
} else {
app.currentTool = BRUSH_TOOL;
}
I found a solution, but I wish it was simpler. Basically I'm using this to select the brush tool and toggle the eraser tool, using only one button. That way I only have to use one button on my Wacom Tablet.
#target photoshop
if (getTool() == 'paintbrushTool') {
setTool('eraserTool');
} else {
setTool('paintbrushTool');
}
// https://forums.adobe.com/thread/579195
function getTool(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("capp"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var cTool = typeIDToStringID(executeActionGet(ref).getEnumerationType(stringIDToTypeID('tool')));
return cTool;
}
// https://www.ps-scripts.com/viewtopic.php?f=68&t=11342&p=152772
function setTool(tool) {
var desc9 = new ActionDescriptor();
var ref7 = new ActionReference();
ref7.putClass( app.stringIDToTypeID(tool) );
desc9.putReference( app.charIDToTypeID('null'), ref7 );
executeAction( app.charIDToTypeID('slct'), desc9, DialogModes.NO );
}
// Tool names (use quoted strings, e.g. 'moveTool')
// moveTool
// marqueeRectTool
// marqueeEllipTool
// marqueeSingleRowTool
// marqueeSingleColumnTool
// lassoTool
// polySelTool
// magneticLassoTool
// quickSelectTool
// magicWandTool
// cropTool
// sliceTool
// sliceSelectTool
// spotHealingBrushTool
// magicStampTool
// patchSelection
// redEyeTool
// paintbrushTool
// pencilTool
// colorReplacementBrushTool
// cloneStampTool
// patternStampTool
// historyBrushTool
// artBrushTool
// eraserTool
// backgroundEraserTool
// magicEraserTool
// gradientTool
// bucketTool
// blurTool
// sharpenTool
// smudgeTool
// dodgeTool
// burnInTool
// saturationTool
// penTool
// freeformPenTool
// addKnotTool
// deleteKnotTool
// convertKnotTool
// typeCreateOrEditTool
// typeVerticalCreateOrEditTool
// typeCreateMaskTool
// typeVerticalCreateMaskTool
// pathComponentSelectTool
// directSelectTool
// rectangleTool
// roundedRectangleTool
// ellipseTool
// polygonTool
// lineTool
// customShapeTool
// textAnnotTool
// soundAnnotTool
// eyedropperTool
// colorSamplerTool
// rulerTool
// handTool
// zoomTool
It's simpler in AppleScript. This is my little library script that I use with my Wacom:
-- put into ~/Library/Script\ Libraries
-- use as set currentTool to script "Photoshop_ScriptLibrary"'s toggleCurrentTool("lassoTool", "eraserTool")
on writeVar(theName, theVar)
do shell script "echo " & theVar & " > /tmp/" & theName & ".txt"
end writeVar
on readVar(theName)
try
return do shell script "cat /tmp/" & theName & ".txt"
end try
return ""
end readVar
on getGroupPath()
set thelayer to ""
tell application "Adobe Photoshop CC 2019" to tell the current document
set thelayer to current layer
end tell
return thelayer
end getGroupPath
on getCurrentTool()
tell application "Adobe Photoshop CC 2019" to return current tool
end getCurrentTool
on deselect()
tell application "Adobe Photoshop CC 2019" to tell the current document to deselect
setFeathered(false)
end deselect
on toggleCurrentTool(tool1, tool2)
setFeathered(false)
set currentTool to tool1
tell application "Adobe Photoshop CC 2019"
if current tool is equal to currentTool then set currentTool to tool2
set current tool to currentTool
end tell
return currentTool
end toggleCurrentTool
on getAllLayers(layerName)
set allLayerNames to {}
tell application "Adobe Photoshop CC 2019"
set allLayers to the layers of current document
repeat with thelayer in allLayers
set theName to the name of thelayer
if theName starts with the first word of layerName then set end of allLayerNames to theName
end repeat
end tell
return allLayerNames
end getAllLayers
on getPrevLayer(targetLayerName, currentLayer)
set currentLayerId to id of currentLayer
tell application "Adobe Photoshop CC 2019"
return the first art layer of the current document whose name is targetLayerName and id is not currentLayerId
return the first art layer of the current document whose name is targetLayerName
end tell
end getPrevLayer
on getPrevious(layerName)
set suffix to the last word of layerName
set suffixlength to get (length of suffix) + 2
log "getPrevious(" & layerName & "), suffix: " & suffix
-- remove the last word from the layer name. Unless we're dealing with numbered copies
set targetLayerName to (text 1 thru (-1 * suffixlength)) of layerName
-- first: Check if layer name ends in number. If number > 2, we want the layer with the next-smaller number
-- WIP copy 16 -> WIP copy 15
-- WIP copy 1 -> WIP copy
-- second: If the layer does not end in a number,
try
set thenumber to (suffix as number)
if thenumber is greater than 2 then set targetLayerName to targetLayerName & " " & thenumber - 1
on error -- if layer doesn't end in a number: remove "copy"
if layerName ends with "copy" then set targetLayerName to text 1 thru -6 of layerName
end try
return targetLayerName
end getPrevious
on getPreviousLayer(currentLayer)
return getPrevLayer((getPrevious(name of currentLayer)), currentLayer)
end getPreviousLayer
on getFeathered()
return "true" is equal to readVar("feathered")
end getFeathered
on setFeathered(b)
writeVar("feathered", b)
end setFeathered
on isOnLayerMask()
try
set windowName to ""
tell application "System Events" to tell process "Adobe Photoshop CC 2019"
tell (1st window whose value of attribute "AXMain" is true)
set windowName to value of attribute "AXTitle"
end tell
end tell
end try
return windowName contains "Layer Mask"
end isOnLayerMask
on isSelected()
try
tell application "Adobe Photoshop CC 2019" to tell current document
set props to properties of selection
if bounds of props is not equal to missing value then return true
end tell
end try
return false
end isSelected
on tryFeather()
if getFeathered() or not isSelected() then return
try
tell application "Adobe Photoshop CC 2019" to tell current document
feather selection by 5
end tell
setFeathered(true)
on error
setFeathered(false)
end try
end tryFeather
on tryBlur(_radius)
if isSelected() then
try
tell application "Adobe Photoshop CC 2019" to tell current document
filter current layer using gaussian blur with options {radius:_radius}
end tell
end try
end if
end tryBlur
you can try to use photoshop-python-api
from photoshop import Session
with Session() as ps:
print(ps.app.currentTool)
https://github.com/loonghao/photoshop-python-api
Old question, but still relevant so I wanted to simplify it further. The OP was on the right track with the code, it needed only the necessary string values for various tools, which were provided by #skibulk above.
According to the Photoshop Javascript Reference PDF, currentTool is a read-write string property of the Application object. This means we can get the value of the current tool, but also set the value of the current tool.
#target photoshop
if (app.currentTool == "paintbrushTool") {
app.currentTool = "eraserTool";
} else {
app.currentTool = "paintbrushTool";
}
// Tool names (use quoted strings, e.g. 'moveTool')
// moveTool
// marqueeRectTool
// marqueeEllipTool
// marqueeSingleRowTool
// marqueeSingleColumnTool
// lassoTool
// polySelTool
// magneticLassoTool
// quickSelectTool
// magicWandTool
// cropTool
// sliceTool
// sliceSelectTool
// spotHealingBrushTool
// magicStampTool
// patchSelection
// redEyeTool
// paintbrushTool
// pencilTool
// colorReplacementBrushTool
// cloneStampTool
// patternStampTool
// historyBrushTool
// artBrushTool
// eraserTool
// backgroundEraserTool
// magicEraserTool
// gradientTool
// bucketTool
// blurTool
// sharpenTool
// smudgeTool
// dodgeTool
// burnInTool
// saturationTool
// penTool
// freeformPenTool
// addKnotTool
// deleteKnotTool
// convertKnotTool
// typeCreateOrEditTool
// typeVerticalCreateOrEditTool
// typeCreateMaskTool
// typeVerticalCreateMaskTool
// pathComponentSelectTool
// directSelectTool
// rectangleTool
// roundedRectangleTool
// ellipseTool
// polygonTool
// lineTool
// customShapeTool
// textAnnotTool
// soundAnnotTool
// eyedropperTool
// colorSamplerTool
// rulerTool
// handTool
// zoomTool

Running AppleScript from XPCOM

I've been trying to execute applescript code through XPCOM, but no matter what I do it just doesn't seem to work, the observer tells me that the process finishes without a problem, but nothing happens.
var processArgs = ['-e','\'tell application "iTunes"\'','-e','\'activate\'','-e','\'end tell\''];
var file = Cc["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
file.initWithPath( '/usr/bin/osascript');
var process = Cc["#mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
process.init( file );
var observer = {
observe: function( subject, topic ) {
SiteFusion.consoleMessage('DONE ' + topic);
}
}
process.runAsync( processArgs, processArgs.length, observer );
The output in the console is 'DONE process-finished' so it should have worked, does anyone know why this script refuses to open iTunes?
Reason is that you use escaped single quotes in arguments, so your actual resulting AppleScript looks like:
'tell application "iTunes"'
'activate'
'end tell'
Which is clearly not valid. Instead, your arguments should look like this:
const processArgs = ['-e', 'tell application "iTunes"', '-e', 'activate', '-e', 'end tell'];
or, alternatively,
const processArgs = ['-e', `
tell application "iTunes"
activate
end tell`];
or, alternatively,
const processArgs = ['-e', 'tell application "iTunes" to activate'];

Xcode console, clear screen programmatically

I'm kinda new to Xcode and even programming.
From Xcode, in my code, how do I show the console and clear the screen?
I know I could do it with the Xcode preferences, but I would like to do it programmatically.
This works for me - leave out the last activate part if you wish Xcode to stay on top of your app:
bool ClearXCodeDebuggerConsole()
{
NSString *const scriptText = #"\
tell application \"System Events\"\n\
set currentapp to the name of the current application\n\
end tell\n\
tell application \"Xcode\" to activate\n\
tell application \"System Events\"\n\
keystroke \"r\" using {command down, control down, option down}\n\
end tell\n\
tell application currentapp to activate\n\
return true";
NSAppleScript *script = [[[NSAppleScript alloc] initWithSource:scriptText] autorelease];
[scriptText release];
NSDictionary *dictError = nil;
NSAppleEventDescriptor *result = [script executeAndReturnError:&dictError];
if (!result) return false;
if ([result booleanValue] != YES) return false;
return true;
}
You can display the console window by pressing Shift + Command + R. You can clear the console window by pressing Control + Option + Command + R. Both options are available from the Run menu.

Resources