はじめに
前回『〔Mac〕 ShiftItのメニューをビジュアル化する』にて、ShiftItのメニューにアイコンを付加してビジュアル化する方法を記事にしました。
今回は、さらに踏み込んで、独自の配置パターンを追加する方法の記事です。
追加する配置パターン
$今回は、左\frac{2}{3} と 右\frac{2}{3}$の配置パターンを追加します。具体的には、次の6パターン。(配置パターンの例として説明します。何個でもどんな配置パターンでも追加できます)
さすがに、プロパティ設定だけでは実現できず、ソースコードに手を入れることになります。合計6(7)ファイルに変更を加えますので、順を追って説明します。
-
- MeinMenu.xib
-
- DefaultShiftItActions.m
-
- DefaultShiftItActions.h
-
- ShiftItAppDelegate.m
-
- PreferencesWindowController.m
-
- ShiftIt-defaults.plist
-
- Localizable.strings(メニューを日本語化する場合のみ必要)
コードはObjective-Cで書かれていますが、言語知識はそれほどなくても十分対応可能だと思います。
1) メニュー項目の追加
最初はメニュー項目の追加です。
MeinMenu.xib
を開き、上記の6つの配置パターンのMenuItem
を追加します。追加したイメージは下図の通り。
メニュー項目の並びのどこに追加しても構いませんが、追加したMenuItemのtag
に2026以降の数値を設定する必要があります(元々のMenuItemが2001〜2025まで使用している)。
2) 配置関数の追加
メニュー項目のクリックもしくはショートカットキーにより呼び出される、ウィンドウ配置関数(処理コード)を追加します。
DefaultShiftItActions.m
を開き、340行目辺りに以下のコードを追加します。
const SimpleWindowGeometryChangeBlock shiftItTwoThirdsTopLeft = ^AnchoredRect(NSRect windowRect, NSSize screenSize) {
NSRect r = NSMakeRect(0, 0, 0, 0);
r.origin.x = 0;
r.origin.y = 0;
r.size.width = (screenSize.width / 3) * 2;
r.size.height = screenSize.height / 2;
return MakeAnchoredRect(r, kTopDirection | kLeftDirection);
};
const SimpleWindowGeometryChangeBlock shiftItTwoThirdsBottomLeft = ^AnchoredRect(NSRect windowRect, NSSize screenSize) {
NSRect r = NSMakeRect(0, 0, 0, 0);
r.origin.x = 0;
r.origin.y = screenSize.height / 2;
r.size.width = (screenSize.width / 3) * 2;
r.size.height = screenSize.height / 2;
return MakeAnchoredRect(r, kBottomDirection | kLeftDirection);
};
const SimpleWindowGeometryChangeBlock shiftItTwoThirdsTopRight = ^AnchoredRect(NSRect windowRect, NSSize screenSize) {
NSRect r = NSMakeRect(0, 0, 0, 0);
r.origin.x = screenSize.width - ((screenSize.width / 3) * 2);
r.origin.y = 0;
r.size.width = (screenSize.width / 3) * 2;
r.size.height = screenSize.height / 2;
return MakeAnchoredRect(r, kTopDirection);
};
const SimpleWindowGeometryChangeBlock shiftItTwoThirdBottomRight = ^AnchoredRect(NSRect windowRect, NSSize screenSize) {
NSRect r = NSMakeRect(0, 0, 0, 0);
r.origin.x = screenSize.width - ((screenSize.width / 3) * 2);
r.origin.y = screenSize.height / 2;
r.size.width = (screenSize.width / 3) * 2;
r.size.height = screenSize.height / 2;
return MakeAnchoredRect(r, kBottomDirection);
};
const SimpleWindowGeometryChangeBlock shiftItTwoThirdsLeft = ^AnchoredRect(NSRect windowRect, NSSize screenSize) {
NSRect r = NSMakeRect(0, 0, 0, 0);
r.origin.x = 0;
r.origin.y = 0;
r.size.width = (screenSize.width / 3) * 2;
r.size.height = screenSize.height;
return MakeAnchoredRect(r, kLeftDirection);
};
const SimpleWindowGeometryChangeBlock shiftItTwoThirdsRight = ^AnchoredRect(NSRect windowRect, NSSize screenSize) {
NSRect r = NSMakeRect(0, 0, 0, 0);
r.origin.x = screenSize.width - ((screenSize.width / 3) * 2);
r.origin.y = 0;
r.size.width = (screenSize.width / 3) * 2;
r.size.height = screenSize.height;
return MakeAnchoredRect(r, kTopDirection);
};
ここは、SimpleWindowGeometryChangeBlock型
関数の引数windowRect
とscreenSize
が重要で、windowRect
が配置されるウィンドウの矩形NSRect型
、screenSize
はそのウィンドウがあるスクリーン(ディスプレイ)のサイズNSSize型
が渡されます。これを入力として、目的とする配置になるように計算して、新しい矩形を返すコードを書くことです。
具体的に、メニュー項目(Left Two Thirds Top
)の場合を例にすると、
左上の赤い矩形の位置になるので、NSRect r
は、以下の通りとなります。
- r.origin.x = 0 //左上
- r.origin.y = 0 //左上
- r.size.width = (screenSize.width / 3) * 2 //スクリーンの横幅の3分の2
- r.size.height = screenSize.height / 2 //スクリーンの高さの2分の1
このように何分割にでも可能ですし、また、絶対座標・絶対サイズとすることも可能です。お好みの配置パターンを設定すればよいのです。
**座標系ですが、macOS標準のスクリーン左下が(0, 0)ではなく、左上が(0, 0)としてインタフェースされます。**個人的にもこの方が扱い易いです。
3) 配置関数のextern宣言
上記で追加した配置関数のextern宣言を追加します。
DefaultShiftItActions.h
を開き、46行目辺りに以下のコードを追加します。
const extern SimpleWindowGeometryChangeBlock shiftItTwoThirdsTopLeft;
const extern SimpleWindowGeometryChangeBlock shiftItTwoThirdsBottomLeft;
const extern SimpleWindowGeometryChangeBlock shiftItTwoThirdsTopRight;
const extern SimpleWindowGeometryChangeBlock shiftItTwoThirdBottomRight;
const extern SimpleWindowGeometryChangeBlock shiftItTwoThirdsLeft;
const extern SimpleWindowGeometryChangeBlock shiftItTwoThirdsRight;
4) メニューから呼び出されるアクションの登録
メニュー項目のクリックもしくはショートカットキーにより呼び出されるアクションを登録します。
ShiftItAppDelegate.m
を開き、604行目辺りに以下のコードを追加します。
REGISTER_ACTION(dict, @"l2tt", NSLocalizedString(@"Left Two Thirds Top", nil), 26, [[[WindowGeometryShiftItAction alloc] initWithBlock:shiftItTwoThirdsTopLeft] autorelease]);
REGISTER_ACTION(dict, @"l2tb", NSLocalizedString(@"Left Two Thirds Bottom", nil), 27, [[[WindowGeometryShiftItAction alloc] initWithBlock:shiftItTwoThirdsBottomLeft] autorelease]);
REGISTER_ACTION(dict, @"r2tt", NSLocalizedString(@"Right Two Thirds Top", nil), 28, [[[WindowGeometryShiftItAction alloc] initWithBlock:shiftItTwoThirdsTopRight] autorelease]);
REGISTER_ACTION(dict, @"r2tb", NSLocalizedString(@"Right Two Thirds Bottom", nil), 29, [[[WindowGeometryShiftItAction alloc] initWithBlock:shiftItTwoThirdBottomRight] autorelease]);
REGISTER_ACTION(dict, @"l2t", NSLocalizedString(@"Left Two Thirds", nil), 30, [[[WindowGeometryShiftItAction alloc] initWithBlock:shiftItTwoThirdsLeft] autorelease]);
REGISTER_ACTION(dict, @"r2t", NSLocalizedString(@"Right Two Thirds", nil), 31, [[[WindowGeometryShiftItAction alloc] initWithBlock:shiftItTwoThirdsRight] autorelease]);
指定する内容で重要なのは赤字の4箇所で、以下の通りです。
REGISTER_ACTION(dict, @"VVV", NSLocalizedString(@"XXX", nil), YYY, [[[WindowGeometryShiftItAction alloc] initWithBlock:ZZZ] autorelease]);
- VVV:識別子(他と被らなければ何でもよい)
- XXX:メニュー項目に表示するローカライズ文字列
- YYY:MenuItemの追加で指定したtagから2000を引いた数値
- ZZZ:『3) 配置関数のextern宣言』で追加した配置関数名
を指定します。
5) ショートカットキーの指定
次にShiftItの環境設定画面のショートカットキー
タブの表示に関するhotkeyIdentifiers配列
に追加します。
PreferencesWindowController.m
を開き、200行目辺りに以下のコードを追加します。(hotkeyIdentifiers配列の途中に追加するので、diff形式で示します。)
static NSString *hotkeyIdentifiers[] = {
@"left",
@"right",
@"top",
@"bottom",
NULL,
@"tl",
@"tr",
@"bl",
@"br",
NULL,
@"ltt",
@"ltb",
@"ctt",
@"ctb",
@"rtt",
@"rtb",
NULL,
+ @"l2tt",
+ @"l2tb",
+ @"r2tt",
+ @"r2tb",
+ NULL,
@"lt",
@"ct",
@"rt",
NULL,
+ @"l2t",
+ @"r2t",
+ NULL,
@"center",
@"zoom",
@"maximize",
@"fullScreen",
NULL,
@"increase",
@"reduce",
NULL,
@"nextscreen",
@"previousscreen"
};
重要なのは、『1) メニュー項目の追加』で追加したメニュー項目の並びと区切り線も含め一致させること、および、『4) メニューから呼び出されるアクションの登録』で追加したアクション登録文の『VVV:識別子』と一致させることです。
6) ショートカットキーのデフォルト値を追加
次にショートカットキーのデフォルト値を追加します。環境設定画面のショートカットキー
タブにも表示されます(MenuItemで指定したキーバインド(KeyEquivalent)は、この設定値に置き換わります)。
ShiftIt-defaults.plist
を開き、153行目辺りに以下のコード(XML)を追加します。
<key>l2ttKeyCode</key>
<integer>16</integer>
<key>l2ttModifiers</key>
<integer>1835008</integer>
<key>l2tbKeyCode</key>
<integer>4</integer>
<key>l2tbModifiers</key>
<integer>1835008</integer>
<key>r2ttKeyCode</key>
<integer>35</integer>
<key>r2ttModifiers</key>
<integer>1835008</integer>
<key>r2tbKeyCode</key>
<integer>41</integer>
<key>r2tbModifiers</key>
<integer>1835008</integer>
<key>l2tKeyCode</key>
<integer>0</integer>
<key>l2tModifiers</key>
<integer>1835008</integer>
<key>r2tKeyCode</key>
<integer>2</integer>
<key>r2tModifiers</key>
<integer>1835008</integer>
これは、一つのメニュー項目に対し、2組のキーバリューペアを指定します。下記のように、1組目がショートカットキーに指定する修飾キー、2組目がキーコードです。
<key>VVVModifiers</key> <integer>MMM</integer>
<key>VVVKeyCode</key> <integer>KKK</integer>
指定する内容で重要なのは赤字の4箇所で、以下の通り指定します。
- VVV:『4) メニューから呼び出されるアクションの登録』で指定した『VVV:識別子』
- MMM:ショートカットキーに使用する修飾キー(NSEventModifierFlags型の値)
- KKK:ショートカットキーに使用するキーコード値(cf.CGKeyCode(US配列))
ちなみに、修飾キー:1835008(=0x1C0000)とキーコード:0で、⌃⌥⌘A
(control+option+command+A)を意味します。
修飾キーとキーコードは10進数で指定します。
7) メニューの日本語化(任意)
最後に、メニュー項目を日本語化したい場合は、ローカライズ文字列を追加します。
Localizable.strings(Japanese)
を開き、メニュー項目Title
に対応する日本語文字列を追加します。
"Left Two Thirds Top" = "左上3分の2";
"Left Two Thirds Bottom" = "左下3分の2";
"Right Two Thirds Top" = "右上3分の2";
"Right Two Thirds Bottom" = "右下3分の2";
"Left Two Thirds" = "左3分の2";
"Right Two Thirds" = "右3分の2";
左側のキーワードは、『4) メニューから呼び出されるアクションの登録』で指定した、『XXX:ローカライズ文字列』と一致させる必要があります。
メニュー項目を日本語化しないなら、このファイルの変更は不要です。
以上で改修作業は終わり。修正ミスがないことを確認したら、ビルドして動作確認します。
おわりに
どうでしょうか?、お好みの配置パターンが無事に追加できたでしょうか?
何かの参考になれば幸いです。
追伸
Xcodeでデバック実行すると、毎回、アクセシビリティ(システム環境設定→セキュリティとプライバシ→アクセシビリティ)の再設定が必要で面倒。
パスは同じなのになんでビルドする毎に再設定が必要なのだろうか? 設定したタイムスタンプと、Appが作成されたタイムスタンプを厳密に比較しているのだろうか?
以上です。