Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

キーバインドを編集可能にする #181

Merged
merged 23 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
66acdaa
キーバインドのプリセットメニューを追加
mtgto Jun 20, 2024
62a7f1e
キーバインドの名称変更画面を途中まで
mtgto Jun 20, 2024
867d8eb
キーバインドの名称変更画面の続き
mtgto Jun 22, 2024
21457fb
キーバインドのキー入力の変更画面を追加
mtgto Jun 23, 2024
9e8dd8a
キーバインドのキー入力の状態用のクラスを追加
mtgto Jun 23, 2024
b205413
キーバインドのキー入力のテキストフィールド用のビューを追加
mtgto Jun 30, 2024
6a51d0a
特殊キーに名前をつける
mtgto Jun 30, 2024
f641316
キーバインドの修飾キーのToggleは選択してなくても表示する
mtgto Jul 2, 2024
8a8ce9d
キーバインドの編集画面を閉じるときにViewModelに保存する
mtgto Jul 2, 2024
6b7bd6c
KeyBinding.InputのコンストラクタからdisplayStringが不要になったので削除
mtgto Jul 5, 2024
a3cacb7
キーバインド設定を変更したときに永続化する
mtgto Jul 7, 2024
87e06a5
キーバインドに登録するのがシフトキーを必要とする記号の場合に対応
mtgto Jul 7, 2024
0b7f1d9
Merge branch 'main' into customize-keybinding
mtgto Jul 10, 2024
7ed84e0
Merge branch 'main' into customize-keybinding
mtgto Jul 12, 2024
94a0b1d
修飾キーと文字の間の空白を止めた
mtgto Jul 12, 2024
d8f58ad
キーバインドセットの編集をポップアップボタンに入れる
mtgto Jul 12, 2024
c7b18ed
Merge branch 'main' into customize-keybinding
mtgto Jul 15, 2024
6c60214
キー入力を一つももたないアクションを許容する
mtgto Jul 15, 2024
713ca7b
同一アクションで同じキー入力を重複して登録しようとしたら登録を取り消す
mtgto Jul 15, 2024
2836096
キーバインドセットでテーブルのダブルクリックで編集画面を開く
mtgto Jul 15, 2024
06978b3
キーバインド設定の名前設定画面の見出しの修正
mtgto Jul 15, 2024
dc9b7c9
キーバインドを右クリックから編集できるようにする
mtgto Jul 17, 2024
d12871a
デフォルトのキーバインドは更新しようとしてもViewModel側でも弾くようにする
mtgto Jul 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion macSKK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
CE496C952B440BBD001C623C /* Data+EucJis2004Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE496C942B440BBD001C623C /* Data+EucJis2004Tests.swift */; };
CE496C982B440CDA001C623C /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CE496C972B440CCA001C623C /* libiconv.tbd */; };
CE49A2782C19E07800D53CFE /* KeyBindingSetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE49A2772C19E07800D53CFE /* KeyBindingSetTests.swift */; };
CE49A27A2C245F6400D53CFE /* KeyBindingSetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE49A2792C245F6400D53CFE /* KeyBindingSetView.swift */; };
CE49A27C2C26F61700D53CFE /* KeyBindingInputsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE49A27B2C26F61700D53CFE /* KeyBindingInputsView.swift */; };
CE4CB5CC2AD557D90046FA34 /* NumberEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE4CB5CB2AD557D90046FA34 /* NumberEntry.swift */; };
CE4CB5CE2AD55DF90046FA34 /* NumberEntryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE4CB5CD2AD55DF90046FA34 /* NumberEntryTests.swift */; };
CE5EB6AD2AAC0DE000389B98 /* FileDict.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5EB6AC2AAC0DE000389B98 /* FileDict.swift */; };
Expand Down Expand Up @@ -191,6 +193,8 @@
CE496C942B440BBD001C623C /* Data+EucJis2004Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+EucJis2004Tests.swift"; sourceTree = "<group>"; };
CE496C972B440CCA001C623C /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
CE49A2772C19E07800D53CFE /* KeyBindingSetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBindingSetTests.swift; sourceTree = "<group>"; };
CE49A2792C245F6400D53CFE /* KeyBindingSetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBindingSetView.swift; sourceTree = "<group>"; };
CE49A27B2C26F61700D53CFE /* KeyBindingInputsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBindingInputsView.swift; sourceTree = "<group>"; };
CE4CB5CB2AD557D90046FA34 /* NumberEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberEntry.swift; sourceTree = "<group>"; };
CE4CB5CD2AD55DF90046FA34 /* NumberEntryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberEntryTests.swift; sourceTree = "<group>"; };
CE5EB6AC2AAC0DE000389B98 /* FileDict.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDict.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -309,6 +313,16 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
CE00FCCD2C30E99300AC6EEB /* KeyBinding */ = {
isa = PBXGroup;
children = (
CE11C7BC2BE47D5D00A35F3D /* KeyBindingView.swift */,
CE49A2792C245F6400D53CFE /* KeyBindingSetView.swift */,
CE49A27B2C26F61700D53CFE /* KeyBindingInputsView.swift */,
);
path = KeyBinding;
sourceTree = "<group>";
};
CE1B00602BA4285A00C830FD /* Network */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -477,7 +491,7 @@
CE496C8B2B43968A001C623C /* LogView.swift */,
CEC376EA2965211200D9C432 /* KeyEventView.swift */,
CE40D9A02A6D0C2F00D44799 /* SystemDictView.swift */,
CE11C7BC2BE47D5D00A35F3D /* KeyBindingView.swift */,
CE00FCCD2C30E99300AC6EEB /* KeyBinding */,
CE2157652B2EA985006E4C41 /* UserDefaultsKeys.swift */,
);
path = Settings;
Expand Down Expand Up @@ -773,8 +787,10 @@
CEE3717529653112000DB2C3 /* SoftwareUpdateView.swift in Sources */,
CE496C912B440892001C623C /* URL+Additions.swift in Sources */,
CE11C7BD2BE47D5D00A35F3D /* KeyBindingView.swift in Sources */,
CE49A27A2C245F6400D53CFE /* KeyBindingSetView.swift in Sources */,
CE39DB212A8DFD8F00BC619F /* MarkedText.swift in Sources */,
CE40D9A32A6D0C3900D44799 /* SystemDict.swift in Sources */,
CE49A27C2C26F61700D53CFE /* KeyBindingInputsView.swift in Sources */,
CE5EB6AD2AAC0DE000389B98 /* FileDict.swift in Sources */,
CEB0888E2A7F393600EFD1E3 /* AnnotationView.swift in Sources */,
CEC376E82965199500D9C432 /* SettingsView.swift in Sources */,
Expand Down
186 changes: 133 additions & 53 deletions macSKK/KeyBinding.swift

Large diffs are not rendered by default.

78 changes: 75 additions & 3 deletions macSKK/KeyBindingSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,29 @@

import AppKit

struct KeyBindingSet {
struct KeyBindingSet: Identifiable, Hashable {
/// 設定の名称。
let id: String
static let defaultId: ID = "macSKK"
static let serializeVersion: Int = 1
/**
* 修飾キーを除いたキー入力が同じ場合は修飾キーが多いものが前に来るように並べた配列。
* 入力に一番合致するキー入力を返すために最初にソートしてもっておく。
*/
let sorted: [(KeyBinding.Input, KeyBinding.Action)]

static let defaultKeyBindingSet = KeyBindingSet(KeyBinding.defaultKeyBindingSettings)
// KeyBinding.Actionの順に並べたキーバインディングの配列
var values: [KeyBinding] {
let dict = Dictionary(grouping: sorted, by: { $0.1 }).mapValues { $0.map { $0.0 } }
return KeyBinding.Action.allCases.map { action in
KeyBinding(action, dict[action] ?? [])
}
}

static let defaultKeyBindingSet = KeyBindingSet(id: Self.defaultId, values: KeyBinding.defaultKeyBindingSettings)

init(_ values: [KeyBinding]) {
init(id: String, values: [KeyBinding]) {
self.id = id
sorted = values.flatMap { keyValue in
keyValue.inputs.map { ($0, keyValue.action) }
}.sorted(by: { lts, rts in
Expand All @@ -34,7 +47,66 @@ struct KeyBindingSet {
})
}

// UserDefaultsからのデコード用
init?(dict: [String: Any]) {
guard let id = dict["id"] as? String, let keyBindings = dict["keyBindings"] as? [[String: Any]], let version = dict["version"] as? Int else {
return nil
}
if version != Self.serializeVersion {
logger.error("シリアライズバージョンが合わないためキーバインド \(id, privacy: .public) が読み込めません。(現在: \(Self.serializeVersion), 環境設定: \(version)")
return nil
}
var values: [KeyBinding] = []
for dict in keyBindings {
guard let keyBinding = KeyBinding(dict: dict) else {
logger.warning("キーバインド \(id, privacy: .public) の読み込みに失敗しました")
return nil
}
values.append(keyBinding)
}
self.init(id: id, values: values)
}

// UserDefaultsへのエンコード用
func encode() -> [String: Any] {
["id": id, "version": Self.serializeVersion, "keyBindings": values.map { $0.encode() }]
}

private init(id: String, sorted: [(KeyBinding.Input, KeyBinding.Action)]) {
self.id = id
self.sorted = sorted
}

/// 現在のキーバインドに割り当てられているアクションを返す。
/// 入力はIMKInputController#handleの引数のNSEventなので、charactersIgnoreingModifiersがシフトキーの影響を受けない。
func action(event: NSEvent) -> KeyBinding.Action? {
sorted.first(where: { $0.0.accepts(event: event) })?.1
}

var canDelete: Bool {
id != Self.defaultId
}

var canEdit: Bool {
id != Self.defaultId
}

func copy(id: String) -> Self {
return Self(id: id, sorted: sorted)
}

// 指定したactionにひもづく入力をinputsに置き換えて返す
func update(for action: KeyBinding.Action, inputs: [KeyBinding.Input]) -> Self {
let keyBindings = values.filter { $0.action != action }
return KeyBindingSet(id: id, values: keyBindings + [KeyBinding(action, inputs)])
}

// MARK: Hashable
static func == (lhs: KeyBindingSet, rhs: KeyBindingSet) -> Bool {
return lhs.id == rhs.id
}

func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
Loading
Loading