author:: null source:: mac上用Automator编写自动脚本_destiny_ac的博客-CSDN博客_mac自动按键脚本 clipped:: 2022-08-29 published::
最近努力学习新知识,在公司内网上阅读一些优秀文章,但是发现这些文章:是通过通过flash控件展示,并且不提供无法下载地址(类似《百度文库》)。一次忍了,两次再忍了,三次就无法忍受:都在我电脑上展示了,这么做就是恶心人了。。。。
于是花了大半天时间,使用mac上自带软件Automator,从零开始完成了自己的工具:《连续抓图导出PDF》。
实现原理:自动截屏、翻页=》merge生成PDF文档。(感兴趣的人,可以下载附件看看源码)
在写这个脚本过程中,本以为会很快,但是还是碰到了不少问题;于是就记录并分享出来。
首先:最基本用法,可以直接参考Automator帮助,本文章只写自认为容易忽略或者难点的几个地方。
变量新建就不说了;这里主要说变量再控件上使用,几种方法(有的方法只对部分控件有用):
从下拉列表直接选择“变量”
将“变量”拖进区域
当然你也可以,抛弃使用已存在的变量,直接通过下拉框选择一个“新建变量”。
“输入变量名”弹出提示,“回车”选择
最后,如果上面三种方法你尝试都不行的话,基本上可以宣告,那个是不支持变量的。
比如,LOOP的“次数”,是不支持变量的:
脚本使用
Automator脚本支持:shell脚本(bash、perl、python、ruby等)、appleScript、javascript几种,你可以选择不同的脚本来运行。
脚本参数传递
脚本和变量之间,是无法直接获取或设置的
“变量”值传递到脚本
– shell脚本
获取到的输入:只能是通过输入的一行一行的字符串
也即如果,想获取变量值的话,可以通过,“获得变量的值”控件来输出值,然后传递到脚本然后再读取。
如:下面是获取“页数”、“URL”、“临时文件夹”三个变量值到输出,然后传递给perl脚本。
– AppleScript脚本
AppleScript的输入不是一行一行的字符串,貌似是键值队(还不熟悉这块),结果没搞懂如何传递的变量——搞懂后,再补充。
于是我考虑的解决方案是:通过分隔符“|”将输入的多行转换成一行,然后在AppleScript进行反转。的确是有些trick -_-!——不过后来查资料发现,也有人这么整。
perl代码:
@input = ();
while (<>) {
$_=~s/(^\s*)|(\s*$)//g;
push(@input,$_);
}
print join "|" ,@input;
AppleScript代码:
on run input
set myArray to my theSplit((item 1 of input) as string, "|")
set outputPath to item 1 of myArray
set pagenum to item 2 of myArray as number
set myurl to item 3 of myArray
set tempDir to item 4 of myArray
return myArray
end run
on theSplit(theString, theDelimiter)
set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to theDelimiter
set theArray to text items of theString
set AppleScript's text item delimiters to oldDelimiters
return theArray
end theSplit
脚本结果,设置到“变量”中
脚本中的变量,是无法设置到脚本中,怎么办呢?其也只能通过脚本输出结果,然后“设定变量的值”控件,对变量进行设置。
- - 设置一个变量
注意:这里有一个问题,如果脚本输出的是多行,其实只把第一行字符串,赋值到“变量”中
-
- 设置多个变量
但是如果要设置多个变量值,咋办?
于是又是一个trick方法来了,利用上面“只会把第一行赋值给变量”的机制,通过“漏斗”方式逐个对变量进行赋值:
如上图,依次对“导出路径”、“页数”等多个变量进行逐个复制。
其中perl代码作用是:过滤第一行字符串:
$count=0;
while(<>){
print $_ if $count >0 ;
$count = $count + 1 ;
}
Automator提供“录制”功能,位于右上角:
注意如果你使用录制功能,需要mac再偏好设置里,设置一下“允许Automator控制你的电脑”,这样在运行时才有用:
但是实际操作起来,我碰到了下面两个问题:
1、鼠标录制,总是不准
2、键盘录制,则永远也没有录制上去
第一个问题,我没有找到很好办法;最后没有使用;
第二个问题,不是录入,而是写代码,通过appleScript来实现:
键盘操作
脚本代码是:
on run {input, parameters}
set timeoutSeconds to 0
set uiScript to "keystroke \"a\" "
my doWithTimeout(uiScript, timeoutSeconds)
return input
end run
on doWithTimeout(uiScript, timeoutSeconds)
set endDate to (current date) + timeoutSeconds
repeat
try
run script "tell application \"System Events\"
" & uiScript & "
end tell"
exit repeat
on error errorMessage
if ((current date) > endDate) then
error "Can not " & uiScript
end if
end try
end repeat
end doWithTimeout
接下来,看看键盘操作(均是修改,标注的那一行)几种情况解决方案:
普通字符
普通字符,比较简单,使用keystroke ,输入字符就可以,比如输入”a”字符:
set uiScript to "keystroke \"a\" "
特殊字符
对于一些特殊字符,没有特殊ASCII码,比如:上、下、左、右键。因此可以考虑另外一个通过“键值”(即操作系统对按键的虚拟值)来实现,key code :
比如:“右”按键的代码是:
set uiScript to "key code 124 "
当然,key code 也可以输入普通字符,如:
“a” 按键代码是:
set uiScript to "key code 0 "
“A”按键代码是:
set uiScript to "key code 0 using {shift down} "
mac系统的虚拟键值,可以通过终端命令执行下面命令查询到:
$ grep '^ *kVK' /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h|tr -d ,|while read x y z;do printf '%d %s %s\n' $z $z ${x#kVK_};done|sort -n
或者你直接查下“附1-key code 表”也行:
组合键
上两个方法,都可以配合组合键进行使用:
set uiScript to "key code 124 using {control down, option down, command down,shift down}" --control+option+command+right+shift
Automator对于系列处理动作的流程,制作非常简单,仅仅需要拖拽基本就可以实现。
但是在分支、循环等这种逻辑上,处理起来要复杂很多。 基本稍微复杂一点的都需要脚本配合才可以的。
简单循环
Automator只提供了简单的“Loop”循环控件,这个循环控件可控执行很差,因为:
-
只能从脚本开头循环
-
循环策略支持:
A)次数/时间,但是无法通过变量控制
B)询问方式
试想一下,你就是需要从中间块循环,但是他非要从开头开始,你是无法选择的,这是个多么想哭的事情。
复杂循环
那么对于复杂的循环怎么处理?
Automator支持workflow的调用,因此如果你需要循环的话一种解决方案就是:将需要循环块的部分,写成workflow1,然后再主workflow通过脚本控制workflow1的循环。
Created with Raphaël 2.1.2 workflow开始 准备工作 调用workflow1 是否结束? 结束 yes no
注意:新建workflow1时,选择“工组流程”:
这里实现主要有两个问题:
1、workflow之间的变量是无法共享的(至少现在我发现是这样的)。它也只能想字符串一样传递。
但是这个问题:上面脚本使用一节中的“多变量的赋值”方法可以解决。
2、如何脚本调用,workflow?
通过 do shell script cmd,进行执行cmd命令调用,但是这里有一个问题就是:命令执行是不等待结束立即返回的(实现方法是新起进程执行)——目前还没有找到能够等待返回的方法。
on run input
set myArray to my theSplit((item 1 of input) as string, "|")
set outputPath to item 1 of myArray
set pagenum to item 2 of myArray as number
set myurl to item 3 of myArray
set tempDir to item 4 of myArray
delay 10
set mycount to 1000 as number
repeat
run_workflow(tempDir & "/" & (mycount) & ".pdf", "/Users/xxxx/Desktop/test2/自动截频.workflow")
if pagenum ≤ 1 then
exit repeat
end if
set pagenum to pagenum - 1
set mycount to mycount + 1
set timeoutSeconds to 2
set uiScript to "keystroke (ASCII character 29) "
my doWithTimeout(uiScript, timeoutSeconds)
end repeat
delay 1
return myArray
end run
on run_workflow(inputVars, workflowPath)
set {tid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
set theInputsList to inputVars as text
set AppleScript's text item delimiters to tid
set cmd to "automator -i '" & theInputsList & "' " & workflowPath
return do shell script cmd
end run_workflow
on theSplit(theString, theDelimiter)
set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to theDelimiter
set theArray to text items of theString
set AppleScript's text item delimiters to oldDelimiters
return theArray
end theSplit
on doWithTimeout(uiScript, timeoutSeconds)
set endDate to (current date) + timeoutSeconds
repeat
try
run script "tell application \"System Events\"
" & uiScript & "
end tell"
exit repeat
on error errorMessage
if ((current date) > endDate) then
error "Can not " & uiScript
end if
end try
end repeat
end doWithTimeout
附1-key code 表
十进制
十六进制
按键
0
0x00
ANSI_A
1
0x01
ANSI_S
2
0x02
ANSI_D
3
0x03
ANSI_F
4
0x04
ANSI_H
5
0x05
ANSI_G
6
0x06
ANSI_Z
7
0x07
ANSI_X
8
0x08
ANSI_C
9
0x09
ANSI_V
10
0x0A
ISO_Section
11
0x0B
ANSI_B
12
0x0C
ANSI_Q
13
0x0D
ANSI_W
14
0x0E
ANSI_E
15
0x0F
ANSI_R
16
0x10
ANSI_Y
17
0x11
ANSI_T
18
0x12
ANSI_1
19
0x13
ANSI_2
20
0x14
ANSI_3
21
0x15
ANSI_4
22
0x16
ANSI_6
23
0x17
ANSI_5
24
0x18
ANSI_Equal
25
0x19
ANSI_9
26
0x1A
ANSI_7
27
0x1B
ANSI_Minus
28
0x1C
ANSI_8
29
0x1D
ANSI_0
30
0x1E
ANSI_RightBracket
31
0x1F
ANSI_O
32
0x20
ANSI_U
33
0x21
ANSI_LeftBracket
34
0x22
ANSI_I
35
0x23
ANSI_P
36
0x24
Return
37
0x25
ANSI_L
38
0x26
ANSI_J
39
0x27
ANSI_Quote
40
0x28
ANSI_K
41
0x29
ANSI_Semicolon
42
0x2A
ANSI_Backslash
43
0x2B
ANSI_Comma
44
0x2C
ANSI_Slash
45
0x2D
ANSI_N
46
0x2E
ANSI_M
47
0x2F
ANSI_Period
48
0x30
Tab
49
0x31
Space
50
0x32
ANSI_Grave
51
0x33
Delete
53
0x35
Escape
55
0x37
Command
56
0x38
Shift
57
0x39
CapsLock
58
0x3A
Option
59
0x3B
Control
60
0x3C
RightShift
61
0x3D
RightOption
62
0x3E
RightControl
63
0x3F
Function
64
0x40
F17
65
0x41
ANSI_KeypadDecimal
67
0x43
ANSI_KeypadMultiply
69
0x45
ANSI_KeypadPlus
71
0x47
ANSI_KeypadClear
72
0x48
VolumeUp
73
0x49
VolumeDown
74
0x4A
Mute
75
0x4B
ANSI_KeypadDivide
76
0x4C
ANSI_KeypadEnter
78
0x4E
ANSI_KeypadMinus
79
0x4F
F18
80
0x50
F19
81
0x51
ANSI_KeypadEquals
82
0x52
ANSI_Keypad0
83
0x53
ANSI_Keypad1
84
0x54
ANSI_Keypad2
85
0x55
ANSI_Keypad3
86
0x56
ANSI_Keypad4
87
0x57
ANSI_Keypad5
88
0x58
ANSI_Keypad6
89
0x59
ANSI_Keypad7
90
0x5A
F20
91
0x5B
ANSI_Keypad8
92
0x5C
ANSI_Keypad9
93
0x5D
JIS_Yen
94
0x5E
JIS_Underscore
95
0x5F
JIS_KeypadComma
96
0x60
F5
97
0x61
F6
98
0x62
F7
99
0x63
F3
100
0x64
F8
101
0x65
F9
102
0x66
JIS_Eisu
103
0x67
F11
104
0x68
JIS_Kana
105
0x69
F13
106
0x6A
F16
107
0x6B
F14
109
0x6D
F10
111
0x6F
F12
113
0x71
F15
114
0x72
Help
115
0x73
Home
116
0x74
PageUp
117
0x75
ForwardDelete
118
0x76
F4
119
0x77
End
120
0x78
F2
121
0x79
PageDown
122
0x7A
F1
123
0x7B
LeftArrow
124
0x7C
RightArrow
125
0x7D
DownArrow
126
0x7E
UpArrow