Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

投稿者: Takaaki Naganoya

GUI Scriptingでコンテクストメニューのキャプチャを取得

Posted on 1月 24, 2020 by Takaaki Naganoya

GUI Scriptingを用いてスクリプトエディタ上でコンテクストメニューを表示させて、コンテクストメニューのキャプチャを行うAppleScriptです。macOS 10.14.6上で試しただけなので、10.15上では試していません(たぶん動くと思うのですが)。

–> Watch Demo Movie

画面キャプチャをNSImageに取得する機能については、DSCapture.frameworkをビルドして、AppleScript(実行環境はScript Debugger)から呼び出しています。

–> Download DSCapture.framework (To ~/Library/Frameworks/)

AppleScriptの鬼っ子機能である「GUI Scripting」。ある顧客が「キーボードショートカットとキーボード操作をそのままScript化することでこれを作れ」という仕様を出してきて、とても実現できない内容がまだらに含まれていたので「ナイスジョーク!」と却下した記憶があります。

「できること」(キーボードショートカット操作)に「できないこと」(目視で当該データの位置確認)を混ぜて仕様を出されると悪夢でしかありません。

あと、GUI Scriptingで操作を行うと信頼性がないうえに、信頼性を確保するためには「待つ」という処理が必要だったり、本来のAppleScriptの処理速度よりも100倍以上遅くなるので、本当に必要な箇所にだけ使う&可能なかぎり使用しないというのが自分の基本的なスタンスです。

コンテクストメニューの画面キャプチャを自動で

そんな中、新型Piyomaru Script Assistant(macOS 10.14以降対応。10.13は無視)の資料を作るために、コンテクストメニューの内容を画面キャプチャする必要に迫られました。

AppleScriptが500個ぐらい、階層化されたメニューに入っているので、これの画面キャプチャを撮るだけで一仕事です。テストで1階層分の資料を作ってみたのですが、けっこうかかります。

そこで、スクリプトエディタ上で表示させたコンテクストメニューをプログラムで撮れないかを検討することになります。

真っ先に調べたのはCocoaにそういう機能がないかどうか。自前のプログラムのビューの内容をキャプチャすることはできますが、他のアプリケーションのビューをキャプチャする機能は見つかりませんでした。

仕方がないので、画面のキャプチャをまるごと取得して、撮影対象のビューの座標から画像の切り抜きを行うようにしてみました。

GUI Scriptingでコンテクストメニューを表示させるのは無理かと思っていたのですが、できるんですね。これも冗談半分で探してみたらあっけなく方法が見つかって、

tell theTarget to perform action "AXShowMenu" --コンテクストメニューの表示

これで実際にコンテクストメニューの表示を行えました。

実現はいろいろ大変

スクリプトエディタ上の画面撮影を行うので、Scriptの実行そのものはScript Debuggerで実行。

問題になったのは2点。

1つは、画面キャプチャの撮影を行うフレームワークでメインディスプレイから画面イメージをNSImageで取得し、その結果をメイン側(暗黙のrunハンドラといったほうがいいのか)のプロパティに返しているのですが、すぐに反映されないらしくて、クラッシュを頻発。

結局、プロパティに内容が反映されたことをループで時間待ちして受信。

もう1つ困った点は、コンテクストメニューの表示解除(キャンセル)。1つのコンテクストメニュー表示&キャプチャ撮影だけでは意味がありません。選択メニュー項目を変更して、複数のコンテクストメニューのキャプチャを順次行えなくてはなりません。

いろいろな方法を試してみたものの、最前面のアプリケーションを「スクリプトエディタ」でない状態を作ればコンテクストメニュー表示状態は解除されます(このあたり、AppleScriptが純粋なプログラマーに苦手とされる理由。実際に使っているユーザーでないとこういう発想自体が出てこない)。Script Debugger側で実行しているので、Script Debuggerをactivateすることでその状態(コンテクストメニュー表示解除)を作ってみました。

そんなわけでコンテクストメニューの(選択項目を変更して全項目を選択状態にした)画面キャプチャができました。

現在は1階層分のコンテクストメニューの撮影を行なっていますが、メニュー階層をすべてAppleScript側からスキャンして、それぞれのメニューに対して、各メニュー項目を表示した状態で巡回キャプチャできるとよさそうです。

cropNSImageTo:{x1, y1, x2, y2} fromImage:theImage ハンドラは、Y座標の変換をこの用途(全画面キャプチャしたNSImageの切り抜き)の帳尻合わせのために書き換えています。この用途以外では使えないはずです。

AppleScript名:GUI Scriptingで指定したGUI部品のキャプチャを取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/24
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "DSCapture" –https://github.com/kiding/DSCapture.framework
use framework "AppKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSPNGFileType : a reference to current application’s NSPNGFileType
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep

property targPos : {0, 0}
property targSize : {0, 0}
property screenSize : {}
property outPath : ""
property captImg : missing value

set (my captImg) to missing value

tell application "System Events"
  tell process "スクリプトエディタ" –"Script Editor" (Japanese localized name)
    –Editor Area Reference
    
set theTarg to text area 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
  end tell
end tell

repeat with i from 1 to 19
  
  
set captImg to missing value
  
set outPath to (POSIX path of (path to desktop)) & ((NSUUID’s UUID()’s UUIDString()) as string) & ".png"
  
  
set {mPos, mSize} to dispMenu(i, theTarg) of me
  
copy mPos to {cx1, cy1}
  
copy mSize to {cWidth, cHeight}
  
  
screenCapture() of me
  
  
repeat 100 times
    if (my captImg) is not equal to missing value then exit repeat
    
delay 0.1
  end repeat
  
  
  
set bImg to (my cropNSImageTo:{cx1, cy1, cWidth, cHeight} fromImage:(my captImg))
  
saveNSImageAtPathAsPNG(bImg, my outPath) of me
  
  
tell current application to activate –Cancel Context Menu
  
delay 0.1
end repeat

on screenCapture()
  current application’s DSCapture’s sharedCapture()’s |full|()’s captureWithTarget:me selector:"displayCaptureData:" useCG:false
end screenCapture

–Delegate Handler
on displayCaptureData:aSender
  set aCount to aSender’s |count|()
  
set anImage to (aSender’s imageAtIndex:0)
  
set my captImg to anImage
  
–saveNSImageAtPathAsPNG(anImage, my outPath) of me
end displayCaptureData:

on cropNSImageTo:{x1, y1, x2, y2} fromImage:theImage
  set newWidth to x2
  
set newHeight to y2
  
set theSize to (theImage’s |size|())
  
set oldHeight to height of theSize
  
  
— transpose y value for Cocoa coordintates
  
set y1 to oldHeight – newHeight – y1
  
set newRect to {{x:x1, y:y1}, {width:x2, height:y2}}
  
  
theImage’s lockFocus()
  
set theRep to NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect
  
theImage’s unlockFocus()
  
  
set outImage to NSImage’s alloc()’s initWithSize:(theRep’s |size|())
  
outImage’s addRepresentation:theRep
  
  
return outImage
end cropNSImageTo:fromImage:

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveNSImageAtPathAsPNG

on dispMenu(selInd, theTarget)
  activate application "Script Editor"
  
tell application "System Events"
    tell process "スクリプトエディタ" –"Script Editor" (Japanese localized name)
      
      
ignoring application responses
        tell theTarget to perform action "AXShowMenu" –コンテクストメニューの表示
      end ignoring
      
      
tell text area 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
        tell menu 1
          set mPos to position
          
set mSize to size
          
          
set mList to every menu item
          
tell menu item (13 + selInd)
            set aRes to properties
            
set selected to true
          end tell
        end tell
      end tell
      
    end tell
  end tell
  
  
return {mPos, mSize}
end dispMenu

★Click Here to Open This Script 

Posted in GUI Scripting | Tagged 10.14savvy NSBitmapImageRep NSImage NSPNGFileType NSString NSURL NSUUID | Leave a comment

Blogへの新規ユーザー登録を停止

Posted on 1月 24, 2020 by Takaaki Naganoya

本Blogには誰でもユーザー登録できるようになっていました。フォーラムの運用を想定していたので、誰でも登録できるようになっていたほうがよいと考えたからです。

ただ、最近はスパマーのボットによるユーザー登録が増えてきて、スパマーのブラックリストを用いての確認とかユーザー削除の作業が増えてきて、一時はスパマー除去のためのプラグインを入れて様子を見ていました。

スパマー除去プラグインのお試し期間が過ぎ、一思案。

スパマー除去サービスを利用するのが最善手でありますが、そこまでするんだったらもう少し、WordPressのユーザー登録時にロボットを弾くための認証プロセスを追加するなどの方法もありそうですし(自分が考えるぐらいだから存在するでしょう)。

とりあえずの暫定措置で、ユーザー登録そのものを一時的に停止します。日本語で書いて意味があるかは不明ですが、、、

Posted in news | Leave a comment

1888年1月1日以前の日付が-1日になる問題の原因

Posted on 1月 23, 2020 by Takaaki Naganoya

Shane Stanleyにチャットで教えてもらっていました(お食事前に申し訳ない!) これは-1日になるほうが暦自体の仕様的に正しいようです。1888/1/1以前には「子午線」とかタイムゾーン(子午線ごとの標準時)という考え方自体が存在せず、1888/1/1に運用を開始した「日本標準時」に合わせてGMT +9になったため、この1888/1/1から前の日付はさかのぼって-1日される、と。

# 子午線のある現在の日付から子午線という概念がまだ存在しない日付をさかのぼった結果、日付が1日ズレた、と

現在施行されている「グレゴリオ暦」は、日本においても1873年(明治3年)に導入されました。この件については、よく知られていることです(自分の記憶があいまいで明治1年かと思っていました)。

ただ、この「グレゴリオ暦@Japan Ver.1」では子午線に関する決まりがなく、アメリカなどの国土が広い国では列車の時刻表などで問題になっていました。

その後、1884/10/11の国際子午線会議における子午線の制定を受け、日本標準時の運用が1888/1/1に開始になりました。この、1888/1/1の日本標準時の運用前にはタイムゾーンという考え方自体がなかったわけです。この、「グレゴリオ暦@Japan Ver.2」ともいえる暦法が1888/1/1に導入されたことにともない、時刻の変更とともに日付が変わったということである、と。

当時は子午線という概念そのものがなく、日本標準時が運用開始になったのが1888/1/1だということでようやく納得できました。

Classic Mac OSやMac OS X 10.6まではカレンダーの計算にこうした歴史的な経緯が加味されておらず、途中でポリシーが変更になったというのが真相のようです。累積誤差で日付が変わったんじゃなかったんですね、、、、

1582/10/15
ローマにてグレゴリオ暦 制定

1873/1/1(明治3年)
日本にてグレゴリオ暦に改暦。ただし、子午線の運用は各国間で規定がなかった。

1884/10/11
国際子午線会議

1888/1/1
日本標準時 運用開始

[おまけ] Cocoa自体のグレゴリオ暦の開始日を実際に取得してみました。

AppleScript名:gregorianStartDate.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/23
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set sDate to current application’s NSDateFormatter’s alloc()’s init()’s gregorianStartDate()
–> (NSDate) "1582-10-15 00:00:00 +0000"

set asDate to sDate as date
–> date "1582年10月15日 金曜日 9:18:59"

★Click Here to Open This Script 

Posted in Calendar History | 2 Comments

元号変換v42

Posted on 1月 23, 2020 by Takaaki Naganoya

西暦→和暦の元号を求めるAppleScriptの改修版です。

前バージョンでは、1868年から1887年までの計算が1日ズレるとか(dateオブジェクトの仕様)、明治の計算が合っていなかったので、その点を修正しました。

前バージョンまでは文字列で与えられた日付をいったんdateオブジェクトに変換していました。これは、”2020/11/31″といった正しくない日付が与えられた場合に、”2020/12/1″と妥当な解釈をし直すための処理でした。つまり、エラー対策のためだけにいったんdateオブジェクトに変換していたわけです。

これさえ行わなければ、とくにdateオブジェクトまわりの問題(before1887)は発生しません。dateオブジェクトとして解釈を行わず、単なる文字列を年、月、日に分解して、大小判定するだけの処理に置き換えました(11/31といったカレンダー的におかしな記述は無視)。

明治の計算についてもごにょごにょして修正してみました。

dateとしての年、月、日の妥当性チェックを行いたい場合には、月が1〜12、日が1〜31といった値の範囲チェックを追加で行うぐらいでしょうか。

AppleScript名:元号変換v42
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/23
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

set outList to {}
repeat with i from 1867 to 2021
  set aStr to (i as string) & "/1/25"
  
set {aGengoStr, aGengoNum} to retJapaneseGengo(aStr) of JGengoKit
  
set the end of outList to {i, aGengoStr, aGengoNum}
end repeat

return outList
–> {{1867, "(改暦前)", false}, {1868, "明治", 1}, {1869, "明治", 2}, {1870, "明治", 3}, {1871, "明治", 4}, {1872, "明治", 5}, {1873, "明治", 6}, {1874, "明治", 7}, {1875, "明治", 8}, {1876, "明治", 9}, {1877, "明治", 10}, {1878, "明治", 11}, {1879, "明治", 12}, {1880, "明治", 13}, {1881, "明治", 14}, {1882, "明治", 15}, {1883, "明治", 16}, {1884, "明治", 17}, {1885, "明治", 18}, {1886, "明治", 19}, {1887, "明治", 20}, {1888, "明治", 21}, {1889, "明治", 22}, {1890, "明治", 23}, {1891, "明治", 24}, {1892, "明治", 25}, {1893, "明治", 26}, {1894, "明治", 27}, {1895, "明治", 28}, {1896, "明治", 29}, {1897, "明治", 30}, {1898, "明治", 31}, {1899, "明治", 32}, {1900, "明治", 33}, {1901, "明治", 34}, {1902, "明治", 35}, {1903, "明治", 36}, {1904, "明治", 37}, {1905, "明治", 38}, {1906, "明治", 39}, {1907, "明治", 40}, {1908, "明治", 41}, {1909, "明治", 42}, {1910, "明治", 43}, {1911, "明治", 44}, {1912, "明治", 45}, {1913, "大正", 2}, {1914, "大正", 3}, {1915, "大正", 4}, {1916, "大正", 5}, {1917, "大正", 6}, {1918, "大正", 7}, {1919, "大正", 8}, {1920, "大正", 9}, {1921, "大正", 10}, {1922, "大正", 11}, {1923, "大正", 12}, {1924, "大正", 13}, {1925, "大正", 14}, {1926, "大正", 15}, {1927, "昭和", 2}, {1928, "昭和", 3}, {1929, "昭和", 4}, {1930, "昭和", 5}, {1931, "昭和", 6}, {1932, "昭和", 7}, {1933, "昭和", 8}, {1934, "昭和", 9}, {1935, "昭和", 10}, {1936, "昭和", 11}, {1937, "昭和", 12}, {1938, "昭和", 13}, {1939, "昭和", 14}, {1940, "昭和", 15}, {1941, "昭和", 16}, {1942, "昭和", 17}, {1943, "昭和", 18}, {1944, "昭和", 19}, {1945, "昭和", 20}, {1946, "昭和", 21}, {1947, "昭和", 22}, {1948, "昭和", 23}, {1949, "昭和", 24}, {1950, "昭和", 25}, {1951, "昭和", 26}, {1952, "昭和", 27}, {1953, "昭和", 28}, {1954, "昭和", 29}, {1955, "昭和", 30}, {1956, "昭和", 31}, {1957, "昭和", 32}, {1958, "昭和", 33}, {1959, "昭和", 34}, {1960, "昭和", 35}, {1961, "昭和", 36}, {1962, "昭和", 37}, {1963, "昭和", 38}, {1964, "昭和", 39}, {1965, "昭和", 40}, {1966, "昭和", 41}, {1967, "昭和", 42}, {1968, "昭和", 43}, {1969, "昭和", 44}, {1970, "昭和", 45}, {1971, "昭和", 46}, {1972, "昭和", 47}, {1973, "昭和", 48}, {1974, "昭和", 49}, {1975, "昭和", 50}, {1976, "昭和", 51}, {1977, "昭和", 52}, {1978, "昭和", 53}, {1979, "昭和", 54}, {1980, "昭和", 55}, {1981, "昭和", 56}, {1982, "昭和", 57}, {1983, "昭和", 58}, {1984, "昭和", 59}, {1985, "昭和", 60}, {1986, "昭和", 61}, {1987, "昭和", 62}, {1988, "昭和", 63}, {1989, "平成", 1}, {1990, "平成", 2}, {1991, "平成", 3}, {1992, "平成", 4}, {1993, "平成", 5}, {1994, "平成", 6}, {1995, "平成", 7}, {1996, "平成", 8}, {1997, "平成", 9}, {1998, "平成", 10}, {1999, "平成", 11}, {2000, "平成", 12}, {2001, "平成", 13}, {2002, "平成", 14}, {2003, "平成", 15}, {2004, "平成", 16}, {2005, "平成", 17}, {2006, "平成", 18}, {2007, "平成", 19}, {2008, "平成", 20}, {2009, "平成", 21}, {2010, "平成", 22}, {2011, "平成", 23}, {2012, "平成", 24}, {2013, "平成", 25}, {2014, "平成", 26}, {2015, "平成", 27}, {2016, "平成", 28}, {2017, "平成", 29}, {2018, "平成", 30}, {2019, "平成", 31}, {2020, "令和", 2}, {2021, "令和", 3}}

script JGengoKit
  on retJapaneseGengo(aDate as string)
    set dList to parseByDelim(aDate, "/") of me
    
if length of dList is not equal to 3 then error "Date Format Error"
    
    
copy dList to {aYear, aMonth, aDay}
    
    
tell current application
      
      
set aStr to retZeroPaddingText(aYear, 4) of me & retZeroPaddingText(aMonth, 2) of me & retZeroPaddingText(aDay, 2) of me
      
      
set aGengo to ""
      
if aStr ≥ "20190501" then
        set aGengo to "令和"
        
set aGengoNum to aYear – 2019 + 1
      else if aStr ≥ "19890108" then
        set aGengo to "平成"
        
set aGengoNum to aYear – 1989 + 1
      else if aStr ≥ "19261225" then
        set aGengo to "昭和"
        
set aGengoNum to aYear – 1926 + 1
      else if aStr ≥ "19120730" then
        set aGengo to "大正"
        
set aGengoNum to aYear – 1912 + 1
      else if aStr ≥ "18680125" then
        set aGengo to "明治"
        
if aYear = 1868 then
          set aGengoNum to 1
        else if (aYear ≥ 1869) or (aYear ≤ 1912) then
          set aGengoNum to aYear – 1867
        end if
      else
        –日本では明治以降に太陽暦を導入したのでそれ以前は意味がない?
        
set aGengo to "(改暦前)"
        
set aGengoNum to false
      end if
      
      
return {aGengo, aGengoNum}
    end tell
  end retJapaneseGengo
  
  
–数値にゼロパディングしたテキストを返す
  
on retZeroPaddingText(aNum, aLen)
    set tText to ("0000000000" & aNum as text)
    
set tCount to length of tText
    
set resText to text (tCount – aLen + 1) thru tCount of tText
    
return resText
  end retZeroPaddingText
  
  
on parseByDelim(aData, aDelim)
    set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set dList to text items of aData
    
set AppleScript’s text item delimiters to curDelim
    
return dList
  end parseByDelim
end script

★Click Here to Open This Script 

Posted in Calendar | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

1867/1/1〜1887/12/31までの範囲のdateオブジェクトからyear, month, dayを取り出すと-1日される?

Posted on 1月 22, 2020 by Takaaki Naganoya

過去のdateオブジェクトを検証する機会があり(明治の元号計算が合っていない件)、いろいろ検証していたところ、1867/1/1から1887/12/1までのdateオブジェクトからyear,month,dayを個別に取り出すと、dayが-1されるという現象が観測されました。

→ 本現象の発生メカニズムはこちら

西暦から和暦に変換する処理で、明治の年が合わないという(自分のプログラム由来の)問題を検討していました。この問題の洗い出しのため、「日」単位で順次和暦変換していたら、そのちょうど(明治→大正など)改元の境目の日付で(原因不明の)計算ミスが起こっていました。

1868/1/25からは明治時代、という判定は行えても、その1868/1/25というdateオブジェクトからYear, Month, Dayの各要素を取り出すと1868, 1, 24という結果に。

以前から「大昔の日付を扱うと問題がありそう」だとは思っていましたが、このように具体的な現象として観測したのは(個人的には)初めてでした(単に覚えていないだけかも)。

確認したのはmacOS 10.14.6とmacOS 10.15.3beta、macOS 10.13.6上ですが、どれも同じ結果になるようです。

# 追試で、OS X 10.7.5でも試してみたところ、同じ結果になりました
# OS X 10.6.8では確認されませんでした

未来のdateオブジェクトは2050年ぐらいまでチェックしてみたものの、問題はありませんでした。

過去に遡ってうるう日が設定されたとかいう話なんでしょうか? そういう話は聞いたことがないのですが、、、

日本においては太陽暦(グレゴリオ暦)を導入したのが明治元年(1868/1/25〜)なので、それ以前の日付をグレゴリオ歴で求めてもいまひとつ実用性がない(?) ともいえますが、少なくとも1868年から1887年までの間のdateオブジェクトから各種の値の取り出しが期待どおりに行われないのは問題といえるでしょう。

多分、もっと昔の日付も同様にdateオブジェクトからの値取り出しを行うと問題が出ると思われますが、前述のような理由からそこまでの日付を計算させることもないだろうかと。

# ふだん使っているgetMLenInternationalに問題があるのかと考えて、昔使っていたgetMLenを引っ張り出してきましたが、こちらはずいぶんと記法がお可愛らしい感じで、、、、

ただ、この件は気がつかなかっただけで、ずいぶん昔から存在している話なのかも????


▲Classic Mac OS 8.6では確認できませんでした(SheepShaver上で動作)この時代にはmonthをas numberで数値にcastできませんでした

AppleScript名:dateTest.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/22
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

script spd
  property mList : {}
end script

set (mList of spd) to {}
repeat with y from 1867 to 1888
  repeat with m from 1 to 12
    set aLen to getMlen(y, m) of me
    
repeat with d from 1 to aLen
      set aTmpStr to (y as string) & "/" & (m as string) & "/" & (d as string)
      
set aTmpD to date aTmpStr
      
      
set tmpY to year of aTmpD
      
set tmpM to month of aTmpD as number
      
set tmpD to day of aTmpD
      
      
if (tmpY is not equal to y) or (tmpM is not equal to m) or (tmpD is not equal to d) then
        set the end of (mList of spd) to {aTmpD, tmpY, tmpM, tmpD}
      end if
    end repeat
  end repeat
end repeat

return (mList of spd)
–> {{date "1867年1月1日 火曜日 0:00:00", 1866, 12, 31}, …… {date "1887年12月31日 土曜日 0:00:00", 1887, 12, 30}}

–現在のカレンダーで指定年月の日数を返す
on getMlenInternational(aYear as integer, aMonth as integer)
  set theNSCalendar to current application’s NSCalendar’s currentCalendar() — do *not* use initWithCalendarIdentifier:
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:1 hour:0 minute:0 |second|:0 nanosecond:0
  
set theResult to theNSCalendar’s rangeOfUnit:(current application’s NSDayCalendarUnit) inUnit:(current application’s NSMonthCalendarUnit) forDate:theDate
  
return |length| of theResult
end getMlenInternational

–指定年の指定月の日数を求める
on getMlen(aYear, aMonth)
  set aYear to aYear as number
  
set aMonth to aMonth as number
  
  
set aDat to (aYear as text) & "/" & (aMonth as text) & "/1"
  
if aMonth is 12 then
    set eDat to ((aYear + 1) as text) & "/" & (1 as text) & "/1"
  else
    set eDat to ((aYear as text) & "/" & (aMonth + 1) as text) & "/1"
  end if
  
  
set eDat to date eDat
  
set eDat to eDat – 1
  
  
set mLen to day of eDat
  
return mLen
end getMlen

★Click Here to Open This Script 

Posted in Calendar History | Tagged 10.13savvy 10.14savvy 10.15savvy | 1 Comment

Keynoteで選択中の画像を特定する

Posted on 1月 22, 2020 by Takaaki Naganoya


Keynoteの書類上で選択中のオブジェクト(image)を特定するAppleScriptです。

Keynoteには、選択中のオブジェクトを求めるという重要な機能「selection」が実装されていません。一応、最新版のKeynoteには「selection」の予約語が存在しているものの、slide中の選択オブジェクトではなく「選択中のスライド」が返ってきます。current slideとほぼ同じ動作です。これでは実用性がいまひとつです。

ないと困るselection(get selected object)ですが、実装されていないのは仕方ありません。

そのものズバリの機能が存在していないものの、他のやりかたで選択中の画像を特定してみました。数が少なかったり重複するものが存在していない場合には有効のようです。

本Scriptでは、Keynote書類上で選択中の画像があるという前提の上で、GUI Scripting経由でコピーを行い、選択対象をクリップボードに入れます。このクリップボード内の画像のサイズを取得。次に、現在のKeynote書類の現在のスライド(ページ)上の画像(imageオブジェクト)のサイズを取得し、順次照合。同じサイズのものがあれば、それが選択中のオブジェクトであると類推します。

かなり穴の多いロジックですが、最初の一歩としては悪くないでしょう。とりあえずは、サイズで比較を行い、同一のものがあれば画像同士の類似性を計算するといった方法も検討できそうです。

お手上げになってしまうのは、画像サイズや内容ともに同一のものが複数あった場合です。その場合を除けば割と識別できそうに思えます。

また、ながらく調査を行なってきた「ローカライズ言語に依存しないGUI Scripting」を用いて選択中のオブジェクトのコピーができるとよさそうです。

AppleScript名:Keynoteで選択中の画像を特定する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/22
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.7"
use scripting additions
use framework "Foundation"
use framework "AppKit"

set kRes to getSelectedImage() of me
–> image 3 of slide 24 of document id "534F4E65-4459-4B00-95D4-34C3E020467E"

on getSelectedImage()
  my executeKeynoteItemCopy() –Execute Copy From Menu
  
  
–クリップボードの内容をNSImageに
  
set aNSIMage to my getClipboardASImage()
  
if aNSIMage = false then
    return false
  end if
  
  
–クリップボード中のNSImageのサイズを取得
  
set aSize to aNSIMage’s |size|()
  
set selWidth to (aSize’s width) as real
  
set selHeight to (aSize’s height) as real
  
  
–Keynoteの最前面のドキュメントの現在のスライド上の画像からサイズを取得してクリップボード内の画像サイズと照合する
  
tell application "Keynote"
    tell front document
      tell current slide
        set iList to every image
        
        
repeat with i in iList
          set myHeight to (height of i) as real
          
set myWidth to (width of i) as real
          
if {myWidth, myHeight} = {selWidth, selHeight} then
            return contents of i
          end if
        end repeat
      end tell
    end tell
  end tell
  
return false
end getSelectedImage

— クリップボードの内容をNSImageとして取り出して返す
on getClipboardASImage()
  set theNSPasteboard to current application’s NSPasteboard’s generalPasteboard()
  
set theAttributedStringNSArray to theNSPasteboard’s readObjectsForClasses:({current application’s NSImage}) options:(missing value)
  
if theAttributedStringNSArray = {} then return false
  
set theNSAttributedString to theAttributedStringNSArray’s objectAtIndex:0
  
return theNSAttributedString
end getClipboardASImage

on executeKeynoteItemCopy()
  activate application "Keynote"
  
tell application "System Events"
    tell process "Keynote"
      –click menu item "Copy" of menu 1 of menu bar item "Edit" of menu bar 1
      
click menu item "コピー" of menu 1 of menu bar item "編集" of menu bar 1
    end tell
  end tell
end executeKeynoteItemCopy

★Click Here to Open This Script 

Posted in Clipboard GUI Scripting Image | Tagged 10.14savvy 10.15savvy Keynote NSImage NSPasteboard | Leave a comment

AirSharingLib Script Library

Posted on 1月 22, 2020 by Takaaki Naganoya

AppleScriptからAirDrop経由で他のMacやiPhone、iPadなどのiOSデバイスとファイル共有するAppleScript Library「AirSharingLib」v1.0です。

–> Download airsharinglib(To ~/Library/Script Libraries/)

もともとの内容はhttp://www.macosautomation.comに掲載されている「Sharing Utilities」ですが、現在のmacOS用に一部書き換えたのと、WiFiの強制パワーオンなどの機能を追加しています。

AirDrop経由のファイル共有については、さまざまな場面で必要になりますし、複数ファイルを指定してAirDrop共有するのはGUI側(Finder側)から行うのはなかなか操作が煩わしいので、AppleScriptから操作できると便利です。

そうしたAirDrop共有のためのAppleScriptライブラリが存在していることは重要なのですが、Sharing Utilityだといまひとつ古くなりすぎているので、さまざまなプログラムで参照するのに問題が出てくるように感じていました。

そのため、あらためてSharing Utilityとは別のライブラリをでっち上げた次第です。

AppleScript名:sample1
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/20
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
–  http://www.piyocast.com
use AppleScript version "2.7" –10.13 or later
use framework "Foundation"
use scripting additions
use airLib : script "AirSharingLib"

set fileList to (choose file with prompt "You can select multiple files with folding [SHIFT] key" with multiple selections allowed)

share with air fileList

★Click Here to Open This Script 

Posted in AirDrop Script Libraries | Tagged 10.14savvy 10.15savvy | 1 Comment

自然言語テキストから複数の日付情報を抽出

Posted on 1月 21, 2020 by Takaaki Naganoya

自然言語テキストから日付の情報(複数可)を抽出するAppleScriptです。

URLやメールアドレスの抽出では、複数のデータをNSDataDetectorで抽出するAppleScriptは書いてありましたが、日付情報の抽出を行うものはなかったので、書いておきました。

AppleScript名:自然言語テキストから複数の日付情報(複数)を抽出して日付のリストを返す.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/21
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set theDate to getDatesIn("本テキストには次の火曜日という日付情報を含んでいる。明日かもしれない。次の木曜日もそうだ。") of me
–> {date "2020年1月28日 火曜日 12:00:00", date "2020年1月22日 水曜日 12:00:00", date "2020年1月23日 木曜日 12:00:00"}

set theDate to getDatesIn("This text contains next Tuesday. The date may be tomorrow. Next Wednesday happen.") of me
–> {date "2020年1月28日 火曜日 12:00:00", date "2020年1月22日 水曜日 12:00:00", date "2020年1月29日 水曜日 12:00:00"}

on getDatesIn(aString)
  set anNSString to current application’s NSString’s stringWithString:aString
  
set theDetector to current application’s NSDataDetector’s dataDetectorWithTypes:(current application’s NSTextCheckingTypeDate) |error|:(missing value)
  
set theMatchs to theDetector’s matchesInString:anNSString options:0 range:{0, anNSString’s |length|()}
  
if theMatchs = missing value then error "No date found with String:" & aString
  
set dRes to theMatchs’s valueForKeyPath:"date"
  
return dRes as list
end getDatesIn

★Click Here to Open This Script 

AppleScript名:自然言語テキストから複数の日付情報(複数)を抽出して日付と当該箇所のリストを返す v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/21
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set theDate to getDatesAndOrigStringsIn("本テキストには次の火曜日という日付情報を含んでいる。明日かもしれない。次の木曜日もそうだ。") of me
–> {{originalStr:"次の火曜日", detectDate:date "2020年1月28日 火曜日 12:00:00"}, {originalStr:"明日", detectDate:date "2020年1月22日 水曜日 12:00:00"}, {originalStr:"次の木曜日", detectDate:date "2020年1月23日 木曜日 12:00:00"}}

set theDate to getDatesAndOrigStringsIn("This text contains next Tuesday. The date may be tomorrow. Next Wednesday happen.") of me
–> {{originalStr:"next Tuesday", detectDate:date "2020年1月28日 火曜日 12:00:00"}, {originalStr:"tomorrow", detectDate:date "2020年1月22日 水曜日 12:00:00"}, {originalStr:"Next Wednesday", detectDate:date "2020年1月29日 水曜日 12:00:00"}}

on getDatesAndOrigStringsIn(aString)
  set anNSString to current application’s NSString’s stringWithString:aString
  
set theDetector to current application’s NSDataDetector’s dataDetectorWithTypes:(current application’s NSTextCheckingTypeDate) |error|:(missing value)
  
set theMatchs to theDetector’s matchesInString:anNSString options:0 range:{0, anNSString’s |length|()}
  
if theMatchs = missing value then error "No date found with String:" & aString
  
set dRes to (theMatchs’s valueForKeyPath:"date") as list
  
set rRes to (theMatchs’s valueForKeyPath:"range") as list
  
  
set allRes to {}
  
set aLen to length of dRes
  
repeat with i from 1 to aLen
    set aSubStr to (anNSString’s substringWithRange:(item i of rRes))
    
set dDate to contents of item i of dRes
    
set the end of allRes to {originalStr:aSubStr as string, detectDate:dDate}
  end repeat
  
  
return allRes
end getDatesAndOrigStringsIn

★Click Here to Open This Script 

Posted in Calendar Natural Language Processing | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy NSDataDetector NSString | Leave a comment

Blogアーカイブ本 vol.6を販売開始

Posted on 1月 21, 2020 by Takaaki Naganoya

一部の本Blog愛読者の方々からのご要望にお応えして(慣用句)、ここにBlogアーカイブ本のVol.6(2015年)の発売をお知らせいたします。旧BlogのDBダンプからデータを取り出して、2015年11月分までしか残っていなかったので、旧Blogのアーカイブ本はこれが最終巻になります。

→ オンライン販売ページ
→ お試し版ダウンロードページ

本Blog「AppleScriptの穴」は、開設10年目を迎える直前の2018年1月末に、格安ホスティングサービス「Xserver」との間の手違いでDBがシャットダウンされ、そのままの形で公開し続けることができなくなってしまいました。

そこで、AppleScriptのプログラムによるFinder上のAppleScriptの自動HTML化、AppleScriptによるXML-RPC経由でのWordPressへの自動記事投入といったさまざまなソリューションを投下して、現在の登録記事数に復旧。自動記事投入による復旧を行なったために、当時の作業環境でオープンできない(OSバージョン依存、アプリケーション依存)Scriptについては掲載を見送っています。

 旧AppleScriptの穴:2008〜2018年 Mac OS X 10.4〜10.5の時代に開設
 現AppleScriptの穴:2018年〜   Cocoa APIを呼びまくる現在のスタイルが定着

自動投入可能なコンテンツを優先して掲載したため、旧Blogと現Blogでは掲載内容が大幅に変わっています。別物といってよいでしょう。

そのため、Cocoa APIを使用しない「オールドスタイルのAppleScript」(とくに昔のバージョンのアプリケーション依存)については再掲載が難しく、このBlogアーカイブ本シリーズにしか情報をまとめていません。

旧Blogアーカイブ本シリーズも、1年ごとに区切って記事をPDF化して6冊目。Vol.6は2015年1〜12月の1年分の内容をまとめています。全383ページ、2,000円。

ファイル形式はPDFで、キーワードによる全文検索や印刷が行えます。本文からリンクしているXcodeプロジェクトのダウンロードリンクも新たに現行Blogにアップロードしたアーカイブにリンクし直しています。

もちろん、各プログラムリスト末尾にURLリンクをそなえ、ワンクリックでプログラム内容をスクリプトエディタに転送可能です。

ほとんどの掲載プログラムについてコメントを行い、現時点(2020年時点)で評価してどうか、ということを追記しています。

AppleScriptの穴Blogアーカイブvol.6

ASObjCExtras ICU Transformのサンプル
(Free) ASObjCExtras Scripting Guide
Display情報の取得
2Dリストから、指定アイテムNoで、指定データが該当する最初のものを返す v3
指定したアプリケーションの各lproj内の各stringsファイルのパス一覧を取得する
2月1日が日曜日でうるう年ではないかチェック(ASOC)
カレンダー.app(旧称iCal)で選択中のイベントの情報を取得
起動中のプロセスの存在確認
起動中のプロセスの存在確認(ASOC)v2
Photoshop Action Setをインストールする
現在地点の緯度経度情報を取得する
CSVファイルをListにParseする(ASOC)
CSVファイルをListにParseする(ASOC) 2
errorのpartial resultとは?
レコードとレコードの連結
同スコアを考慮した順位決定
公開添削:サーバー上のファイル権限をローカルで書き換えて書き戻し
ASOCで基礎的な文字列比較
ASOCで基礎的な文字列比較 2
文字列同士が同じかチェック(大文字,小文字の差異を考慮したり無視したり)
Umlautを無視した文字列比較
ASOCで数値文字の比較
POSIX pathで与えられたパスの親フォルダを求める(末尾にスラッシュ添付)
DiskSpaceを求める
CocoaでDisk Free Space (Bytes) を求める
写真.app(Photos.app)のScript対応機能は未完成
OS X 10.10.3のdelayに(新たな)バグ? マウスカーソルの移動でdelayがキャンセルされる
Spotlight検索インデックスを再生成
2015/5
Mailで選択中のMessageの添付ファイルをデスクトップに保存
Mailで有効なmailアカウントの新規メール取得を強制的に有効にする
メモリー解放?
OS X 10.11, El Capitanが発表に
バージョン番号文字列からメジャーバージョンを取り出し数値として返す v4
SafariのWebViewへのGUI Scripting的な参照を取得する v2
URLByAppendingPathComponentのじっけん
指定のURLのYouTubeのムービーをOffLiberty経由でローカルにダウンロード
Finderで選択中の戦場の絆のリプレイムービーのファイル名を取得して対戦人数を集計する
JSON文字列とrecordの相互変換
ASOCでレコードのリストをユニーク化
ASOCでbase64エンコード、デコード
ASOCでバージョン番号文字列の正確な比較
ASOCでbase64エンコード、デコード v2
ASOCでNSStringをas stringでcastすると問題が出るバグの検証
指定の画像を別形式に変換する
現在のLocaleのIdentifier文字を取得する
ASOCで数値を指定桁でゼロパディング
指定の画像を別形式に変換する v2
指定の画像を別形式に変換する v3
フォルダアクションの操作
CPUの詳細な型番を取得する
使用中のMacの製品呼称を取得する
使用中のMacの製品呼称を取得する v2
ASOCで少数点以下の数値の切り上げ、切り下げ
ASOCでScript Editorの構文色分け情報を設定ファイルから取り出す v2
ASOCで少数点以下の数値の切り上げ、切り下げ v2
ASOCでRTFの内容を読み取って指定文字を置換してファイルに保存する
ASOCで与えられた画像ファイルがNSImageでハンドリング可能かを取得
ASOCで無線LANの各種情報を取得する
ASOCで無線LANの各種情報を取得する v2
ASOCで動的にWindowを作成
El Capitanの各Apple純正ツールのAppleScript用語辞書の変更度合い
ASOCで各種文字列からdate objectに変換 ほかNSDataDetectorの活用
NSDataDetectorを用いてテキストから各種データを抽出
MacのHardware UUIDを取得する
ASOCで性別と言語コードを指定してTTS voiceを取得 v2
ASOCでHostの情報を取得する
ASOCでNSLocaleのじっけん
100%クラッシュするNSCalendarの操作
NSTimeZoneのじっけん
ASOCでNSFont,NSFontManagerのじっけん
ASOCでプロセス関連のじっけん
ASOCでspotlight検索するじっけん
ASOCで文字を逆順に
ASOCでspotlight検索するじっけん v2
秒以下の時間待ちを検証
エラートラップのpartial result
メールアドレスの妥当性チェック
URLの妥当性チェック
URLからドメイン名を抽出
指定URLをロードしてtitleを取得
メーラーから取得したメールアドレスのうち純粋なアドレス部分を抽出 v2
現在実行中のプロセスの情報を取得
続・伏字文字列を作成する
指定URLのファイルをダウンロード
テキストの言語を推測する
与えられたテキストの言語を自動判別して対応する言語のTTS Voiceで読み上げ
マルチバイト文字の検出、の落とし穴
NSCountedSetでNSDictionaryの登場頻度集計
指定URLをロード WKWebView版
クリップボードの内容をRTFとPDFで書き出す
spotlightでタグを指定して検索
NSPredicateによる正規表現を利用した部分一致抽出
BridgePlus 1.2のframeworkの新機能テスト(1)
多国語OCR「FineReader OCR Pro」をAppleScriptでコントロール
指定フォルダのファイルパス一覧取得(拡張子指定つき)
続・指定フォルダのファイルパス一覧取得(拡張子指定つき)
文字エンコーディングを自動判別して日本語テキストファイル読み込み v1.2.1
マウスカーソルの強制移動とクリック
XML-RPCのテスト
数字以外を削除して返す
テキストとリストの変換
iWorkアプリがアップデート、AppleScript対応機能が強化される
PDFメディアサイズの取得(単位:Point)
指定ファイルに指定アイコン画像をつける
PDFの各種情報を取得する
指定ファイルのアイコン画像を取得する
アプレットのアイコンをDockに出さない
ASOCによるファイルの移動
Keynote 6.6のじっけん(3)〜表を作成してデータで埋める
指定フォルダ内のフォルダのみを取得する
Foundationのバージョンを取得する
NSErrorを生成する
Systemのアラートサウンド名称を取得して鳴らす v2
ムービーからオーディオのみ抽出してm4aで保存 v2
Safariと同じUser Agent文字列を組み立てる
Safariでアクセス中のページが設定しているCookieの値を求める
文字列のURLエンコード、デコード
iWorkアプリがアップデート。AppleScript関連の機能変更はなし
PEGKitのじっけん
Cocoaオブジェクトのクラス名を文字列で取得

Posted in PRODUCTS | Leave a comment

Numbersで書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめる

Posted on 1月 21, 2020 by Takaaki Naganoya

Numbersでオープン中の複数の書類があったときに、書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめるAppleScriptです。

さすがに、機械的な作業すぎて手で行う気にはなれなかったので、ありもののScriptを利用して作ってみました。

こういう用途のために作っておいたライブラリ「choose multiple list」を利用しています。


▲データ取得元


▲データ集約先


▲ダイアログで「データ取得元」と「データ集約先」を選択

BridgePlus内蔵のFrameworkがmacOS 10.14/10.15に邪魔されて認識されない環境では動かせないかもしれません。このあたり、SIP解除するしかないと思わせるものがあります。

ライブラリで複雑な選択を行えるUI部品を作っておいたおかげで、これだけ込み入った動作を行うAppleScriptを書きましたが、Cocoaの機能はほぼ使っていません(getDataFromNumbersDocは作り置きしておいた、頻出ルーチンなので使いまわしています)。choose multiple listライブラリは、こういう用途のために作っておいたものであり、まさにそのぴったりな用途であったといえるでしょう。

AppleScript名:書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめる.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/20
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7" — High Sierra (10.13) or later
use framework "Foundation"
use scripting additions
use bPlus : script "BridgePlus"
use mulList : script "choose multiple list"

script spd
  property allData : {}
end script

set (allData of spd) to {}

set {aName, bName} to getTargetDocNames() of me

–「データ取得元」のNumbers書類のすべてのシートの表1から2D Listでデータ取得
tell application "Numbers"
  tell document aName
    set sList to name of every sheet
    
repeat with i in sList
      set tmp2DDat to getDataFromNumbersDoc(aName, i) of me
      
set (allData of spd) to (allData of spd) & tmp2DDat
    end repeat
  end tell
end tell

set aHeight to length of (allData of spd)
set aWidth to length of item 1 of (allData of spd)

–「データ集約先」のNumbers書類の現在のシートの表1にまとめた2D Listを展開する(巨大すぎると時間がかかるので、CSV書き出ししてオープンするなどの別の方法を採るべき)
tell application "Numbers"
  tell document bName
    tell active sheet
      set tRes to make new table with properties {row count:aHeight + 1, column count:aWidth}
    end tell
  end tell
end tell

fillCurrentTable(bName, (allData of spd)) of me

–Numbersの書類の現在のシートを、指定の2次元配列でfillする
on fillCurrentTable(docName, aList)
  set aLen to length of aList
  
set aWidth to length of first item of aList
  
  
tell application "Numbers"
    tell document docName
      tell active sheet
        tell table 1
          repeat with i from 1 to aLen
            tell row (i + 1)
              set aRowList to contents of item i of aList
              
repeat with ii from 1 to aWidth
                tell cell ii
                  set aTmpData to contents of item ii of aRowList
                  
ignoring application responses
                    set value to aTmpData
                  end ignoring
                end tell
              end repeat
            end tell
          end repeat
        end tell
      end tell
    end tell
  end tell
end fillCurrentTable

–Numbersでオープン中の書類の名称一覧からデータ取得元とデータ集約先の書類名をダイアログで選択
on getTargetDocNames()
  tell application "Numbers"
    set nList to name of every document
  end tell
  
  
set selList to {nList, nList}
  
set tList to {"データ取得元", "データ集約先"}
  
  
set {aRes, bRes} to choose multiple list selList main message "各Numbers書類の役割を選択してください" sub message "「データ取得元」のデータを順次、「データ集約先」の表1に連結します" with title lists tList height 140 width 400 return type item contents without allow same items
  
return {aRes, bRes}
end getTargetDocNames

–Numbersでオープン中の書類の選択中のシートの表1からデータを取得して2D Listに
on getDataFromNumbersDoc(aDocName, sheetName)
  
  
load framework
  
  
tell application "Numbers"
    if (count (every document)) = 0 then return false
    
    
tell document aDocName
      if (count (every sheet)) = 0 then return false
      
      
tell sheet sheetName
        tell table 1
          set colCount to column count
          
set rowCount to row count
          
set headerCount to header row count
          
set footerCount to footer row count
          
          
set dList to value of every cell of cell range
        end tell
      end tell
      
    end tell
  end tell
  
  
–Convert 1D List to 2D List
  
set bList to (current application’s SMSForder’s subarraysFrom:dList groupedBy:colCount |error|:(missing value)) as list
  
set sItem to 1 + headerCount
  
set eItem to rowCount – footerCount
  
set cList to items sItem thru eItem of bList
  
  
return cList
  
end getDataFromNumbersDoc

★Click Here to Open This Script 

Posted in dialog GUI list | Tagged 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

サーバーメンテナンスが行われます

Posted on 1月 20, 2020 by Takaaki Naganoya

2018年1月にDBをふっとばしてくれたホスティング業者「Xserver」をまだ使っているわけですが、日本標準時(JST)で2020年1月21日 AM2:00〜AM8:00ごろまで、データセンター内の回線増強にともない10分から60分程度、本サイトにアクセスできなくなる見通しです。

その間は、本サイトを通じて配布している各種AppleScriptライブラリのsdefに入れている画像やムービーなどが見えなくなります。

Posted in news | Leave a comment

BlogアーカイブのMarkdown書類をリネーム。親、親+1階層フォルダをMM, YYYYとみなして反映

Posted on 1月 19, 2020 by Takaaki Naganoya

Finderで選択中のファイルすべてに対して、親フォルダ名、親+1階層のフォルダ名を反映させたファイル名をつけるAppleScriptです。

Blogアーカイブ本を作るのに、こうした道具を作って使っています。一度書いておけば、2度目からは大幅に時間を短縮できます。最初のファイルから拡張子を取得してそれを後続のファイルすべてに適用するため、同一種類のファイルである必要があります。自分用のツールならではの手抜きといったところでしょうか。

AppleScript名:BlogアーカイブのMarkdown書類をリネーム。親、親+1階層フォルダをMM, YYYYとみなして反映 .scptd
— Created 2020-01-18 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

–選択ファイルを取得
tell application "Finder"
  set aSel to selection as alias list –Select documents to Rename
end tell

set aCount to 10 –start
set aStep to 10
set aDigit to 3

–パス情報を取得
set aFirst to first item of aSel
set aPOSIX to POSIX path of aFirst
set aPathStr to (current application’s NSString’s stringWithString:aPOSIX)
set aDateComList to aPathStr’s pathComponents() –ディレクトリごとにパス情報を分割してリスト化
set aExt to aPathStr’s pathExtension() –拡張子

set aYear to (item -3 of aDateComList) as string –親の親フォルダ名
set aMonth to (item -2 of aDateComList) as string –親フォルダ名

–リネーム(数百項目を超える場合にはFinderでは遅すぎるのでNSFileManagerで処理)
tell application "Finder"
  repeat with i in aSel
    set aTEXT to numToZeroPaddingStr(aCount, aDigit, "0") of me –3 digit
    
set aName to aYear & aMonth & aTEXT & "." & aExt
    
set name of i to aName
    
set aCount to aCount + aStep
  end repeat
end tell

–整数の値に指定桁数ゼロパディングして文字列で返す
on numToZeroPaddingStr(aNum as integer, aDigit as integer, paddingChar as text)
  set aNumForm to current application’s NSNumberFormatter’s alloc()’s init()
  
aNumForm’s setPaddingPosition:(current application’s NSNumberFormatterPadBeforePrefix)
  
aNumForm’s setPaddingCharacter:paddingChar
  
aNumForm’s setMinimumIntegerDigits:aDigit
  
  
set bNum to current application’s NSNumber’s numberWithInt:aNum
  
set aStr to aNumForm’s stringFromNumber:bNum
  
  
return aStr as text
end numToZeroPaddingStr

★Click Here to Open This Script 

Posted in file File path list Markdown Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy Finder NSNumber NSNumberFormatter NSNumberFormatterPadBeforePrefix NSString | Leave a comment

osascript系のAppleScriptランタイムを区別する

Posted on 1月 18, 2020 by Takaaki Naganoya

AppleScriptのランタイム環境が何であるかを区別できるようになりました。

それらのうち、/usr/bin/osascriptを呼び出しているランタイム環境について、さらに細分化して個別に識別するために、ランタイム環境そのものと親プロセスが何であるかをAppleScriptで調査してみました。

結論からいえば、親プロセスが「bash」ならTerminalからosascriptコマンドで起動されたと判断してよさそう。その他は、実行されたScriptの置かれているパスを求めて、macOS標準装備のScript Menuかアプリケーション内部のScript Menuかを見分けるぐらいでしょうか。

これを判定したプログラム自体は、別に技術的にすごいとか機密の塊とかいうことはなくて、「清書してなくて、きたない。無駄に長い。掲載されているプログラムを見ても何も感じない」ことから掲載していません。実験用のテストプログラムでも、ちょっと近年稀に見るぐらいひどい出来です。内容は、単にランタイムプログラムのプロセスIDを取得して、そのプロセスIDをもとにpsコマンドで親プロセスを求めて、コマンドからいろいろ情報を抜いてくるというだけのものです。

Script Menu

ランタイムのパラメータ:/usr/bin/osascript -P /Users/me/Library/Scripts/Finder/pTEST.scptd
親プロセス:/System/Library/Frameworks/Foundation.framework/Versions/C/XPCServices/com.apple.foundation.UserScriptService.xpc/Contents/MacOS/com.apple.foundation.UserScriptService

与えられているScriptが特定フォルダ(/Users/me/Library/Scripts/)以下にあるものかどうか、という識別は可能。ちょっと、根拠が弱そうです。

CotEditor内のScript Menu

ランタイムのパラメータ:/usr/bin/osascript -sd -T 14534 -P /Users/me/Library/Application Scripts/com.coteditor.CotEditor/010)M-pM^_M^MM^NM-pM^_M^SM^\AppleScriptM-cM^AM-(M-cM^AM^WM-cM^AM-&M-hM-'M-#M-iM^GM^H/0020)M-pM^_M^SM^\M-fM-'M^KM-fM^VM^GM-gM-"M-:M-hM-*M^MM-cM^AM^WM-cM^AM-&M-eM-.M^_M-hM-!M^LM-cM^AM^WM-cM^@M^AM-pM^_M^SM^DM-fM^VM-0M-hM-&M^OM-fM^[M-8M-iM-!M^^M-cM^AM-+M-gM-5M^PM-fM^^M^\M-cM^BM^RM-eM^GM-:M-eM^JM^[.@r.scpt
親プロセス:/System/Library/Frameworks/Foundation.framework/Versions/C/XPCServices/com.apple.foundation.UserScriptService.xpc/Contents/MacOS/com.apple.foundation.UserScriptService

親プロセスはScript Menuと同じですが、こちらも実行しているScriptのパスが/Users/me/Library/Application Scripts/com.coteditor.CotEditor/以下であること。これも、識別のための根拠が弱いです。

Terminal経由でosascriptコマンド実行

ランタイムのパラメータ:osascript /Users/me/Desktop/pTEST.scptd
親プロセス:-bash

これは、親プロセスが-bashであることから、明確に区別できます。Terminal.appではなくbashなんですね。

Terminal経由で/usr/bin/osascript(フルパス指定)でコマンド実行

ランタイムのパラメータ:/usr/bin/osascript /Users/me/Desktop/pTEST.scptd
親プロセス:-bash

フルパスで指定すると何か変わってくるかとも思いましたが、とくに変化はありませんでした。

Program AS Style runtime name Parent Process Name Script Path
Script Editor Script/Scriptd Script Editor
Script Editor Cocoa-AppleScript Applet CocoaApplet
Script Editor Applet applet
Script Debugger Script/Scriptd Script Debugger
Script Debugger Applet (Enhanced) FancyDroplet
ASOBjC Explorer 4 Script/Scriptd ASOBjC Explorer 4
Automator Workflow Automator
Automator Applet Application Stub
Script Menu Script/Scriptd osascript …com.apple.foundation.UserScriptService /Users/me/Library/Scripts/ ほか
CotEditor Script osascript …com.apple.foundation.UserScriptService /Users/me/Library/Application Scripts/com.coteditor.CotEditor/
Terminal.app (osascript) Script/Scriptd osascript bash
Posted in OSA shell script | Tagged 10.14savvy | Leave a comment

AppleScriptを実行中のランタイムプログラム名を取得する

Posted on 1月 18, 2020 by Takaaki Naganoya

AppleScriptのランタイムプログラム名(ランタイム名)を取得するAppleScriptです。AppleScript自身が「何によって」実行されているか、その実行プログラム名を取得するものです。

AppleScriptには何種類かランタイム環境が存在し、ランタイム環境ごとに若干の動作が変わってくることが知られています。

ランタイム環境ごとにどこが違うといえば、Finderからのselectionを取得できるとかできないとか(AppleScript Studioがこれに該当。もうありませんけれども)、GUI Scriptingの権限の認証を得られるとか得られないとか。ウィンドウを動的に生成して表示したときに最前面に表示できるとかできないとか(Script Menuがこれに該当)。明示的にメインスレッドで実行する機能がないとか(Script Debuggerがこれに該当)。そういうところです(ほかにもあるかもしれない)。

過去に作ったAppleScriptを確認していたところ、プロセス名を取得するだけの使えないプログラムだと思っていたものが、実は「ランタイムプログラムのプログラム名」を取得できるというスゲーものであることを再発見しました。

ながらく、ランタイムプログラム名をAppleScript側から取得する必要性を感じていたため、この機会に調べてみることに。プログラム自体は些細な(↓)ものです。

AppleScript名:ランタイム環境名の表示
— Created 2015-09-08 by Takaaki Naganoya
— 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set procInfo to current application’s NSProcessInfo’s processInfo()
set aName to procInfo’s processName() as string
display dialog aName

★Click Here to Open This Script 

Script Editor上で実行


–> “Script Editor”

Script Debugger上で実行


–> “Script Debugger”

ASObjC Explorer 4上で実行


–> “ASObjC Explorer 4”

Automator上で実行


–> “Automator”
これには驚きました。特別のランタイムプログラムが使われているのか、それとも単に親プロセスとしてのAutomatorが返ってきているのかは不明ですが、識別できるということには意義がありそうです。

Script Menu上で実行


–> “osascript”
これは、よく知られていることなのでとくに驚きはありません。テストを実施したのはmacOS 10.14.6上で、Script Menuは「スクリプトメニュー」という別アプリケーション(/System/Library/CoreServices/ にある)に変更になったOSバージョンですが、ランタイムにosascriptを使い続けていることを確認することになりました(それ以前のOSと挙動が同じなのでそうだと思っていましたけれども)。

Folder Action上で実行




–> “osascript”
Folder Actionは、macOS標準搭載のフォルダ監視機能です。監視対象のフォルダにファイルが追加されたり、移動されたり、フォルダそのものがオープンしたりするとその対象ファイル/フォルダで指定のAppleScriptを実行します。よく、ドラッグ&ドロップで処理を受け付けたり、ネットワーク経由でファイルを受信した場合にAppleScriptを実行するような使われ方をします。
Folder Action Disptcherが実行しているとばかり思っていたのですが、実際に確認したらosascriptでした。ちなみに、Folder ActionはmacOS 10.11でフルに書き換えられてそれ以前とは別物になっています。以前は数秒に一度対象フォルダをチェックする方式でしたが、10.11以降はFSEventsを利用して随時監視対象フォルダへの変更を受け付けます。

Switch Control上で実行



–> “osascript”
障害者向けの機能としてmacOSに標準装備されている、フローティングパレットからAppleScriptを呼び出せる機能である「Switch Control」。手を使わずに操作したり、他のコントローラで操作するような標準的ではない使い方をサポートするための機構ですが、普通に普通の人が使っても役立ちます。 
Switch ControlでAppleScriptを実行する場合のランタイムプログラムはosascriptです。

CotEditor上で実行


–> “osascript”
これは、CotEditorのソースを読んで確認してありました。ここだけ割と手抜き実装ですが、それでも複数のOSA言語に対応できたりと機能的には悪くはありません。むしろ、osascript側のランタイム環境が他の環境よりも一段落ちることに問題が、、、、GUI Scriptingの権限を取得できないこととか、このCotEditorのメニューから実行するとREST APIが呼び出せないとか。同じosascript系でもScript Menuのほうが制約が少ないのは、おそらくアプリケーション自体に許可されている条件の違いによるものでしょう。

FileMaker Pro上でスクリプトステップ「AppleScriptを実行」を実行


–> “FileMaker Pro”
FileMaker Proはランタイムアプリケーションが廃止され、FileMaker Pro AdvancedもFileMaker Proに一本化されたので、v19以降はFileMaker Proは「FileMaker Pro」というランタイムのみでしょう。v19でもFileMaker Pro自体はSandbox化されていないため、微妙にセキュリティ上の制約が少ない=自由度の高いランタイム環境として残っていくことでしょう。

Script EditorからApplet書き出しして実行


–> “applet”
取得できたらいいなぐらいの気持ちで試してみたものの、これが識別できるのはうれしい誤算です。書き出したAppleScript Applet名は「Appletでランタイム名を取得」であったため、この「applet」というものとは異なります(ねんのため)。

AutomatorからApplet書き出しして実行


–> “Application Stub”
見たことのない名前が、、、、やっぱり、これも別ランタイムなんですね、、、、

Script DebuggerからApplet(Enhanced)で書き出しして実行


–> “FancyDroplet”
Appleの標準ランタイムとはあきらかに別物(Enhanced)なので、たぶん別の名前がついているだろうとは思っていましたが、そういう名前でしたか。名前が予想外だったので驚かされましたが、識別できることに意義があります。

Cocoa-AppleScript Appletを実行


–> “CocoaApplet”
Script Editor上で作成できる、通常のAppleScriptとXcode上で作成するCocoa-Applicationの中間的な性格を持つ「Cocoa-AppleScript Applet」でランタイムプログラム名を取得したらこうなりました。

もちろん、実行プログラム名はまったく別の「ランタイム名を表示するだけのCocoa-AppleScript Applet」というものです。

ショートカットで「AppleScriptを実行」アクションを実行


–> “MacHelper”

macOS 12で搭載されたショートカット.app(Shortcuts.app)および不可視プロセスのAppleScriptの補助専用アプリケーション「Shortcuts Events.app」上で、アクション「AppleScriptを実行」でAppleScriptを実行するときのランタイム名は、「MacHelper」です。意外なところで、ユーザーディレクトリ以下にインストールされたAppleScriptライブラリをこのMacHelper環境は認識します。

→ macOS 13上では、ショートカット.app(Shortcuts.app)およびShortcuts Events.app上のランタイム名が「ShortcutsMacHelper」に変更されました。

RedSweater Software「FastScripts」からAppleScriptを実行

red sweater softwareによるメニュー常駐型Script Menuソフトウェア「FastScripts」から実行したときのランタイム名は「FascScripts Script Runner」です。

Knurling Group「Service Station」からAppleScriptを実行

Knurling Groupによるコンテクストメニューのカスタマイズ・ソフトウェア「Service Station」から実行したときのランタイム名は「osascript」です。

ランタイム名が得られることで実現できること

これらのほか、各アプリケーション内でAppleScript呼び出し機能を有するもの(ファイルメーカー、Mail.appなど)でランタイムプログラム名を取得すると有益な情報が得られることでしょう。

これは、地球上にいる人類が観測衛星を打ち上げて「ここは銀河系だ」と観測できるぐらいすごいことなので、割と意義深いものです。実行中のAppleScriptが、「いま、何のプログラムによって自分自身が実行されている」かという情報を取得できます。

ランタイムプログラムの名称取得については、いくつかのAppleScript実行方法を試してみましたが、得られる名前に違いがないことを確認しています。

直接AppleScriptを動かす方法に加え、間接的にAppleScriptを動かす方法も試してみましたが、同じ結果が得られました。

つまり、動的にOSAScriptViewを生成して実行しようが、NSAppleScriptで実行しようが、AppleScriptの「run script」コマンドで実行しようが、取得されるランタイム名には差がありません。

これで、ランタイム環境のプロセスの親プロセスの情報が取得できると、Terminal.app上から起動したosascriptコマンドで呼び出したのか、Script Menu上から呼び出したのかという状況をAppleScript側で認識できることになることでしょう。

ランタイム環境を識別した上で、各環境で実行できない処理を行わないとか、ランタイム環境ごとに処理を分岐できるようになることでしょう。

ちょうど、Edama2さんと「ランタイム環境ごとに若干の挙動の違いが見られるし、利用できるCocoaの機能にも違いがあるから、ランタイム環境ごとに認識コードでも振ってみようか」などと相談していたので、渡りに船でした。

Posted in OSA | Tagged 10.13savvy 10.14savvy 10.15savvy Automator CotEditor Script Debugger Script Editor | Leave a comment

display drop dialog Script Library

Posted on 1月 16, 2020 by Takaaki Naganoya

指定UTIのファイルのFinderからのドラッグ&ドロップを受け付けるAppleScript Libraries「display drop dialog」をリリース、フリー配布いたします。

# 本ライブラリはEdama2さんのScriptに若干の改変を行い、sdefをつけてパラメータのエラー処理を行い、コードサインしてライブラリ化したものです

–> Download display drop dialog Script Library (To ~/Library/Script Libraries/)

本ライブラリは、指定UTIの書類のドラッグ&ドロップを受け付けるダイアログをAppleScriptから手軽に使えるようにするものです。macOS 10.14以降で動作します。

現在のAppleのTim Cook体制は、セキュリティ強化の美名のもとに「動かないコンピュータ」を目指し、各種機能を阻害する方向に進んでいます。

AppleScriptの世界はその中でも自由度が比較的高い状態にありますが、それでもmacOS 10.12以降では、AppleScriptドロップレットにFinderからドラッグ&ドロップしても、Finderの拡張属性(Xattr)がついたファイルは無視されたりと、なかなか困ります。

そこで、Finderからのドラッグ&ドロップ操作を通常の(Applet書き出ししていない)AppleScript、とくにScript Menuから呼び出す形式のAppleScriptで使えるようにすることを目的として本ライブラリを作成しました。

本ライブラリを用いることで、ドロップレットを作らなくても、Script Menuから呼び出した普通のAppleScriptにファイルのドラッグ&ドロップの受信機能を追加できます。セキュリティと機能性(ドラッグ&ドロップ)を両立させるため、すべてのScripterに欠かすことのできないライブラリになるものと期待しています。

本ライブラリのAppleScript用語辞書には実行イメージ(画面キャプチャ)およびサンプルScriptを入れてあり、実行時の様子やサンプルスクリプト(本Blogと同様のワンクリックで内容が転送されるリンクつき)を確認できるようになっています。

AppleScript名:accept AppleScript documents
use dropLib : script "display drop dialog"

set aMainMes to "Drop AppleScript"
set aSubMes to "Drag and Drop AppleScript files here"
set aUTI to "com.apple.applescript.script"
set execButtonTitle to "Execute"
set aRes to (display drop dialog aUTI main message aMainMes sub message aSubMes with initial folder "" OK button title execButtonTitle)
–> {alias "Machintosh HD:Users:me:Documents:display drop dialog:accept PNG images.scpt", alias "Machintosh HD:Users: me:Documentsaccept Markdown documents.scpt"}

★Click Here to Open This Script 

AppleScript名:accept Markdown documents
use dropLib : script "display drop dialog"

set aMainMes to "Drop Markdown Documents"
set aSubMes to "Drag and Drop Markdown documents here"
set aUTI to "net.daringfireball.markdown"
set execButtonTitle to "Execute"
set aRes to (display drop dialog aUTI main message aMainMes sub message aSubMes with initial folder "" OK button title execButtonTitle)
–> {alias "Machintosh HD:Users:me:Documents::–Book 11 「Blog Archives vol5 2013-2014」:2013:01:201301013.md", alias "Machintosh HD:Users:me:Documents::–Book 11 「Blog Archives vol5 2013-2014」:2013:01:201301012.md"}

★Click Here to Open This Script 

AppleScript名:accept PNG images with initial folder contents
use scripting additions
use dropLib : script "display drop dialog"

set aMainMes to "Drop PNG"
set aSubMes to "Drag and Drop png images here"
set aUTI to "public.png"
set execButtonTitle to "Execute"
set iFolder to path to pictures folder –At first, PNG files in this folder is displayed
set aRes to (display drop dialog aUTI main message aMainMes sub message aSubMes with initial folder iFolder OK button title execButtonTitle)
–> {alias "Machintosh HD:Users:me:Pictures:1015sedhelp2.png", alias "Machintosh HD:Users:me:Pictures:574G01.png", alias "Machintosh HD:Users:me:Pictures:macDown1.png", alias "Machintosh HD:Users:me:Pictures: 2017-09-27 19.33.53.png", alias "Machintosh HD:Users:me:Pictures:2018-11-01 10.54.06.png"

★Click Here to Open This Script 

Posted in dialog GUI PRODUCTS Script Libraries sdef | Tagged 10.14savvy 10.15savvy | Leave a comment

Microsoft Edgeが正式リリース

Posted on 1月 16, 2020 by Takaaki Naganoya

MicrosoftによるGoogle Chrome(オープンソース版のChromium)をベースにした(そのまま)Webブラウザ「Microsoft Edge」の正式版がリリースされました。

ChromiumはAppleScriptに対応しており、ベータ版である「Edge Canary」もChromiumと同様のAppleScript用語辞書を備えていました(A=B)。

正式版「Edge」のAppleScript用語辞書と「Edge Canary」の用語辞書とdiffをとってみたところ、内容が同じであることを確認できました(B=C)。

このため、Google Chromium用のAppleScriptとtell文のアプリケーション名だけ書き換えればEdge用のAppleScriptとして動かせることが期待できます(メニューやボタンを直接動かすGUI Sciriptingをのぞく)。


▲メニュー構成はけっこう違います

Posted in news | Tagged Microsoft Edge | Leave a comment

Blog アーカイブVol.5 rev1.1を公開

Posted on 1月 16, 2020 by Takaaki Naganoya

発売したばかりの「BlogアーカイブVol.5」ですが、画像のリンク抜けがあるとのご報告をいただき、すぐさま修正版をリリースしました。すでにお買い上げの方々におかれましても、再ダウンロードでダウンロードできるはずなので、おためしください。

本件については、画像リンクチェッカーAppleScriptの機能を強化。これまでも、Markdownタグでリンクした画像のリンク抜けについてはAppleScriptで自動チェックを行なっていたのですが、HTMLタグで入れた画像リンクについてはチェック対象外となっていました。

そこで、画像リンクチェッカー「指定ディレクトリ以下のMarkdown書類のリモート画像URLのリンク切れをチェック(Markdown、HTMLタグ両方)」を作成し、自動でMarkdown/HTMLタグで記述された画像リンクチェックを実施。

5か所ほど画像リンク抜けが見つかったので、その点を修正したRev. 1.1をアップロードしました。

表紙と奥付のリビジョン表記が1.0から1.1になっています。

原稿(Pages&Markdown書類)→PDF書き出し→PDF結合→TOC作成 と、ワークフローをAppleScriptで自動化しており、こうしたツールを作ってきたからこそ、たった1人で執筆、編集、発行(販売)を行えるようになっている次第です。

なお、画像リンク抜け以外の箇所はほとんど変わっていませんので、現時点でお手もとにあるPDFで不満のない場合にはそのままでもけっこうです。

Posted in Books PRODUCTS | Leave a comment

Numbersでオープン中の最前面の書類のすべてのシートの表1の行数合計を計算する

Posted on 1月 15, 2020 by Takaaki Naganoya

Numbersでオープン中の最前面の書類のすべてのシートの表1の行数の合計を計算するAppleScriptです。

Blogアーカイブ本作成のために書いたものです。

この記事数をカウントするために使いました。

AppleScript名:Numbersでオープン中の最前面の書類のすべてのシートの表1の行数合計を計算する
set aCount to 0

tell application "Numbers"
  tell front document
    set sList to every sheet
    
repeat with i in sList
      tell i
        try
          set tmpC to count every row of table 1
          
set aCount to aCount + tmpC
        end try
      end tell
    end repeat
  end tell
end tell

return aCount

★Click Here to Open This Script 

Posted in Number | Tagged 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

アラートダイアログ上にTable Viewを表示 v9_アイコンを表示、Finderからのドラッグ&ドロップ

Posted on 1月 15, 2020 by Takaaki Naganoya

Edama2さんからの投稿Scriptです。アラートダイアログ中に各種GUI部品を詰め込む「箱庭インタフェース」シリーズ。テーブルビューを表示して、Finderからのアプリケーションのドラッグ&ドロップを受け付けるAppleScriptです。

–> Download Editable & Executable Script Bundle Document

カスタムクラスの作り方がわかったので、懲りずにTable Viewネタです。
Thanks  Shane Stanley!

アプリケーションフォルダ直下のアプリを、NSValueTransformerを使ってコラムにローカライズ名とアイコンを表示するのと、finderからのドラッグ&ドロップでアイテムの追加です。
追加時に重複チェックをしているので試す時はユーティリティフォルダか別の場所にあるアプリで試してください。

本Scriptは自分も作りたいと思いつつも調査が進んでいなかったものですが、TableViewでFinderからのドラッグ&ドロップを受け付けます。

これを鍛えて再利用しやすい部品に育てることで、ドロップレットの代替品にできると思っています。macOS 10.12以降、Finder上のファイルをAppleScriptドロップレットにドラッグ&ドロップで処理させても、OS側がダウンロードファイルにつけた拡張属性(Xattr)「com.apple.quarantine」がついているとドロップレット側で処理できなかったりします(回避方法はありますけれども)。

このドロップレットという仕組みを使わずに、同様にドラッグ&ドロップによる処理を手軽にできる代替インタフェースとしてこのようなものを考えていた次第です。自分で作らなくてもEdama2さんが作ってくださったので助かりました、、、、

AppleScript名:アラートダイアログ上にTable Viewを表示 v9_アイコンを表示、Finderからのドラッグ&ドロップ
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppleScriptObjC"
use scripting additions

on run
  my main()
end run
on main()
  # Script Bundle内のResourcesフォルダを求める
  
set resourcePath to POSIX path of (path to me) & "Contents/Resources/"
  
set theBundle to current application’s NSBundle’s bundleWithPath:resourcePath
  
theBundle’s loadAppleScriptObjectiveCScripts()
  
  
#
  
set aFolder to path to applications folder
  
set aPath to aFolder’s POSIX path
  
set aURL to current application’s NSURL’s fileURLWithPath:aPath
  
  
# 指定フォルダの直下のファイルを取得
  
set filePaths to current application’s NSFileManager’s defaultManager’s ¬
    contentsOfDirectoryAtURL:aURL ¬
      includingPropertiesForKeys:{current application’s NSURLNameKey} ¬
      
options:(current application’s NSDirectoryEnumerationSkipsHiddenFiles) ¬
      
|error|:(missing value)
  
  
set filePaths to filePaths as list
  
set thisFileType to "com.apple.application-bundle"
  
  
set fileURLs to {}
  
repeat with anItem in filePaths
    
    
set aPath to anItem’s contents’s POSIX path
    
set aURL to (current application’s NSURL’s fileURLWithPath:aPath)
    
    
set {aResult, aUTI, aError} to (aURL’s getResourceValue:(reference) ¬
      forKey:(current application’s NSURLTypeIdentifierKey) ¬
      
|error|:(reference))
    
    
if (aUTI as text) is thisFileType then
      set fileURLs’s end to aURL
    end if
  end repeat
  
  
set optionRec to {fileURLs:fileURLs, fileType:thisFileType}
  
  
set aMainMes to "アプリケーションの選択"
  
set aSubMes to "適切なものを以下からえらんでください"
  
set dateObj to my chooseItemByTableView(aMainMes, aSubMes, optionRec)
end main

# アラートダイアログでtableviewを表示
on chooseItemByTableView(aMainMes, aSubMes, optionRec)
  ### set up view
  
set {theView, makeObj} to my makeContentView(optionRec)
  
  
set paramObj to {myMessage:aMainMes, mySubMessage:aSubMes, setView:theView, myOption:makeObj}
  
my performSelectorOnMainThread:"raizeAlert:" withObject:paramObj waitUntilDone:true
  
  
if (my _retrieve_data) is missing value then error number -128
  
return (my _retrieve_data)
end chooseItemByTableView

## retrieve date
on raizeAlert:paramObj
  set mesText to paramObj’s myMessage
  
set infoText to paramObj’s mySubMessage
  
set theView to paramObj’s setView
  
set aTableObj to paramObj’s myOption
  
  
global _retrieve_data
  
set _retrieve_data to missing value
  
  
### set up alert
  
tell current application’s NSAlert’s new()
    setMessageText_(mesText)
    
setInformativeText_(infoText)
    
addButtonWithTitle_("OK")
    
addButtonWithTitle_("Cancel")
    
setAccessoryView_(theView)
    
tell |window|()
      setInitialFirstResponder_(theView)
    end tell
    
#### show alert in modal loop
    
if runModal() is (current application’s NSAlertSecondButtonReturn) then return
  end tell
  
  
### retrieve date
  
set aIndexSet to aTableObj’s selectedRowIndexes()
  
  
set chooseItems to ((aTableObj’s dataSource())’s arrangedObjects()’s objectsAtIndexes:aIndexSet) as list
  
set _retrieve_data to {}
  
repeat with anItem in chooseItems
    set _retrieve_data’s end to anItem’s fileURL
  end repeat
end raizeAlert:

## ContentView を作成
on makeContentView(paramObj)
  ## 準備
  
set fileURLs to (paramObj’s fileURLs) as list
  
set thisFileType to (paramObj’s fileType) as text
  
  
set keyrec to {column1:"Name"}
  
set keyDict to (current application’s NSDictionary’s dictionaryWithDictionary:keyrec)
  
  
set theDataSource to current application’s YKZArrayController’s new()
  
  
## NSTableView
  
tell current application’s NSTableView’s alloc()
    tell initWithFrame_(current application’s CGRectZero)
      setAllowsEmptySelection_(false)
      
setAllowsMultipleSelection_(true)
      
setDataSource_(theDataSource)
      
setDelegate_(theDataSource)
      
setDoubleAction_("doubleAction:")
      
setGridStyleMask_(current application’s NSTableViewSolidVerticalGridLineMask)
      
setSelectionHighlightStyle_(current application’s NSTableViewSelectionHighlightStyleRegular)
      
setTarget_(theDataSource)
      
setUsesAlternatingRowBackgroundColors_(true)
      
      
set thisRowHeight to rowHeight() as integer
      
set theDataSource’s _table_view to it
    end tell
  end tell
  
  
# data sourceに追加
  
tell (theDataSource)
    awakeFromNib()
    
set its _file_type to thisFileType
    
    
repeat with aURL in fileURLs
      addObject_({fileURL:aURL})
    end repeat
    
    
setSelectionIndex_(0)
  end tell
  
  
## NSTableColumn
  
### Columnの並び順を指定する
  
set viewWidth to 320
  
set columnsCount to keyDict’s |count|()
  
repeat with colNum from 1 to columnsCount
    
    
set keyName to "column" & colNum as text
    
set aTitle to (keyDict’s objectForKey:keyName)
    
    
tell (current application’s NSTableColumn’s alloc()’s initWithIdentifier:(colNum as text))
      tell headerCell()
        setStringValue_(aTitle)
        
set thisHeaderHeight to cellSize()’s height
      end tell
      
      
### Columnの横幅を指定
      
setWidth_(viewWidth)
      
      
### バインディングのオプション
      
— ソートを無効にする
      
set anObj to (current application’s NSNumber’s numberWithBool:false)
      
set aKey to current application’s NSCreatesSortDescriptorBindingOption
      
set bOptions to (current application’s NSDictionary’s dictionaryWithObject:anObj forKey:aKey)
      
      
### 表示内容をNSArrayControllerにバインディング
      
bind_toObject_withKeyPath_options_(current application’s NSValueBinding, theDataSource, "arrangedObjects", bOptions)
      
      (
theDataSource’s _table_view’s addTableColumn:it)
    end tell
    
  end repeat
  
  
## NSScrollView
  
### Viewの高さを計算
  
set rowCount to 12 –> 行数を固定
  
set viewHeight to (thisRowHeight + 2) * rowCount + thisHeaderHeight –> 2を足さないと高さが合わない
  
set vSize to current application’s NSMakeRect(0, 0, viewWidth, viewHeight)
  
  
### Viewを作成
  
tell current application’s NSScrollView’s alloc()
    tell initWithFrame_(vSize)
      setBorderType_(current application’s NSBezelBorder)
      
setDocumentView_(theDataSource’s _table_view)
      
–setHasHorizontalScroller_(true)
      
setHasVerticalScroller_(true)
      
set aScroll to it
    end tell
  end tell
  
  
return {aScroll, theDataSource’s _table_view}
end makeContentView

★Click Here to Open This Script 

AppleScript名:subClasses
#MARK: – NSValueTransformer
script YKZURLToIcon
  property parent : class "NSValueTransformer"
  
property allowsReverseTransformation : false –>逆変換
  
property transformedValueClass : a reference to current application’s NSImage –>クラス
  
  
#変換処理
  
on transformedValue:fileURL
    if fileURL is missing value then return
    
    
set appPath to fileURL’s |path|()
    
set iconImage to current application’s NSWorkspace’s sharedWorkspace’s iconForFile:appPath
    
return iconImage
  end transformedValue:
end script

script YKZURLToDisplayedName
  property parent : class "NSValueTransformer"
  
property allowsReverseTransformation : false –>逆変換
  
property transformedValueClass : a reference to current application’s NSString –>クラス
  
  
#変換処理
  
on transformedValue:fileURL
    if fileURL is missing value then return
    
    
set appPath to fileURL’s |path|()
    
set displayedName to current application’s NSFileManager’s defaultManager’s displayNameAtPath:appPath
    
return displayedName
  end transformedValue:
end script

#MARK: – Array Controller
script YKZArrayController
  property parent : class "NSArrayController"
  
  
#MARK: IBOutlets
  
property _table_view : missing value
  
#MARK:
  
property _data_type : do shell script "uuidgen"
  
property _file_type : ""
  
  
on awakeFromNib()
    –log "YKZArrayController – awakeFromNib"
    
tell _table_view
      registerForDraggedTypes_({current application’s NSFilenamesPboardType, _data_type})
      
setDraggingSourceOperationMask_forLocal_(current application’s NSDragOperationCopy, false)
    end tell
    
    
#Transformerの登録
    
set tNames to {}
    
set tNames’s end to "YKZURLToIcon"
    
set tNames’s end to "YKZURLToDisplayedName"
    
repeat with aTransformer in tNames
      set theTransformer to current application’s class aTransformer’s new()
      (
current application’s NSValueTransformer’s setValueTransformer:theTransformer forName:aTransformer)
    end repeat
  end awakeFromNib
  
  
#MARK: Data Source Overrides
  
on numberOfRowsInTableView:aTableView
    return my content()’s |count|()
  end numberOfRowsInTableView:
  
  
on tableView:aTableView viewForTableColumn:aColumn row:aRow
    –log "viewForTableColumn"
    
    
set aCellView to aTableView’s makeViewWithIdentifier:"YKZTableCellView" owner:me
    
–set isNull to aCellView’s isEqual:(current application’s NSNull’s |null|())
    
–log isNull as text
    
    
if aCellView is missing value then
      
      
set frameRect to current application’s NSMakeRect(0, 0, aColumn’s width, aTableView’s rowHeight())
      
set aCellView to current application’s YKZTableCellView’s alloc’s initWithFrame:frameRect
      
      
set anObj to "YKZURLToIcon"
      
set aKey to current application’s NSValueTransformerNameBindingOption
      
set bOptions to (current application’s NSDictionary’s dictionaryWithObject:anObj forKey:aKey)
      (
aCellView’s imageView())’s bind:(current application’s NSValueBinding) toObject:aCellView withKeyPath:"objectValue.fileURL" options:bOptions
      
      
set anObj to "YKZURLToDisplayedName"
      
set aKey to current application’s NSValueTransformerNameBindingOption
      
set bOptions to (current application’s NSDictionary’s dictionaryWithObject:anObj forKey:aKey)
      (
aCellView’s textField())’s bind:(current application’s NSValueBinding) toObject:aCellView withKeyPath:"objectValue.fileURL" options:bOptions
      
    end if
    
    
return aCellView
  end tableView:viewForTableColumn:row:
  
  
# テーブル内のセルが編集できるか
  
on tableView:aTableView shouldEditTableColumn:aColumn row:aRow
    return false
  end tableView:shouldEditTableColumn:row:
  
  
# テーブル内をダブルクリックしたらOKボタンを押す
  
on doubleAction:sender
    log "doubleAction"
    
## ヘッダをクリックした時は何もしない
    
if (sender’s clickedRow()) is -1 then return
    
    
set theEvent to current application’s NSEvent’s ¬
      keyEventWithType:(current application’s NSEventTypeKeyDown) ¬
        location:(current application’s NSZeroPoint) ¬
        
modifierFlags:0 ¬
        
timestamp:0.0 ¬
        
windowNumber:(sender’s |window|()’s windowNumber()) ¬
        
context:(current application’s NSGraphicsContext’s currentContext()) ¬
        
|characters|:return ¬
        
charactersIgnoringModifiers:(missing value) ¬
        
isARepeat:false ¬
        
keyCode:0
    current application’s NSApp’s postEvent:theEvent atStart:(not false)
  end doubleAction:
  
  
#MARK: Drag Operation Method
  
#ドラッグを開始(ペーストボードに書き込む)
  
on tableView:aTableView writeRowsWithIndexes:rowIndexes toPasteboard:pboard
    –log "writeRowsWithIndexes"
    
set aData to current application’s NSKeyedArchiver’s archivedDataWithRootObject:rowIndexes
    
pboard’s declareTypes:{_data_type} owner:(missing value)
    
pboard’s setData:aData forType:_data_type
    
return true
  end tableView:writeRowsWithIndexes:toPasteboard:
  
#ドラッグ途中
  
on tableView:aTableView validateDrop:info proposedRow:row proposedDropOperation:operation
    –log "validateDrop"
    
#列の間にドラッグ
    
if (operation is current application’s NSTableViewDropAbove) then
      return current application’s NSDragOperationMove
    end if
    
#項目の上にドラッグ
    
set aTypes to info’s draggingPasteboard’s types()
    
if (aTypes’s containsObject:_data_type) as boolean then
      return current application’s NSDragOperationNone
    end if
    
return current application’s NSDragOperationNone
  end tableView:validateDrop:proposedRow:proposedDropOperation:
  
#ドラッグ終了
  
on tableView:aTableView acceptDrop:info row:row dropOperation:operation
    –log "acceptDrop"
    
#
    
set pboard to info’s draggingPasteboard()
    
set aTypes to pboard’s types()
    
    
if (aTypes’s containsObject:_data_type) as boolean then
      
      
set rowData to pboard’s dataForType:_data_type
      
set rowIndexes to current application’s NSKeyedUnarchiver’s unarchiveObjectWithData:rowData
      
      
if (rowIndexes’s firstIndex()) < row then
        set row to row – (rowIndexes’s |count|())
      end if
      
      
set aRange to current application’s NSMakeRange(row, rowIndexes’s |count|())
      
set aIndexSet to current application’s NSIndexSet’s indexSetWithIndexesInRange:aRange
      
      
set anObj to ((my content())’s objectsAtIndexes:rowIndexes)
      
my removeObjects:anObj
      
my insertObjects:anObj atArrangedObjectIndexes:aIndexSet
      
my rearrangeObjects()
      
    else
      set pathList to pboard’s propertyListForType:(current application’s NSFilenamesPboardType)
      
–log result as list
      
repeat with aPath in pathList
        set isAdd to addItem_({filePath:aPath, atIndex:row})
        
if isAdd then beep
      end repeat
      
    end if
    
return true
  end tableView:acceptDrop:row:dropOperation:
  
  
#追加する
  
on addItem:sender –> {filePath:aPath, atIndex:aIndex}
    –log "addItem:"
    
set isAdd to false
    
    
#missing valueの時は最後に追加
    
set {filePath:aPath, atIndex:aIndex} to sender
    
if aIndex is missing value then
      set aIndex to my content()’s |count|() as number
    end if
    
    
#URLに変換
    
set appURL to (current application’s NSURL’s fileURLWithPath:aPath)
    
#アプリケーション以外は追加しない
    
set {aResult, aUTI, aError} to (appURL’s getResourceValue:(reference) ¬
      forKey:(current application’s NSURLTypeIdentifierKey) ¬
      
|error|:(reference))
    log aUTI
    
if (aUTI as text) is not (my _file_type as text) then return isAdd
    
    
#すでにあるか確認
    
set bList to my content() as list
    
repeat with aRecord in bList
      if ((appURL’s isEqual:(aRecord’s fileURL)) as boolean) then
        set isAdd to true
        
exit repeat
      end if
    end repeat
    
    
#なければ追加
    
if not isAdd then
      set anObj to {fileURL:appURL}
      (
my insertObject:anObj atArrangedObjectIndex:aIndex)
    end if
    
return isAdd
  end addItem:
end script

#MARK: – NSTableCellView
script YKZTableCellView
  property parent : class "NSTableCellView"
  
  
on initWithFrame:rect
    –log "initWithFrame"
    
continue initWithFrame:rect
    
    
setAutoresizingMask_(current application’s NSViewWidthSizable)
    
    
tell current application’s NSImageView’s alloc
      tell initWithFrame_(current application’s NSMakeRect(0, 0, 16, 16))
        setImageScaling_(current application’s NSImageScaleProportionallyUpOrDown)
        
setImageAlignment_(current application’s NSImageAlignCenter)
        
        
my setImageView:it
        
my addSubview:it
      end tell
    end tell
    
    
tell current application’s NSTextField’s alloc
      tell initWithFrame_(current application’s NSMakeRect(20, 2, 200, 14))
        setBordered_(false)
        
setDrawsBackground_(false)
        
setEditable_(false)
        
        
my setTextField:it
        
my addSubview:it
      end tell
    end tell
    
    
return me
  end initWithFrame:
end script

★Click Here to Open This Script 

Posted in dialog GUI | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSArrayController NSBundle NSCreatesSortDescriptorBindingOption NSDictionary NSNumber NSScrollView NSTableCellView NSTableView NSURL NSValueBinding NSValueTransformer | Leave a comment

Numbersで各シート名称を置換

Posted on 1月 15, 2020 by Takaaki Naganoya

Numbersでオープン中の最前面の書類中にあるすべてのシートの名前を置換するAppleScriptです。

内容は簡単ですが、Numbersにそうした機能が存在しないので、作っておくと便利です。アーカイブ本を作るのに、こうした(↓)資料を作る必要があるわけですが、そのためにこうしたこまごまとしたScriptをその場で作って作業の効率化を図っています。


▲上の画像あくまでは処理イメージなので、厳密に同一データの処理前・処理後の画面スナップショットではありません。各シートの名称の一部の文字列(YYYY部分)のみ置換されていることをご確認ください

AppleScript名:Numbersで各シート名称を置換
tell application "Numbers"
  tell front document
    set tList to every sheet
    
repeat with i in tList
      tell i
        set aName to name
        
set bName to replaceText(aName, "2011_", "2013_") of me
        
set name to bName
      end tell
    end repeat
  end tell
end tell

–任意のデータから特定の文字列を置換
on replaceText(origData, origText, repText)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {origText}
  
set origData to text items of origData
  
set AppleScript’s text item delimiters to {repText}
  
set origData to origData as text
  
set AppleScript’s text item delimiters to curDelim
  
return origData
end replaceText

★Click Here to Open This Script 

Posted in Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

Post navigation

  • Older posts
  • Newer posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • Numbersで選択範囲のセルの前後の空白を削除
  • macOS 15でも変化したText to Speech環境
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • Script Debuggerの開発と販売が2025年に終了
  • 【続報】macOS 15.5で特定ファイル名パターンのfileをaliasにcastすると100%クラッシュするバグ
  • macOS 26, Tahoe
  • KagiのWebブラウザ、Orion
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • AppleScript入門① AppleScriptってなんだろう?
  • macOS 15 リモートApple Eventsにバグ?
  • NSObjectのクラス名を取得 v2.1
  • macOS 15:スクリプトエディタのAppleScript用語辞書を確認できない
  • 2024年に書いた価値あるAppleScript
  • 有害ではなくなっていたSpaces
  • Pixelmator Proがv3.6.8でHDR画像をサポート
  • Xcode上のAppleScriptObjCのプログラムから、Xcodeのログ欄へのメッセージ出力を実行
  • (確認中)AppleScript Dropletのバグっぽい動作が解消?
  • AVSpeechSynthesizerで読み上げテスト
  • AppleScript Dropletのバグっぽい動作が「復活」(macOS 15.5β)
  • 指定フォルダ以下の画像のMD5チェックサムを求めて、重複しているものをピックアップ

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (201) 14.0savvy (156) 15.0savvy (145) CotEditor (66) Finder (52) Keynote (119) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (76) Pages (55) Pixelmator Pro (20) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • date
  • dialog
  • diff
  • drive
  • Droplet
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • process
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • Scripting Additions
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2025年9月
  • 2025年8月
  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC