├── LICENSE ├── README.md ├── Stapler-mini-v0.app └── Contents │ ├── Info.plist │ ├── MacOS │ └── Stapler-mini-v0 │ ├── PkgInfo │ ├── Resources │ ├── AppIcon.icns │ ├── Assets.car │ ├── Success1.wav │ ├── Success2.wav │ ├── en.lproj │ │ └── Localizable.strings │ └── ja.lproj │ │ └── Localizable.strings │ └── _CodeSignature │ └── CodeResources ├── Stapler-mini-v0 ├── Stapler-mini-v0.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── qdpb.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── qdpb.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── Stapler-mini-v0 │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon_v0_128x128@1x.png │ │ ├── Icon_v0_128x128@2x.png │ │ ├── Icon_v0_16x16@1x.png │ │ ├── Icon_v0_16x16@2x.png │ │ ├── Icon_v0_256x256@1x.png │ │ ├── Icon_v0_256x256@2x.png │ │ ├── Icon_v0_32x32@1x.png │ │ ├── Icon_v0_32x32@2x.png │ │ ├── Icon_v0_512x512@1x.png │ │ └── Icon_v0_512x512@2x.png │ ├── Contents.json │ └── exportFileIcon.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ └── icon_512x512.png │ ├── ContentView.swift │ ├── Info.plist │ ├── Keyboard │ ├── AddPresetSheetView.swift │ ├── CustomizeKey │ │ ├── CustomKeyCategory.swift │ │ ├── CustomizeKeyTabView.swift │ │ └── CustomizeKeyView_1u.swift │ ├── EnterCustomShapeView.swift │ ├── ExportKeyboardView │ │ ├── CustomUTType.swift │ │ ├── ExportSheetView.swift │ │ ├── KeyboardView_AllLayer.swift │ │ ├── KeyboardView_EachLayer.swift │ │ ├── Success1.wav │ │ └── Success2.wav │ ├── KeyboardKeyView.swift │ ├── KeyboardView.swift │ ├── PresetView.swift │ └── SelectedDetailView.swift │ ├── Model&KeyCodeList │ ├── JSONExporter.swift │ ├── KeyCodeList.swift │ └── Preset.swift │ ├── PresetLabelView.swift │ ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json │ ├── Stapler-mini-v0App.swift │ ├── Stapler_mini_v0.entitlements │ ├── en.lproj │ └── Localizable.strings │ └── ja.lproj │ └── Localizable.strings └── 大西配列ANSI.stapler /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 9dpbQ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stapler-mini 2 | ![Icon_v0](https://github.com/user-attachments/assets/bc777a42-1dfd-4523-a1f5-65d78c96cdea) 3 | 4 | ## どんなアプリ? 5 | **Stapler-mini**は[Karabiner-Elements](https://karabiner-elements.pqrs.org/)で使えるjsonファイルを出力するmacOSアプリケーションです。 6 | いわゆる自作キーボードにおける、レイヤー機能・タップホールド機能を、ドラッグ&ドロップで直感的にカスタマイズすることができます。 7 | 8 | ### レイヤー機能って? 9 | レイヤー機能とはあるキーを押しながら他のキー(例えばAとか)を押した時、他のレイヤーで設定しておいたキー(例えばスクショ⌘⇧3)を出力できるようになるような機能です。シフトキーを押しながら数字キーを押した時には数字ではなく記号が入力されますが、その入力される文字を自分で決められるというイメージです。 10 | stapler-mini-v0では8枚のレイヤーを設定することができます。 11 | 12 | ### タップホールド機能って? 13 | タップホールド機能とはキーを単打したときと長押ししたときで入力される文字を打ち分ける機能です。 14 | 例えばシフトキーやその他の修飾キーは単打をしてもキーのDownUpのみが入力されて実用上では全く意味のない入力ですが、そこに好きなショートカットを入れたりすることが可能なわけです。 15 | 反対にescapeやエンターは単打のような使い方しかしないキーなので、それらの長押しに好きな修飾キーのコンビネーションを入れたりもできます。 16 | 17 | ## 使い方 18 | 19 | ### 0.Karabiner-Elementsをダウンロードしておく 20 | [Karabiner-Elements](https://karabiner-elements.pqrs.org/)からダウンロードして、立ち上げて案内の通りに権限を与えます。SimpleModificationで試しに何か書き換えられたら準備完了です。 21 | 22 | ### 1.本アプリをダウンロードする 23 | ss 2024-10-29 22 31 49 24 | ss 2024-10-28 2 55 34 25 | 26 | ### 2.アプリを立ち上げたらPresetを追加する 27 | とりあえず公開版ではMacBookの本体キーボードのレイアウト3種類(US ,UK, JIS)から選ぶことができます。 28 | 最初に入っているVendorIDとProductIDは僕の環境でのMacBookの本体キーボードのIDなので、型番や環境によっては異なる場合があります。Karabiner-Elements側でIDを確認してその値を入力することでそのデバイスの書き換え用のファイルが出力できるようになります。もしくは書き出しした後に一括で編集してください。 29 | 30 | 注意:環境によっては本体キーボードのVendorIDやProductIDがkarabiner側やシステム情報にも表示されないことがあるようです。その場合はLocationIDで条件付け(デバイスの固定値ではないけど本体キーボードなら多分変わらない)でうまくいっているようですが、何か詳しいことがわかる人がいたらDiscordサーバーで知恵を貸してください! 31 | ``` 32 | "conditions": [ 33 | { 34 | "type": "device_if", 35 | "identifiers": [ 36 | { 37 | "is_built_in_keyboard": true 38 | } 39 | ] 40 | } 41 | ] 42 | ``` 43 | 本体キーボード限定の書き換えならこっちの方が良いかも。 44 | 45 | 46 | ### 3.キーをドラッグ&ドロップして好きなようにカスタマイズする 47 | 基本は下側のカスタマイズキーを上部のキーボードビューの任意のキーにドラッグ&ドロップしてカスタマイズを行います。 48 | ss 2024-10-27 20 33 15 49 | 50 | また外部キーボードはVendorIDとProductIDをテキストフィールドに入力することでカスタマイズが可能です。 51 | 本体キーボードともともとのキーコードが一部異なるキーボードを使っている場合、そのキーの書き換えはそのままだとうまくいきません(JISだったらControl↔️Caps Lockとかよくあるパターン)。UserCustomJSONから"from"のキーコードを変更することで一応はカスタマイズが可能です。 52 | 53 | 割り当てたキーのリセットは右クリックから行えます。 54 | 55 | ss 2024-10-30 14 52 39 56 | 57 | 58 | 59 | #### タップホールドをカスタムする 60 | 右側のサイドバーか、キーを**ダブルクリック**してポップアップから、**EnableTapHold**をトグルします。TapとHold二つのキーに対してドラッグ&ドロップをしてカスタムできます。 61 | この時タップホールドを有効にしたのにどちらかが空の状態のままだとjsonファイル出力時にエラーが発生するので注意してください。 62 | 63 | ##### タップホールドのタイプについて 64 | とりあえず公開版には3種類のタップホールドタイプがあります。 65 | 66 | ###### Basic 67 | 一定時間以上押下するとホールドの入力になり、それより早く他のキーが押されたり、キーを解放すると単打が入力される方式のベーシックなタップホールドです。 68 | アルファベットのホーム行に修飾キーホールドを入れたい場合や、閾値を長めに取って誤動作をしないようにしたい場合などに有効です。 69 | 70 | 71 | ⚠️注意⚠️現在BasicタイプにLayer遷移キーを入れたときレイヤーから戻らない不具合を確認しています。 72 | ``` 73 | "to_if_held_down": [{"halt":true, "set_variable": {"name": "layer1","value": 1}}] 74 | ``` 75 | 問題があるのは```"to_if_held_down"```内の```"halt":true```です。ここを消せば問題なく動くはずです。 76 | もしくはUserCustomJSONをトグルした時にはこの不具合は出てないのでタップ・ホールドにキーを入れてトグルするのが楽です。何かわからないことがあれば[Discordサーバー](https://discord.gg/yVhZfsE2zS)で気軽に質問してください! 77 | 78 | ###### Chord 79 | ピアノでの和音のように他のキーと組み合わせた場合にだけホールドのキーが出力されるタイプです。 80 | 閾値を持たず組み合わせの時のみホールドの出力をするのでレイヤーや修飾キーを早い指遣いで使用することができます。レイヤー遷移キーや、よく使うような修飾キーをホールドに入れる場合にこのタイプを使うことを推奨します。 81 | 82 | ###### Repeat 83 | 基本的にはChordと同じ機能ですが、 84 | 「**・ー**」のように一度タップをした後に長押しするとタップキーの長押しになる性質を持っているタイプです。 85 | BackSpaceやDeleteForwardなど、実用上長押しもするキーをタップに入れるときに推奨されるタイプです。 86 | 87 | ※仕組み上、偶数打目のホールドがタップの長押しになる 88 | 89 | #### レイヤーをカスタムする 90 | Specialタブにある色付き数字キーがレイヤー遷移キーです。これをドロップしたキーが押されている間レイヤーのキーを出力するようになります。 91 | 92 | 93 | image 94 | 95 | 96 | 例えばこのようにすれば**かな**のタップで **かな**、**かな**のホールドで**レイヤー3**に遷移します。 97 | 98 | image 99 | 100 | 遷移キーを設定したらそのレイヤーマップにキーをドラッグ&ドロップしてカスタマイズしましょう。 101 | マウスカーソルの移動や、スクロールなどを行えるレイヤーの例です。 102 | image 103 | 104 | 105 | ### 4.jsonファイルとして出力する 106 | 右上の出力ボタンを押してPresetの概要を眺めてみましょう。壮観だなぁ〜! 107 | 実際にキーボードの書き換えを行えるようにjsonとして書き出しましょう。保存されたファイルがFinderで開いたら成功です。👏 108 | エラーが出た場合はエラーメッセージを見て、どのキーに問題があるのかを確認、タップホールドどちらかが空欄問題ではない場合、スクショを[開発者](https://x.com/9dpbQ)に送りつけて文句を言ってください。 109 | 110 | ### 5.出力したファイルをKarabiner-Elementsで有効化する 111 | #### ⚠️⚠️とりあえず公開版3よりKarabinerのインポート画面が自動で開くようになりました⚠️⚠️ 112 | Karabiner側でインポート、Enable Allとすれば設定が有効化できます。ファイルはファイル名が数列になっていますが以下のパスに複製されています。 113 | ``` 114 | ~/.config/karabiner/assets/complex_modifications 115 | ``` 116 | 117 | #### とりあえず公開版2までは以下を参照 118 | まず出力した時に開いたFinderのウィンドウから、**⌘T**か**⌘N**で新しくタブかウィンドウを開いて**⌘⇧G**で以下のパスを開きます。 119 | ``` 120 | ~/.config/karabiner/assets/complex_modifications 121 | ``` 122 | 出力したjsonファイルをcomplex_modificationsのフォルダ内にドラッグ&ドロップします。 123 | 124 | ドラドロした後はこんな感じ 125 | image 126 | 127 | 128 | Karabiner-Elementsを開いてComplexModificationsタブからAdd predifined rule、Enable Allとすれば設定が有効になっているはずです。メモ帳やEventViewerで確認してみてください。 129 | ドラッグ&ドロップしたのに、設定が見当たらない場合、jsonファイルとして欠陥がある可能性があります。テキストエディタでjsonファイルを開いてエラーがある部分を直せば読み込めるようになるはずです。 130 | 131 | ### 6.最強のプリセットを作り込もう! 132 | レイヤーは8枚あるのでそれなりに余裕を持って自分なりの作業環境を構築できるはずです。 133 | アプリ用のレイヤーを作ったり、数字入力用、記号入力用、カーソル用…と用途別に分けても覚えやすいかもしれません。 134 | 画像出力も可能なので[PureRef](https://www.pureref.com/download.php)と組み合わせて常時画面上に表示するみたいなことも可能です。 135 | また、[開発者が自分の設定を作ってる記事](https://note.com/9dpb/n/nf41952e3e799)もあります。アプリ別なコマンドを設定したり、ちょっと細かいところまで説明してるので参考にしてみてください。 136 | 137 | 最強のプリセットが作れたら[Discordコミュニティ](https://discord.gg/yVhZfsE2zS)やXで自慢しよう!要望とかあれば頑張るかもしれない。 138 | -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 24A348 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDocumentTypes 10 | 11 | 12 | CFBundleTypeIconFile 13 | exportFileIcon 14 | CFBundleTypeIconSystemGenerated 15 | 1 16 | CFBundleTypeName 17 | Stapler 18 | CFBundleTypeRole 19 | Editor 20 | LSHandlerRank 21 | Default 22 | LSItemContentTypes 23 | 24 | com.example.stapler 25 | 26 | NSDocumentClass 27 | NSDocument 28 | 29 | 30 | CFBundleExecutable 31 | Stapler-mini-v0 32 | CFBundleIconFile 33 | AppIcon 34 | CFBundleIconName 35 | AppIcon 36 | CFBundleIdentifier 37 | com.9dpbQ.Stapler-mini-v0 38 | CFBundleInfoDictionaryVersion 39 | 6.0 40 | CFBundleName 41 | Stapler-mini-v0 42 | CFBundlePackageType 43 | APPL 44 | CFBundleShortVersionString 45 | 1.0 46 | CFBundleSupportedPlatforms 47 | 48 | MacOSX 49 | 50 | CFBundleVersion 51 | 1 52 | DTCompiler 53 | com.apple.compilers.llvm.clang.1_0 54 | DTPlatformBuild 55 | 24A336 56 | DTPlatformName 57 | macosx 58 | DTPlatformVersion 59 | 15.0 60 | DTSDKBuild 61 | 24A336 62 | DTSDKName 63 | macosx15.0 64 | DTXcode 65 | 1600 66 | DTXcodeBuild 67 | 16A242d 68 | LSMinimumSystemVersion 69 | 15.0 70 | UTExportedTypeDeclarations 71 | 72 | 73 | UTTypeConformsTo 74 | 75 | public.data 76 | 77 | UTTypeDescription 78 | for drag & drop CustomizeKey 79 | UTTypeIcons 80 | 81 | UTTypeIdentifier 82 | com.example.customizekey 83 | UTTypeTagSpecification 84 | 85 | 86 | 87 | UTTypeConformsTo 88 | 89 | public.data 90 | 91 | UTTypeDescription 92 | for sharing user's Preset 93 | UTTypeIcons 94 | 95 | UTTypeIconBadgeName 96 | exportFileIcon 97 | 98 | UTTypeIdentifier 99 | com.example.stapler 100 | UTTypeTagSpecification 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/MacOS/Stapler-mini-v0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0.app/Contents/MacOS/Stapler-mini-v0 -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/Resources/AppIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0.app/Contents/Resources/AppIcon.icns -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/Resources/Assets.car: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0.app/Contents/Resources/Assets.car -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/Resources/Success1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0.app/Contents/Resources/Success1.wav -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/Resources/Success2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0.app/Contents/Resources/Success2.wav -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0.app/Contents/Resources/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/Resources/ja.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0.app/Contents/Resources/ja.lproj/Localizable.strings -------------------------------------------------------------------------------- /Stapler-mini-v0.app/Contents/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Resources/AppIcon.icns 8 | 9 | g6/BZy7qYMUW9ZgH7fykkXSXjvM= 10 | 11 | Resources/Assets.car 12 | 13 | jQgr7hjOpuuIOUq3EX/n+xdnZOg= 14 | 15 | Resources/Success1.wav 16 | 17 | UHwH1E1d4qhJOxt7MyFU4bvNsxw= 18 | 19 | Resources/Success2.wav 20 | 21 | J3ia/8Ciygovm1CLW2E7ulYNkzs= 22 | 23 | Resources/en.lproj/Localizable.strings 24 | 25 | hash 26 | 27 | MkvCMtMWMLpfSFb0Knk1rtntp1U= 28 | 29 | optional 30 | 31 | 32 | Resources/ja.lproj/Localizable.strings 33 | 34 | hash 35 | 36 | XpQ7hNqZBxZPdum5Pmh+UqwTF8s= 37 | 38 | optional 39 | 40 | 41 | 42 | files2 43 | 44 | Resources/AppIcon.icns 45 | 46 | hash2 47 | 48 | qn1hjb+xjJHTAopDTAj/mxKAYUcCJPUTSLQnmmFz6do= 49 | 50 | 51 | Resources/Assets.car 52 | 53 | hash2 54 | 55 | fL0ZkkeQwm4iC8VdcVEc+6/XzTFSxTVbTWLjGcjq6bw= 56 | 57 | 58 | Resources/Success1.wav 59 | 60 | hash2 61 | 62 | b1MWIb2k/VPPvbYXqW1/t7TEmNCWmSiGYrDCdFYWE6k= 63 | 64 | 65 | Resources/Success2.wav 66 | 67 | hash2 68 | 69 | 8z1HhfESQr8CghaFlxBboax39+Rh3iCp3PfWCO+gawU= 70 | 71 | 72 | Resources/en.lproj/Localizable.strings 73 | 74 | hash2 75 | 76 | csR/uf0stYQfkJbVSBBZp4vjGL+Xa025wjYDvKMOijY= 77 | 78 | optional 79 | 80 | 81 | Resources/ja.lproj/Localizable.strings 82 | 83 | hash2 84 | 85 | 1pOcPVC+EEsaOsSrZyB+RDOtJ6DRJjTWrXZLQPtbFik= 86 | 87 | optional 88 | 89 | 90 | 91 | rules 92 | 93 | ^Resources/ 94 | 95 | ^Resources/.*\.lproj/ 96 | 97 | optional 98 | 99 | weight 100 | 1000 101 | 102 | ^Resources/.*\.lproj/locversion.plist$ 103 | 104 | omit 105 | 106 | weight 107 | 1100 108 | 109 | ^Resources/Base\.lproj/ 110 | 111 | weight 112 | 1010 113 | 114 | ^version.plist$ 115 | 116 | 117 | rules2 118 | 119 | .*\.dSYM($|/) 120 | 121 | weight 122 | 11 123 | 124 | ^(.*/)?\.DS_Store$ 125 | 126 | omit 127 | 128 | weight 129 | 2000 130 | 131 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 132 | 133 | nested 134 | 135 | weight 136 | 10 137 | 138 | ^.* 139 | 140 | ^Info\.plist$ 141 | 142 | omit 143 | 144 | weight 145 | 20 146 | 147 | ^PkgInfo$ 148 | 149 | omit 150 | 151 | weight 152 | 20 153 | 154 | ^Resources/ 155 | 156 | weight 157 | 20 158 | 159 | ^Resources/.*\.lproj/ 160 | 161 | optional 162 | 163 | weight 164 | 1000 165 | 166 | ^Resources/.*\.lproj/locversion.plist$ 167 | 168 | omit 169 | 170 | weight 171 | 1100 172 | 173 | ^Resources/Base\.lproj/ 174 | 175 | weight 176 | 1010 177 | 178 | ^[^/]+$ 179 | 180 | nested 181 | 182 | weight 183 | 10 184 | 185 | ^embedded\.provisionprofile$ 186 | 187 | weight 188 | 20 189 | 190 | ^version\.plist$ 191 | 192 | weight 193 | 20 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 77; 7 | objects = { 8 | 9 | /* Begin PBXFileReference section */ 10 | CC5B388D2CCE3DE200043844 /* Stapler-mini-v0.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Stapler-mini-v0.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 11 | /* End PBXFileReference section */ 12 | 13 | /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ 14 | CC5B38D42CCE3FEE00043844 /* Exceptions for "Stapler-mini-v0" folder in "Stapler-mini-v0" target */ = { 15 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet; 16 | membershipExceptions = ( 17 | Info.plist, 18 | ); 19 | target = CC5B388C2CCE3DE200043844 /* Stapler-mini-v0 */; 20 | }; 21 | /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ 22 | 23 | /* Begin PBXFileSystemSynchronizedRootGroup section */ 24 | CC5B388F2CCE3DE200043844 /* Stapler-mini-v0 */ = { 25 | isa = PBXFileSystemSynchronizedRootGroup; 26 | exceptions = ( 27 | CC5B38D42CCE3FEE00043844 /* Exceptions for "Stapler-mini-v0" folder in "Stapler-mini-v0" target */, 28 | ); 29 | path = "Stapler-mini-v0"; 30 | sourceTree = ""; 31 | }; 32 | /* End PBXFileSystemSynchronizedRootGroup section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | CC5B388A2CCE3DE200043844 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | CC5B38842CCE3DE200043844 = { 46 | isa = PBXGroup; 47 | children = ( 48 | CC5B388F2CCE3DE200043844 /* Stapler-mini-v0 */, 49 | CC5B388E2CCE3DE200043844 /* Products */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | CC5B388E2CCE3DE200043844 /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | CC5B388D2CCE3DE200043844 /* Stapler-mini-v0.app */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | /* End PBXGroup section */ 62 | 63 | /* Begin PBXNativeTarget section */ 64 | CC5B388C2CCE3DE200043844 /* Stapler-mini-v0 */ = { 65 | isa = PBXNativeTarget; 66 | buildConfigurationList = CC5B389C2CCE3DE500043844 /* Build configuration list for PBXNativeTarget "Stapler-mini-v0" */; 67 | buildPhases = ( 68 | CC5B38892CCE3DE200043844 /* Sources */, 69 | CC5B388A2CCE3DE200043844 /* Frameworks */, 70 | CC5B388B2CCE3DE200043844 /* Resources */, 71 | ); 72 | buildRules = ( 73 | ); 74 | dependencies = ( 75 | ); 76 | fileSystemSynchronizedGroups = ( 77 | CC5B388F2CCE3DE200043844 /* Stapler-mini-v0 */, 78 | ); 79 | name = "Stapler-mini-v0"; 80 | packageProductDependencies = ( 81 | ); 82 | productName = "Stapler-mini-v0"; 83 | productReference = CC5B388D2CCE3DE200043844 /* Stapler-mini-v0.app */; 84 | productType = "com.apple.product-type.application"; 85 | }; 86 | /* End PBXNativeTarget section */ 87 | 88 | /* Begin PBXProject section */ 89 | CC5B38852CCE3DE200043844 /* Project object */ = { 90 | isa = PBXProject; 91 | attributes = { 92 | BuildIndependentTargetsInParallel = 1; 93 | LastSwiftUpdateCheck = 1600; 94 | LastUpgradeCheck = 1600; 95 | TargetAttributes = { 96 | CC5B388C2CCE3DE200043844 = { 97 | CreatedOnToolsVersion = 16.0; 98 | }; 99 | }; 100 | }; 101 | buildConfigurationList = CC5B38882CCE3DE200043844 /* Build configuration list for PBXProject "Stapler-mini-v0" */; 102 | developmentRegion = en; 103 | hasScannedForEncodings = 0; 104 | knownRegions = ( 105 | en, 106 | Base, 107 | ja, 108 | ); 109 | mainGroup = CC5B38842CCE3DE200043844; 110 | minimizedProjectReferenceProxies = 1; 111 | preferredProjectObjectVersion = 77; 112 | productRefGroup = CC5B388E2CCE3DE200043844 /* Products */; 113 | projectDirPath = ""; 114 | projectRoot = ""; 115 | targets = ( 116 | CC5B388C2CCE3DE200043844 /* Stapler-mini-v0 */, 117 | ); 118 | }; 119 | /* End PBXProject section */ 120 | 121 | /* Begin PBXResourcesBuildPhase section */ 122 | CC5B388B2CCE3DE200043844 /* Resources */ = { 123 | isa = PBXResourcesBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | /* End PBXResourcesBuildPhase section */ 130 | 131 | /* Begin PBXSourcesBuildPhase section */ 132 | CC5B38892CCE3DE200043844 /* Sources */ = { 133 | isa = PBXSourcesBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | ); 137 | runOnlyForDeploymentPostprocessing = 0; 138 | }; 139 | /* End PBXSourcesBuildPhase section */ 140 | 141 | /* Begin XCBuildConfiguration section */ 142 | CC5B389A2CCE3DE500043844 /* Debug */ = { 143 | isa = XCBuildConfiguration; 144 | buildSettings = { 145 | ALWAYS_SEARCH_USER_PATHS = NO; 146 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 147 | CLANG_ANALYZER_NONNULL = YES; 148 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 149 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 150 | CLANG_ENABLE_MODULES = YES; 151 | CLANG_ENABLE_OBJC_ARC = YES; 152 | CLANG_ENABLE_OBJC_WEAK = YES; 153 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 154 | CLANG_WARN_BOOL_CONVERSION = YES; 155 | CLANG_WARN_COMMA = YES; 156 | CLANG_WARN_CONSTANT_CONVERSION = YES; 157 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 158 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 159 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 160 | CLANG_WARN_EMPTY_BODY = YES; 161 | CLANG_WARN_ENUM_CONVERSION = YES; 162 | CLANG_WARN_INFINITE_RECURSION = YES; 163 | CLANG_WARN_INT_CONVERSION = YES; 164 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 165 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 166 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 167 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 168 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 169 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 170 | CLANG_WARN_STRICT_PROTOTYPES = YES; 171 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 172 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 173 | CLANG_WARN_UNREACHABLE_CODE = YES; 174 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 175 | COPY_PHASE_STRIP = NO; 176 | DEBUG_INFORMATION_FORMAT = dwarf; 177 | ENABLE_STRICT_OBJC_MSGSEND = YES; 178 | ENABLE_TESTABILITY = YES; 179 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 180 | GCC_C_LANGUAGE_STANDARD = gnu17; 181 | GCC_DYNAMIC_NO_PIC = NO; 182 | GCC_NO_COMMON_BLOCKS = YES; 183 | GCC_OPTIMIZATION_LEVEL = 0; 184 | GCC_PREPROCESSOR_DEFINITIONS = ( 185 | "DEBUG=1", 186 | "$(inherited)", 187 | ); 188 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 189 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 190 | GCC_WARN_UNDECLARED_SELECTOR = YES; 191 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 192 | GCC_WARN_UNUSED_FUNCTION = YES; 193 | GCC_WARN_UNUSED_VARIABLE = YES; 194 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 195 | MACOSX_DEPLOYMENT_TARGET = 15.0; 196 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 197 | MTL_FAST_MATH = YES; 198 | ONLY_ACTIVE_ARCH = YES; 199 | SDKROOT = macosx; 200 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 201 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 202 | }; 203 | name = Debug; 204 | }; 205 | CC5B389B2CCE3DE500043844 /* Release */ = { 206 | isa = XCBuildConfiguration; 207 | buildSettings = { 208 | ALWAYS_SEARCH_USER_PATHS = NO; 209 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 210 | CLANG_ANALYZER_NONNULL = YES; 211 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 212 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 213 | CLANG_ENABLE_MODULES = YES; 214 | CLANG_ENABLE_OBJC_ARC = YES; 215 | CLANG_ENABLE_OBJC_WEAK = YES; 216 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 217 | CLANG_WARN_BOOL_CONVERSION = YES; 218 | CLANG_WARN_COMMA = YES; 219 | CLANG_WARN_CONSTANT_CONVERSION = YES; 220 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 221 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 222 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 223 | CLANG_WARN_EMPTY_BODY = YES; 224 | CLANG_WARN_ENUM_CONVERSION = YES; 225 | CLANG_WARN_INFINITE_RECURSION = YES; 226 | CLANG_WARN_INT_CONVERSION = YES; 227 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 228 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 229 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 230 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 231 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 232 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 233 | CLANG_WARN_STRICT_PROTOTYPES = YES; 234 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 235 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 236 | CLANG_WARN_UNREACHABLE_CODE = YES; 237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 238 | COPY_PHASE_STRIP = NO; 239 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 240 | ENABLE_NS_ASSERTIONS = NO; 241 | ENABLE_STRICT_OBJC_MSGSEND = YES; 242 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 243 | GCC_C_LANGUAGE_STANDARD = gnu17; 244 | GCC_NO_COMMON_BLOCKS = YES; 245 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 246 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 247 | GCC_WARN_UNDECLARED_SELECTOR = YES; 248 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 249 | GCC_WARN_UNUSED_FUNCTION = YES; 250 | GCC_WARN_UNUSED_VARIABLE = YES; 251 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 252 | MACOSX_DEPLOYMENT_TARGET = 15.0; 253 | MTL_ENABLE_DEBUG_INFO = NO; 254 | MTL_FAST_MATH = YES; 255 | SDKROOT = macosx; 256 | SWIFT_COMPILATION_MODE = wholemodule; 257 | }; 258 | name = Release; 259 | }; 260 | CC5B389D2CCE3DE500043844 /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | buildSettings = { 263 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 264 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 265 | CODE_SIGN_ENTITLEMENTS = "Stapler-mini-v0/Stapler_mini_v0.entitlements"; 266 | CODE_SIGN_STYLE = Automatic; 267 | COMBINE_HIDPI_IMAGES = YES; 268 | CURRENT_PROJECT_VERSION = 1; 269 | DEVELOPMENT_ASSET_PATHS = "\"Stapler-mini-v0/Preview Content\""; 270 | DEVELOPMENT_TEAM = TBSVB6XDJZ; 271 | ENABLE_HARDENED_RUNTIME = YES; 272 | ENABLE_PREVIEWS = YES; 273 | GENERATE_INFOPLIST_FILE = YES; 274 | INFOPLIST_FILE = "Stapler-mini-v0/Info.plist"; 275 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 276 | LD_RUNPATH_SEARCH_PATHS = ( 277 | "$(inherited)", 278 | "@executable_path/../Frameworks", 279 | ); 280 | MARKETING_VERSION = 1.0; 281 | PRODUCT_BUNDLE_IDENTIFIER = "com.9dpbQ.Stapler-mini-v0"; 282 | PRODUCT_NAME = "$(TARGET_NAME)"; 283 | SWIFT_EMIT_LOC_STRINGS = YES; 284 | SWIFT_VERSION = 5.0; 285 | }; 286 | name = Debug; 287 | }; 288 | CC5B389E2CCE3DE500043844 /* Release */ = { 289 | isa = XCBuildConfiguration; 290 | buildSettings = { 291 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 292 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 293 | CODE_SIGN_ENTITLEMENTS = "Stapler-mini-v0/Stapler_mini_v0.entitlements"; 294 | CODE_SIGN_STYLE = Automatic; 295 | COMBINE_HIDPI_IMAGES = YES; 296 | CURRENT_PROJECT_VERSION = 1; 297 | DEVELOPMENT_ASSET_PATHS = "\"Stapler-mini-v0/Preview Content\""; 298 | DEVELOPMENT_TEAM = TBSVB6XDJZ; 299 | ENABLE_HARDENED_RUNTIME = YES; 300 | ENABLE_PREVIEWS = YES; 301 | GENERATE_INFOPLIST_FILE = YES; 302 | INFOPLIST_FILE = "Stapler-mini-v0/Info.plist"; 303 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 304 | LD_RUNPATH_SEARCH_PATHS = ( 305 | "$(inherited)", 306 | "@executable_path/../Frameworks", 307 | ); 308 | MARKETING_VERSION = 1.0; 309 | PRODUCT_BUNDLE_IDENTIFIER = "com.9dpbQ.Stapler-mini-v0"; 310 | PRODUCT_NAME = "$(TARGET_NAME)"; 311 | SWIFT_EMIT_LOC_STRINGS = YES; 312 | SWIFT_VERSION = 5.0; 313 | }; 314 | name = Release; 315 | }; 316 | /* End XCBuildConfiguration section */ 317 | 318 | /* Begin XCConfigurationList section */ 319 | CC5B38882CCE3DE200043844 /* Build configuration list for PBXProject "Stapler-mini-v0" */ = { 320 | isa = XCConfigurationList; 321 | buildConfigurations = ( 322 | CC5B389A2CCE3DE500043844 /* Debug */, 323 | CC5B389B2CCE3DE500043844 /* Release */, 324 | ); 325 | defaultConfigurationIsVisible = 0; 326 | defaultConfigurationName = Release; 327 | }; 328 | CC5B389C2CCE3DE500043844 /* Build configuration list for PBXNativeTarget "Stapler-mini-v0" */ = { 329 | isa = XCConfigurationList; 330 | buildConfigurations = ( 331 | CC5B389D2CCE3DE500043844 /* Debug */, 332 | CC5B389E2CCE3DE500043844 /* Release */, 333 | ); 334 | defaultConfigurationIsVisible = 0; 335 | defaultConfigurationName = Release; 336 | }; 337 | /* End XCConfigurationList section */ 338 | }; 339 | rootObject = CC5B38852CCE3DE200043844 /* Project object */; 340 | } 341 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0.xcodeproj/project.xcworkspace/xcuserdata/qdpb.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0.xcodeproj/project.xcworkspace/xcuserdata/qdpb.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0.xcodeproj/xcuserdata/qdpb.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Stapler-mini-v0.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | ///ウィンドウを閉じたらアプリが終了したり、そういうバックグラウンド処理のクラス。 2 | ///使い方が合ってるかよくわからない 3 | import Foundation 4 | import Cocoa 5 | import SwiftData 6 | import UniformTypeIdentifiers 7 | 8 | class AppDelegate: NSObject, NSApplicationDelegate { 9 | @MainActor 10 | var modelContainer: ModelContainer? 11 | 12 | func applicationDidFinishLaunching(_ aNotification: Notification) { 13 | // SwiftData のモデルコンテナは @main struct で設定されるため、ここでは不要 14 | } 15 | 16 | ///以下🦑アイコンへ.staplerファイルをドロップした時の処理をAIとやってみたけど、全く動かない。 17 | ///ドキュメントタイプのファイルアイコンを設定しても反映されてなかったり、Allowed 18 | /// ContentTypeで.staplerをフィルターにかけれなかったり、そもそもUTTypeの定義に何かしら足りないものがあるからなのかも? 19 | /// それかそもそもこの方法がとんちんかんなのかも 20 | func application(_ sender: NSApplication, openFile filename: String) -> Bool { 21 | let url = URL(fileURLWithPath: filename) 22 | if UTType(filenameExtension: url.pathExtension) == .stapler { 23 | loadPreset(from: url) { preset in 24 | if let preset = preset { 25 | Task { @MainActor in 26 | await self.addPresetToContext(preset) 27 | } 28 | print("Loaded and added preset from dock: \(preset.presetName)") 29 | } else { 30 | print("Failed to load preset from dock") 31 | } 32 | } 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | func application(_ application: NSApplication, open urls: [URL]) { 39 | for url in urls where UTType(filenameExtension: url.pathExtension) == .stapler { 40 | loadPreset(from: url) { preset in 41 | if let preset = preset { 42 | Task { @MainActor in 43 | await self.addPresetToContext(preset) 44 | } 45 | print("Loaded and added preset from dock: \(preset.presetName)") 46 | } else { 47 | print("Failed to load preset from dock") 48 | } 49 | } 50 | } 51 | } 52 | 53 | private func loadPreset(from url: URL, completion: @escaping (Preset?) -> Void) { 54 | do { 55 | let jsonData = try Data(contentsOf: url) 56 | let loadedPreset = try JSONDecoder().decode(Preset.self, from: jsonData) 57 | completion(loadedPreset) 58 | } catch { 59 | print("Failed to load preset: \(error)") 60 | completion(nil) 61 | } 62 | } 63 | 64 | @MainActor 65 | private func addPresetToContext(_ preset: Preset) async { 66 | guard let modelContext = modelContainer?.mainContext else { return } 67 | modelContext.insert(preset) 68 | do { 69 | try modelContext.save() 70 | } catch { 71 | print("Failed to save context after adding preset: \(error)") 72 | } 73 | } 74 | 75 | func applicationWillTerminate(_ aNotification: Notification) { 76 | // アプリケーション終了時の処理 77 | } 78 | 79 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {//ウィンドウを閉じたらアプリが終了するような処理 80 | NSApplication.shared.terminate(self) 81 | return true 82 | } 83 | } 84 | 85 | 86 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Icon_v0_16x16@1x.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "Icon_v0_16x16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "Icon_v0_32x32@1x.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "Icon_v0_32x32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "Icon_v0_128x128@1x.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "Icon_v0_128x128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "Icon_v0_256x256@1x.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "Icon_v0_256x256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "Icon_v0_512x512@1x.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "Icon_v0_512x512@2x.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_128x128@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_128x128@1x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_128x128@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_16x16@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_16x16@1x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_16x16@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_256x256@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_256x256@1x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_256x256@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_32x32@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_32x32@1x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_32x32@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_512x512@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_512x512@1x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/AppIcon.appiconset/Icon_v0_512x512@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_128x128.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_16x16.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_256x256.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_32x32.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Assets.xcassets/exportFileIcon.iconset/icon_512x512.png -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/ContentView.swift: -------------------------------------------------------------------------------- 1 | ///メインのビュー 2 | ///色々なビューをここに集結。 3 | import SwiftUI 4 | import SwiftData 5 | 6 | struct ContentView: View { 7 | @Environment(\.modelContext) private var modelContext 8 | @Query(sort: [SortDescriptor(\Preset.presetName, order: .forward)]) private var presets: [Preset] 9 | 10 | @State private var isEditing: Bool = false 11 | @State private var selectedPresetID: UUID? = nil 12 | @FocusState private var isPresetNameFocused: Bool 13 | 14 | @State private var showingAlert = false 15 | @State private var alertMessage = "" 16 | @State private var isSheetPresented_AddPreset: Bool = false 17 | @State private var isSheetPresented_Export: Bool = false 18 | @State private var selectedKeyboardLayout: KeyboardLayout? = nil 19 | 20 | @State private var selectedPreset: Preset? = nil 21 | @State private var selectedKeyboardKey: KeyboardKey = .initial 22 | @State private var isInspectorPresented: Bool = false 23 | 24 | 25 | var body: some View { 26 | NavigationSplitView { 27 | List(selection: $selectedPresetID) { 28 | ForEach(presets, id: \.id) { preset in 29 | NavigationLink { 30 | PresetView(preset: .constant(preset), selectedKeyboardKey: $selectedKeyboardKey) 31 | .navigationTitle(preset.presetName) 32 | .toolbar { 33 | ToolbarItem { 34 | Button(action: { 35 | isSheetPresented_Export = true 36 | }) { 37 | Image(systemName: "square.and.arrow.up") 38 | } 39 | } 40 | } 41 | } label: { 42 | PresetLabelView( 43 | preset: preset, 44 | isEditing: $isEditing, 45 | selectedPresetID: $selectedPresetID, 46 | isFocused: $isPresetNameFocused, 47 | onDelete: { 48 | if let index = presets.firstIndex(where: { $0.id == preset.id }) { 49 | modelContext.delete(presets[index]) 50 | selectedPreset = nil 51 | } 52 | } 53 | ) 54 | } 55 | .onChange(of: selectedPresetID) { 56 | isEditing = false 57 | selectedPreset = preset 58 | } 59 | } 60 | } 61 | .navigationSplitViewColumnWidth(min: 180, ideal: 200, max: 220) 62 | .toolbar { 63 | ToolbarItem { 64 | Button(action: {isSheetPresented_AddPreset = true }) { 65 | Label("Add Preset", systemImage: "plus") 66 | } 67 | 68 | 69 | } 70 | } 71 | 72 | } detail: {//Presetが選択されていない状態のビュー 73 | Text("Select or Add a preset from + button.") 74 | } 75 | .inspector(isPresented: $isInspectorPresented) { 76 | SelectedDetailView(selectedKeyboardKey: $selectedKeyboardKey, selectedPreset: selectedPreset) 77 | .inspectorColumnWidth(min: 180, ideal: 200, max: 220) 78 | .toolbar { 79 | ToolbarItem { 80 | Button { 81 | isInspectorPresented.toggle() 82 | } label: { 83 | Label("toggle inspector", systemImage: "sidebar.right") 84 | } 85 | 86 | } 87 | } 88 | } 89 | .sheet(isPresented: $isSheetPresented_AddPreset) { 90 | AddPresetSheetView( 91 | selectedKeyboardType: $selectedKeyboardLayout, 92 | isSheetPresented: $isSheetPresented_AddPreset, 93 | onDecision: addPreset, 94 | importPreset: { 95 | loadPreset { preset in 96 | if let preset = preset { 97 | modelContext.insert(preset) 98 | // Presetが正常に読み込まれた場合の処理 99 | print("Loaded Preset: \(preset.presetName)") 100 | } else { 101 | // 読み込みが失敗またはキャンセルされた場合の処理 102 | print("Failed or Canceled to load Preset.") 103 | // showingAlert = true 104 | // alertMessage = "Failed to load Preset. .stapler file is only importable" 105 | } 106 | } 107 | } 108 | ) 109 | } 110 | .sheet(isPresented: $isSheetPresented_Export) { 111 | if let index = presets.firstIndex(where: { $0.id == selectedPresetID }) { 112 | let preset = presets[index] 113 | ExportSheetView(preset: preset) 114 | } 115 | } 116 | .alert(isPresented: $showingAlert) { 117 | Alert(title: Text("Import Result"), message: Text(alertMessage), dismissButton: .default(Text("OK"))) 118 | } 119 | // .frame(minWidth: 1000, maxWidth: .infinity, minHeight: 800, maxHeight: .infinity)//ウィンドウの最小、最大サイズ 120 | } 121 | private func addPreset(keyboardLayout: KeyboardLayout?) { 122 | guard let keyboardLayout = keyboardLayout else { return } 123 | let newPreset = Preset(presetName: "New Preset", keyboardLayout: keyboardLayout) 124 | modelContext.insert(newPreset) 125 | } 126 | private func deletePresets(offsets: IndexSet) { 127 | withAnimation { 128 | for index in offsets { 129 | modelContext.delete(presets[index]) 130 | } 131 | } 132 | } 133 | 134 | } 135 | 136 | 137 | #Preview { 138 | ContentView() 139 | .modelContainer(for: Preset.self, inMemory: true) 140 | } 141 | 142 | 143 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDocumentTypes 6 | 7 | 8 | CFBundleTypeIconFile 9 | exportFileIcon 10 | CFBundleTypeIconSystemGenerated 11 | 1 12 | CFBundleTypeName 13 | Stapler 14 | CFBundleTypeRole 15 | Editor 16 | LSHandlerRank 17 | Default 18 | LSItemContentTypes 19 | 20 | com.example.stapler 21 | 22 | NSDocumentClass 23 | NSDocument 24 | 25 | 26 | UTExportedTypeDeclarations 27 | 28 | 29 | UTTypeConformsTo 30 | 31 | public.data 32 | 33 | UTTypeDescription 34 | for drag & drop CustomizeKey 35 | UTTypeIcons 36 | 37 | UTTypeIdentifier 38 | com.example.customizekey 39 | UTTypeTagSpecification 40 | 41 | 42 | 43 | UTTypeConformsTo 44 | 45 | public.data 46 | 47 | UTTypeDescription 48 | for sharing user's Preset 49 | UTTypeIcons 50 | 51 | UTTypeIconBadgeName 52 | exportFileIcon 53 | 54 | UTTypeIdentifier 55 | com.example.stapler 56 | UTTypeTagSpecification 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/AddPresetSheetView.swift: -------------------------------------------------------------------------------- 1 | ///プリセットを追加する時のビュー。 2 | ///US/UK/JISから選択するか.staplerファイルをインポートする感じ。 3 | /// 4 | ///現在は本体キーボードしかないけれど、今後はKeyboardViewに柔軟性を持たせて自分の持っているキーボードを再現できるようにしていきたい。 5 | ///そのためにはちょっとクラスの書き換えが必要かなぁ? 6 | /// 7 | 8 | import SwiftUI 9 | // カスタムボタンスタイル 10 | struct CustomShapeButtonStyle_Gradient: ButtonStyle { 11 | let shape: S 12 | let fillColor: LinearGradient 13 | let frameSize: CGSize 14 | 15 | func makeBody(configuration: Configuration) -> some View { 16 | shape 17 | .fill(fillColor) 18 | .frame(width: frameSize.width, height: frameSize.height) 19 | .overlay( 20 | configuration.label 21 | ) 22 | .scaleEffect(configuration.isPressed ? 0.98 : 1.0) // 押した時のスケールエフェクト 23 | // .animation(.bouncy, value: configuration.isPressed) 24 | } 25 | } 26 | 27 | struct AddPresetSheetView: View { 28 | @Binding var selectedKeyboardType: KeyboardLayout? 29 | @Binding var isSheetPresented: Bool 30 | 31 | let onDecision: (KeyboardLayout?) -> Void 32 | let importPreset: () -> Void 33 | 34 | var body: some View { 35 | VStack { 36 | HStack { 37 | Text("Select Keyboard Layout") 38 | .font(.headline) 39 | .padding() 40 | Button { 41 | isSheetPresented = false 42 | importPreset() 43 | } label: { 44 | Label("import Preset", systemImage: "square.and.arrow.down") 45 | } 46 | } 47 | VStack { 48 | Text("MacBook Built-in Keyboard") 49 | .font(.caption) 50 | HStack { 51 | // US キーボード 52 | Button(action: { 53 | selectedKeyboardType = .US 54 | }) { 55 | Text("US") 56 | .foregroundColor(selectedKeyboardType == .US ? .accentColor : .white) 57 | .font(.system(size: 20)) 58 | } 59 | .buttonStyle( 60 | CustomShapeButtonStyle_Gradient( 61 | shape: RoundedRectangle(cornerRadius: 65 * 0.07), 62 | fillColor: LinearGradient(colors: [.black], startPoint: .bottom, endPoint: .top), 63 | frameSize: CGSize(width: 65 * 1.75 - 65 * 0.07, height: 65 - 65 * 0.07) 64 | ) 65 | ) 66 | .padding(7) 67 | // JIS キーボード 68 | Button(action: { 69 | selectedKeyboardType = .JIS 70 | }) { 71 | Text("JIS") 72 | .foregroundColor(selectedKeyboardType == .JIS ? .accentColor : .white) 73 | .font(.system(size: 20)) 74 | } 75 | .buttonStyle( 76 | CustomShapeButtonStyle_Gradient( 77 | shape: EnterShape_JIS(frameValue: 65), 78 | fillColor: LinearGradient(colors: [.black], startPoint: .bottom, endPoint: .top), 79 | frameSize: CGSize(width: 65*1.5, height: 65*2) 80 | ) 81 | ) 82 | 83 | // UK キーボード 84 | Button(action: { 85 | selectedKeyboardType = .UK 86 | }) { 87 | Text("UK") 88 | .foregroundColor(selectedKeyboardType == .UK ? .accentColor : .white) 89 | .font(.system(size: 20)) 90 | .padding(.leading, 10) 91 | } 92 | .buttonStyle( 93 | CustomShapeButtonStyle_Gradient( 94 | shape: EnterShape_UK(frameValue: 65), 95 | fillColor: LinearGradient(colors: [.black], startPoint: .bottom, endPoint: .top), 96 | frameSize: CGSize(width: 65, height: 65*2) 97 | ) 98 | ) 99 | } 100 | } 101 | // 決定・キャンセルボタン 102 | HStack { 103 | Button("Cancel") { 104 | isSheetPresented = false 105 | } 106 | .padding() 107 | 108 | Button("Create a Preset") { 109 | onDecision(selectedKeyboardType) 110 | isSheetPresented = false 111 | } 112 | .disabled(selectedKeyboardType == nil) 113 | .padding() 114 | } 115 | } 116 | .padding() 117 | .onAppear { 118 | selectedKeyboardType = nil 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/CustomizeKey/CustomKeyCategory.swift: -------------------------------------------------------------------------------- 1 | ///カテゴリ別のCustomizeKeyの配列とか 2 | 3 | import Foundation 4 | 5 | struct CustomKeyCategory: Identifiable { 6 | let id: UUID = UUID() 7 | let name: String 8 | let keys: [CustomizeKey] 9 | } 10 | 11 | struct CustomKeyDataSet { 12 | static let basicKeys: CustomKeyCategory = CustomKeyCategory( 13 | name: "Basic", 14 | keys: [ 15 | //Alphabets 16 | CustomizeKey(afterDisplaySymbol: "square.dotted", afterKeyOutPut: "vk_none", isUsingSFSymbol: true, helpText: "this key outputs nothing"), 17 | CustomizeKey(afterDisplaySymbol: "A", afterKeyOutPut: "a"), 18 | CustomizeKey(afterDisplaySymbol: "B", afterKeyOutPut: "b"), 19 | CustomizeKey(afterDisplaySymbol: "C", afterKeyOutPut: "c"), 20 | CustomizeKey(afterDisplaySymbol: "D", afterKeyOutPut: "d"), 21 | CustomizeKey(afterDisplaySymbol: "E", afterKeyOutPut: "e"), 22 | CustomizeKey(afterDisplaySymbol: "F", afterKeyOutPut: "f"), 23 | CustomizeKey(afterDisplaySymbol: "G", afterKeyOutPut: "g"), 24 | CustomizeKey(afterDisplaySymbol: "H", afterKeyOutPut: "h"), 25 | CustomizeKey(afterDisplaySymbol: "I", afterKeyOutPut: "i"), 26 | CustomizeKey(afterDisplaySymbol: "J", afterKeyOutPut: "j"), 27 | CustomizeKey(afterDisplaySymbol: "K", afterKeyOutPut: "k"), 28 | CustomizeKey(afterDisplaySymbol: "L", afterKeyOutPut: "l"), 29 | CustomizeKey(afterDisplaySymbol: "M", afterKeyOutPut: "m"), 30 | CustomizeKey(afterDisplaySymbol: "N", afterKeyOutPut: "n"), 31 | CustomizeKey(afterDisplaySymbol: "O", afterKeyOutPut: "o"), 32 | CustomizeKey(afterDisplaySymbol: "P", afterKeyOutPut: "p"), 33 | CustomizeKey(afterDisplaySymbol: "Q", afterKeyOutPut: "q"), 34 | CustomizeKey(afterDisplaySymbol: "R", afterKeyOutPut: "r"), 35 | CustomizeKey(afterDisplaySymbol: "S", afterKeyOutPut: "s"), 36 | CustomizeKey(afterDisplaySymbol: "T", afterKeyOutPut: "t"), 37 | CustomizeKey(afterDisplaySymbol: "U", afterKeyOutPut: "u"), 38 | CustomizeKey(afterDisplaySymbol: "V", afterKeyOutPut: "v"), 39 | CustomizeKey(afterDisplaySymbol: "W", afterKeyOutPut: "w"), 40 | CustomizeKey(afterDisplaySymbol: "X", afterKeyOutPut: "x"), 41 | CustomizeKey(afterDisplaySymbol: "Y", afterKeyOutPut: "y"), 42 | CustomizeKey(afterDisplaySymbol: "Z", afterKeyOutPut: "z"), 43 | //BasicNumbers 44 | CustomizeKey(afterDisplaySymbol: "1", afterKeyOutPut: "1"), 45 | CustomizeKey(afterDisplaySymbol: "2", afterKeyOutPut: "2"), 46 | CustomizeKey(afterDisplaySymbol: "3", afterKeyOutPut: "3"), 47 | CustomizeKey(afterDisplaySymbol: "4", afterKeyOutPut: "4"), 48 | CustomizeKey(afterDisplaySymbol: "5", afterKeyOutPut: "5"), 49 | CustomizeKey(afterDisplaySymbol: "6", afterKeyOutPut: "6"), 50 | CustomizeKey(afterDisplaySymbol: "7", afterKeyOutPut: "7"), 51 | CustomizeKey(afterDisplaySymbol: "8", afterKeyOutPut: "8"), 52 | CustomizeKey(afterDisplaySymbol: "9", afterKeyOutPut: "9"), 53 | CustomizeKey(afterDisplaySymbol: "0", afterKeyOutPut: "0"), 54 | 55 | ] 56 | ) 57 | static let symbolKeys: CustomKeyCategory = CustomKeyCategory( 58 | name: "Symbol", 59 | keys: [ 60 | //単打で出せるもの(US視点) 61 | 62 | 63 | CustomizeKey(afterDisplaySymbol: "-", afterKeyOutPut: "-"), 64 | CustomizeKey(afterDisplaySymbol: "_", afterKeyOutPut: "_"),//Shift + - 65 | 66 | CustomizeKey(afterDisplaySymbol: "=", afterKeyOutPut: "="), 67 | CustomizeKey(afterDisplaySymbol: "+", afterKeyOutPut: "+"),//Shift + = 68 | 69 | CustomizeKey(afterDisplaySymbol: "\\", afterKeyOutPut: "\\"),//backslash 70 | CustomizeKey(afterDisplaySymbol: "|", afterKeyOutPut: "|"),//Shift + backslash 71 | 72 | CustomizeKey(afterDisplaySymbol: ";", afterKeyOutPut: ";"), 73 | CustomizeKey(afterDisplaySymbol: ":", afterKeyOutPut: ":"),//Shift + ; 74 | 75 | CustomizeKey(afterDisplaySymbol: "`", afterKeyOutPut: "`"), 76 | CustomizeKey(afterDisplaySymbol: "~", afterKeyOutPut: "~"),//Shift + ` 77 | 78 | CustomizeKey(afterDisplaySymbol: "'", afterKeyOutPut: "'"), 79 | CustomizeKey(afterDisplaySymbol: "\"", afterKeyOutPut: "\""),//Shift + ' 80 | 81 | CustomizeKey(afterDisplaySymbol: ",", afterKeyOutPut: ","), 82 | CustomizeKey(afterDisplaySymbol: ".", afterKeyOutPut: "."), 83 | 84 | CustomizeKey(afterDisplaySymbol: "/", afterKeyOutPut: "/"), 85 | CustomizeKey(afterDisplaySymbol: "?", afterKeyOutPut: "?"),//Shift + slash 86 | 87 | //Shift系 88 | //数字+シフト 89 | CustomizeKey(afterDisplaySymbol: "!", afterKeyOutPut: "!"),//Shift + 1 90 | CustomizeKey(afterDisplaySymbol: "@", afterKeyOutPut: "@"),//Shift + 2 91 | CustomizeKey(afterDisplaySymbol: "#", afterKeyOutPut: "#"),//Shift + 3 92 | CustomizeKey(afterDisplaySymbol: "$", afterKeyOutPut: "$"),//Shift + 4 93 | CustomizeKey(afterDisplaySymbol: "%", afterKeyOutPut: "%"),//Shift + 5 94 | CustomizeKey(afterDisplaySymbol: "^", afterKeyOutPut: "^"),//Shift + 6 95 | CustomizeKey(afterDisplaySymbol: "&", afterKeyOutPut: "&"),//Shift + 7 96 | CustomizeKey(afterDisplaySymbol: "*", afterKeyOutPut: "*"),//Shift + 8 97 | CustomizeKey(afterDisplaySymbol: "(", afterKeyOutPut: "("),//Shift + 9 98 | CustomizeKey(afterDisplaySymbol: ")", afterKeyOutPut: ")"),//Shift + 0 99 | 100 | CustomizeKey(afterDisplaySymbol: "[", afterKeyOutPut: "["), 101 | CustomizeKey(afterDisplaySymbol: "]", afterKeyOutPut: "]"), 102 | 103 | CustomizeKey(afterDisplaySymbol: "{", afterKeyOutPut: "{"),//Shift + [ 104 | CustomizeKey(afterDisplaySymbol: "}", afterKeyOutPut: "}"),//Shift + ] 105 | 106 | 107 | 108 | CustomizeKey(afterDisplaySymbol: "<", afterKeyOutPut: "<"),//Shift + , 109 | CustomizeKey(afterDisplaySymbol: ">", afterKeyOutPut: ">"),//Shift + . 110 | 111 | 112 | 113 | //記号+シフト 114 | 115 | // //Option系 ユーザーがDisplay Nameをいじれるようにしつつ、あとは修飾キートグルでどうにかしてもらうことにする。 116 | // //数字+オプション 117 | // CustomizeKey(afterDisplaySymbol: "º", afterKeyOutPut: "º"),//0 118 | // CustomizeKey(afterDisplaySymbol: "¡", afterKeyOutPut: "¡"),//1 119 | // CustomizeKey(afterDisplaySymbol: "™", afterKeyOutPut: "™"),//2 120 | // CustomizeKey(afterDisplaySymbol: "£", afterKeyOutPut: "£"),//3 121 | // CustomizeKey(afterDisplaySymbol: "¢", afterKeyOutPut: "¢"),//4 122 | // CustomizeKey(afterDisplaySymbol: "∞", afterKeyOutPut: "∞"),//5 123 | // CustomizeKey(afterDisplaySymbol: "§", afterKeyOutPut: "§"),//6 124 | // CustomizeKey(afterDisplaySymbol: "¶", afterKeyOutPut: "¶"),//7 125 | // CustomizeKey(afterDisplaySymbol: "•", afterKeyOutPut: "•"),//8 126 | // CustomizeKey(afterDisplaySymbol: "ª", afterKeyOutPut: "ª"),//9 127 | // //アルファベット+オプション 128 | // CustomizeKey(afterDisplaySymbol: "å", afterKeyOutPut: "å"),//A 129 | // CustomizeKey(afterDisplaySymbol: "∫", afterKeyOutPut: "∫"),//B 130 | // CustomizeKey(afterDisplaySymbol: "ç", afterKeyOutPut: "ç"),//C 131 | // CustomizeKey(afterDisplaySymbol: "∂", afterKeyOutPut: "∂"),//D 132 | // CustomizeKey(afterDisplaySymbol: "´", afterKeyOutPut: "´"),//E 133 | // CustomizeKey(afterDisplaySymbol: "ƒ", afterKeyOutPut: "ƒ"),//F 134 | // CustomizeKey(afterDisplaySymbol: "©", afterKeyOutPut: "©"),//G 135 | // CustomizeKey(afterDisplaySymbol: "˙", afterKeyOutPut: "˙"),//H 136 | // CustomizeKey(afterDisplaySymbol: "ˆ", afterKeyOutPut: "ˆ"),//I 137 | // CustomizeKey(afterDisplaySymbol: "∆", afterKeyOutPut: "∆"),//J 138 | // CustomizeKey(afterDisplaySymbol: "˚", afterKeyOutPut: "˚"),//K 139 | // CustomizeKey(afterDisplaySymbol: "¬", afterKeyOutPut: "¬"),//L 140 | // CustomizeKey(afterDisplaySymbol: "µ", afterKeyOutPut: "µ"),//M 141 | // CustomizeKey(afterDisplaySymbol: "˜", afterKeyOutPut: "˜"),//N 142 | // CustomizeKey(afterDisplaySymbol: "ø", afterKeyOutPut: "ø"),//O 143 | // CustomizeKey(afterDisplaySymbol: "π", afterKeyOutPut: "π"),//P 144 | // CustomizeKey(afterDisplaySymbol: "œ", afterKeyOutPut: "œ"),//Q 145 | // CustomizeKey(afterDisplaySymbol: "®", afterKeyOutPut: "®"),//R 146 | // CustomizeKey(afterDisplaySymbol: "ß", afterKeyOutPut: "ß"),//S 147 | // CustomizeKey(afterDisplaySymbol: "†", afterKeyOutPut: "†"),//T 148 | // CustomizeKey(afterDisplaySymbol: "¨", afterKeyOutPut: "¨"),//U 149 | // CustomizeKey(afterDisplaySymbol: "√", afterKeyOutPut: "√"),//V 150 | // CustomizeKey(afterDisplaySymbol: "∑", afterKeyOutPut: "∑"),//W 151 | // CustomizeKey(afterDisplaySymbol: "≈", afterKeyOutPut: "≈"),//X 152 | // CustomizeKey(afterDisplaySymbol: "¥", afterKeyOutPut: "¥"),//Y 153 | // CustomizeKey(afterDisplaySymbol: "Ω", afterKeyOutPut: "Ω"),//Z 154 | // //記号+オプション 155 | //// CustomizeKey(afterDisplaySymbol: "`", afterKeyOutPut: "`"),//Option + ` 同じっぽい?意味なさそう 156 | // CustomizeKey(afterDisplaySymbol: "–", afterKeyOutPut: "–"),//Option + - 157 | // CustomizeKey(afterDisplaySymbol: "≠", afterKeyOutPut: "≠"),//Option + = 158 | // CustomizeKey(afterDisplaySymbol: "“", afterKeyOutPut: "“"),//Option + [ 159 | // CustomizeKey(afterDisplaySymbol: "‘", afterKeyOutPut: "‘"),//Option + ] 160 | // CustomizeKey(afterDisplaySymbol: "«", afterKeyOutPut: "«"),//Option + backslash 161 | // CustomizeKey(afterDisplaySymbol: "…", afterKeyOutPut: "…"),//Option + ; 162 | // CustomizeKey(afterDisplaySymbol: "'", afterKeyOutPut: "'"),//Option + ' 163 | // CustomizeKey(afterDisplaySymbol: "≤", afterKeyOutPut: "≤"),//Option + , 164 | // CustomizeKey(afterDisplaySymbol: "≥", afterKeyOutPut: "≥"),//Option + . 165 | // CustomizeKey(afterDisplaySymbol: "÷", afterKeyOutPut: "÷"),//Option + slash 166 | ] 167 | ) 168 | static let keyPadKeys: CustomKeyCategory = CustomKeyCategory( 169 | name: "Keypad", 170 | keys: [ 171 | //KeyPadKeys 172 | CustomizeKey(afterDisplaySymbol: "k0", afterKeyOutPut: "keypad_0"), 173 | CustomizeKey(afterDisplaySymbol: "k1", afterKeyOutPut: "keypad_1"), 174 | CustomizeKey(afterDisplaySymbol: "k2", afterKeyOutPut: "keypad_2"), 175 | CustomizeKey(afterDisplaySymbol: "k3", afterKeyOutPut: "keypad_3"), 176 | CustomizeKey(afterDisplaySymbol: "k4", afterKeyOutPut: "keypad_4"), 177 | CustomizeKey(afterDisplaySymbol: "k5", afterKeyOutPut: "keypad_5"), 178 | CustomizeKey(afterDisplaySymbol: "k6", afterKeyOutPut: "keypad_6"), 179 | CustomizeKey(afterDisplaySymbol: "k7", afterKeyOutPut: "keypad_7"), 180 | CustomizeKey(afterDisplaySymbol: "k8", afterKeyOutPut: "keypad_8"), 181 | CustomizeKey(afterDisplaySymbol: "k9", afterKeyOutPut: "keypad_9"), 182 | CustomizeKey(afterDisplaySymbol: "num_lock", afterKeyOutPut: "keypad_num_lock"), 183 | CustomizeKey(afterDisplaySymbol: "k/", afterKeyOutPut: "keypad_slash"), 184 | CustomizeKey(afterDisplaySymbol: "k*", afterKeyOutPut: "keypad_asterisk"), 185 | CustomizeKey(afterDisplaySymbol: "k-", afterKeyOutPut: "keypad_hyphen"), 186 | CustomizeKey(afterDisplaySymbol: "k+", afterKeyOutPut: "keypad_plus"), 187 | CustomizeKey(afterDisplaySymbol: "k=", afterKeyOutPut: "keypad_equal_sign"), 188 | CustomizeKey(afterDisplaySymbol: "enter", afterKeyOutPut: "keypad_enter"), 189 | CustomizeKey(afterDisplaySymbol: "k,", afterKeyOutPut: "keypad_comma"), 190 | CustomizeKey(afterDisplaySymbol: "k.", afterKeyOutPut: "keypad_period"), 191 | 192 | ] 193 | ) 194 | static let controlKeys: CustomKeyCategory = CustomKeyCategory( 195 | name: "Control", 196 | keys: [ 197 | //Controls 198 | CustomizeKey(afterDisplaySymbol: "return", afterKeyOutPut: "return", isUsingSFSymbol: true), 199 | CustomizeKey(afterDisplaySymbol: "␣", afterKeyOutPut: "␣"), 200 | CustomizeKey(afterDisplaySymbol: "arrow.right.to.line", afterKeyOutPut: "tab", isUsingSFSymbol: true), 201 | CustomizeKey(afterDisplaySymbol: "esc", afterKeyOutPut: "esc"), 202 | CustomizeKey(afterDisplaySymbol: "delete.left", afterKeyOutPut: "BS", isUsingSFSymbol: true), 203 | CustomizeKey(afterDisplaySymbol: "delete.right", afterKeyOutPut: "Del", isUsingSFSymbol: true), 204 | CustomizeKey(afterDisplaySymbol: "かな", afterKeyOutPut: "かな"), 205 | CustomizeKey(afterDisplaySymbol: "英数", afterKeyOutPut: "英数"), 206 | CustomizeKey(afterDisplaySymbol: "変換", afterKeyOutPut: "変換"), 207 | CustomizeKey(afterDisplaySymbol: "無変換", afterKeyOutPut: "無変換"), 208 | //FullSizeControls 209 | CustomizeKey(afterDisplaySymbol: "print_screen", afterKeyOutPut: "print_screen"), 210 | CustomizeKey(afterDisplaySymbol: "scroll_lock", afterKeyOutPut: "scroll_lock"), 211 | CustomizeKey(afterDisplaySymbol: "pause", afterKeyOutPut: "pause"), 212 | CustomizeKey(afterDisplaySymbol: "insert", afterKeyOutPut: "insert"), 213 | CustomizeKey(afterDisplaySymbol: "application", afterKeyOutPut: "application"), 214 | CustomizeKey(afterDisplaySymbol: "help", afterKeyOutPut: "help"), 215 | CustomizeKey(afterDisplaySymbol: "power", afterKeyOutPut: "power"), 216 | //Arrows 217 | CustomizeKey(afterDisplaySymbol: "←", afterKeyOutPut: "←"), 218 | CustomizeKey(afterDisplaySymbol: "↑", afterKeyOutPut: "↑"), 219 | CustomizeKey(afterDisplaySymbol: "→", afterKeyOutPut: "→"), 220 | CustomizeKey(afterDisplaySymbol: "↓", afterKeyOutPut: "↓"), 221 | CustomizeKey(afterDisplaySymbol: "page_up", afterKeyOutPut: "page_up"), 222 | CustomizeKey(afterDisplaySymbol: "page_down", afterKeyOutPut: "page_down"), 223 | CustomizeKey(afterDisplaySymbol: "home", afterKeyOutPut: "home"), 224 | CustomizeKey(afterDisplaySymbol: "end", afterKeyOutPut: "end"), 225 | //MediaControls 226 | //MacOS 227 | CustomizeKey(afterDisplaySymbol: "rectangle.3.group", afterKeyOutPut: "mission_control", isUsingSFSymbol: true), 228 | CustomizeKey(afterDisplaySymbol: "magnifyingglass", afterKeyOutPut: "spotlight", isUsingSFSymbol: true), 229 | CustomizeKey(afterDisplaySymbol: "microphone", afterKeyOutPut: "dictation", isUsingSFSymbol: true), 230 | CustomizeKey(afterDisplaySymbol: "square.grid.3x2", afterKeyOutPut: "launchpad", isUsingSFSymbol: true), 231 | //Sound 232 | CustomizeKey(afterDisplaySymbol: "backward", afterKeyOutPut: "rewind", isUsingSFSymbol: true), 233 | CustomizeKey(afterDisplaySymbol: "playpause", afterKeyOutPut: "play_or_pause", isUsingSFSymbol: true), 234 | CustomizeKey(afterDisplaySymbol: "forward", afterKeyOutPut: "fast_forward", isUsingSFSymbol: true), 235 | CustomizeKey(afterDisplaySymbol: "speaker.slash", afterKeyOutPut: "mute", isUsingSFSymbol: true), 236 | CustomizeKey(afterDisplaySymbol: "speaker.wave.1", afterKeyOutPut: "volume_decrement", isUsingSFSymbol: true), 237 | CustomizeKey(afterDisplaySymbol: "speaker.wave.3", afterKeyOutPut: "volume_increment", isUsingSFSymbol: true), 238 | CustomizeKey(afterDisplaySymbol: "eject", afterKeyOutPut: "eject", isUsingSFSymbol: true), 239 | //Light Displayの3つの差異は?ないなら一つに統合して良い気がする 240 | CustomizeKey(afterDisplaySymbol: "sun.min.fill", afterKeyOutPut: "display_brightness_decrement", isUsingSFSymbol: true), 241 | CustomizeKey(afterDisplaySymbol: "sun.max.fill", afterKeyOutPut: "display_brightness_increment", isUsingSFSymbol: true), 242 | 243 | CustomizeKey(afterDisplaySymbol: "sun.min.fill", afterKeyOutPut: "brightness_down", isUsingSFSymbol: true), 244 | CustomizeKey(afterDisplaySymbol: "sun.max.fill", afterKeyOutPut: "brightness_up", isUsingSFSymbol: true), 245 | CustomizeKey(afterDisplaySymbol: "sun.min.fill", afterKeyOutPut: "brightness_down(2)", isUsingSFSymbol: true),//外部ディスプレイ? 246 | CustomizeKey(afterDisplaySymbol: "sun.max.fill", afterKeyOutPut: "brightness_up(2)", isUsingSFSymbol: true), 247 | 248 | CustomizeKey(afterDisplaySymbol: "light.min", afterKeyOutPut: "illumination_down", isUsingSFSymbol: true),//keyboard backlight 249 | CustomizeKey(afterDisplaySymbol: "light.max", afterKeyOutPut: "illumination_up", isUsingSFSymbol: true), 250 | ] 251 | ) 252 | 253 | 254 | 255 | 256 | static let specialKeys: CustomKeyCategory = CustomKeyCategory( 257 | name: "Special", 258 | keys: [ 259 | CustomizeKey(afterDisplaySymbol: "1.square", afterKeyOutPut: "layer1", isUsingSFSymbol: true, layerKeyNumber: 1), 260 | CustomizeKey(afterDisplaySymbol: "2.square", afterKeyOutPut: "layer2", isUsingSFSymbol: true, layerKeyNumber: 2), 261 | CustomizeKey(afterDisplaySymbol: "3.square", afterKeyOutPut: "layer3", isUsingSFSymbol: true, layerKeyNumber: 3), 262 | CustomizeKey(afterDisplaySymbol: "4.square", afterKeyOutPut: "layer4", isUsingSFSymbol: true, layerKeyNumber: 4), 263 | CustomizeKey(afterDisplaySymbol: "5.square", afterKeyOutPut: "layer5", isUsingSFSymbol: true, layerKeyNumber: 5), 264 | CustomizeKey(afterDisplaySymbol: "6.square", afterKeyOutPut: "layer6", isUsingSFSymbol: true, layerKeyNumber: 6), 265 | CustomizeKey(afterDisplaySymbol: "7.square", afterKeyOutPut: "layer7", isUsingSFSymbol: true, layerKeyNumber: 7), 266 | CustomizeKey(afterDisplaySymbol: "8.square", afterKeyOutPut: "layer8", isUsingSFSymbol: true, layerKeyNumber: 8), 267 | 268 | 269 | CustomizeKey(afterDisplaySymbol: "L⇧", afterKeyOutPut: "left_shift"), 270 | CustomizeKey(afterDisplaySymbol: "L⌘", afterKeyOutPut: "left_command"), 271 | CustomizeKey(afterDisplaySymbol: "L^", afterKeyOutPut: "left_control"), 272 | CustomizeKey(afterDisplaySymbol: "L⌥", afterKeyOutPut: "left_option"), 273 | 274 | CustomizeKey(afterDisplaySymbol: "R⇧", afterKeyOutPut: "right_shift"), 275 | CustomizeKey(afterDisplaySymbol: "R⌘", afterKeyOutPut: "right_command"), 276 | CustomizeKey(afterDisplaySymbol: "R^", afterKeyOutPut: "right_control"), 277 | CustomizeKey(afterDisplaySymbol: "R⌥", afterKeyOutPut: "right_option"), 278 | CustomizeKey(afterDisplaySymbol: "fn", afterKeyOutPut: "fn"), 279 | ] 280 | ) 281 | 282 | static let functionKeys: CustomKeyCategory = CustomKeyCategory( 283 | name: "FunctionKey", 284 | keys: [ 285 | CustomizeKey(afterDisplaySymbol: "F1", afterKeyOutPut: "F1"), 286 | CustomizeKey(afterDisplaySymbol: "F2", afterKeyOutPut: "F2"), 287 | CustomizeKey(afterDisplaySymbol: "F3", afterKeyOutPut: "F3"), 288 | CustomizeKey(afterDisplaySymbol: "F4", afterKeyOutPut: "F4"), 289 | CustomizeKey(afterDisplaySymbol: "F5", afterKeyOutPut: "F5"), 290 | CustomizeKey(afterDisplaySymbol: "F6", afterKeyOutPut: "F6"), 291 | CustomizeKey(afterDisplaySymbol: "F7", afterKeyOutPut: "F7"), 292 | CustomizeKey(afterDisplaySymbol: "F8", afterKeyOutPut: "F8"), 293 | CustomizeKey(afterDisplaySymbol: "F9", afterKeyOutPut: "F9"), 294 | CustomizeKey(afterDisplaySymbol: "F10", afterKeyOutPut: "F10"), 295 | CustomizeKey(afterDisplaySymbol: "F11", afterKeyOutPut: "F11"), 296 | CustomizeKey(afterDisplaySymbol: "F12", afterKeyOutPut: "F12"), 297 | CustomizeKey(afterDisplaySymbol: "F13", afterKeyOutPut: "F13"), 298 | CustomizeKey(afterDisplaySymbol: "F14", afterKeyOutPut: "F14"), 299 | CustomizeKey(afterDisplaySymbol: "F15", afterKeyOutPut: "F15"), 300 | CustomizeKey(afterDisplaySymbol: "F16", afterKeyOutPut: "F16"), 301 | CustomizeKey(afterDisplaySymbol: "F17", afterKeyOutPut: "F17"), 302 | CustomizeKey(afterDisplaySymbol: "F18", afterKeyOutPut: "F18"), 303 | CustomizeKey(afterDisplaySymbol: "F19", afterKeyOutPut: "F19"), 304 | CustomizeKey(afterDisplaySymbol: "F20", afterKeyOutPut: "F20"), 305 | CustomizeKey(afterDisplaySymbol: "F21", afterKeyOutPut: "F21"), 306 | CustomizeKey(afterDisplaySymbol: "F22", afterKeyOutPut: "F22"), 307 | CustomizeKey(afterDisplaySymbol: "F23", afterKeyOutPut: "F23"), 308 | CustomizeKey(afterDisplaySymbol: "F24", afterKeyOutPut: "F24"), 309 | 310 | 311 | ] 312 | ) 313 | 314 | static let internationalKeys: CustomKeyCategory = CustomKeyCategory( 315 | name: "International", 316 | keys: [ 317 | CustomizeKey(afterDisplaySymbol: "international1", afterKeyOutPut: "international1"), 318 | CustomizeKey(afterDisplaySymbol: "international2", afterKeyOutPut: "international2"), 319 | CustomizeKey(afterDisplaySymbol: "international3", afterKeyOutPut: "international3"), 320 | CustomizeKey(afterDisplaySymbol: "international4", afterKeyOutPut: "international4"), 321 | CustomizeKey(afterDisplaySymbol: "international5", afterKeyOutPut: "international5"), 322 | CustomizeKey(afterDisplaySymbol: "international6", afterKeyOutPut: "international6"), 323 | CustomizeKey(afterDisplaySymbol: "international7", afterKeyOutPut: "international7"), 324 | CustomizeKey(afterDisplaySymbol: "international8", afterKeyOutPut: "international8"), 325 | CustomizeKey(afterDisplaySymbol: "international9", afterKeyOutPut: "international9"), 326 | CustomizeKey(afterDisplaySymbol: "lang1", afterKeyOutPut: "lang1"), 327 | CustomizeKey(afterDisplaySymbol: "lang2", afterKeyOutPut: "lang2"), 328 | CustomizeKey(afterDisplaySymbol: "lang3", afterKeyOutPut: "lang3"), 329 | CustomizeKey(afterDisplaySymbol: "lang4", afterKeyOutPut: "lang4"), 330 | CustomizeKey(afterDisplaySymbol: "lang5", afterKeyOutPut: "lang5"), 331 | CustomizeKey(afterDisplaySymbol: "lang6", afterKeyOutPut: "lang6"), 332 | CustomizeKey(afterDisplaySymbol: "lang7", afterKeyOutPut: "lang7"), 333 | CustomizeKey(afterDisplaySymbol: "lang8", afterKeyOutPut: "lang8"), 334 | CustomizeKey(afterDisplaySymbol: "lang9", afterKeyOutPut: "lang9"), 335 | 336 | 337 | ] 338 | ) 339 | 340 | static let mouseKeys: CustomKeyCategory = CustomKeyCategory( 341 | name: "Mouse", 342 | keys: [ 343 | CustomizeKey(afterDisplaySymbol: "mouse_up", afterKeyOutPut: "mouse_up"), 344 | CustomizeKey(afterDisplaySymbol: "mouse_up(fast)", afterKeyOutPut: "mouse_up(fast)"), 345 | CustomizeKey(afterDisplaySymbol: "mouse_up(slow)", afterKeyOutPut: "mouse_up(slow)"), 346 | CustomizeKey(afterDisplaySymbol: "mouse_down", afterKeyOutPut: "mouse_down"), 347 | CustomizeKey(afterDisplaySymbol: "mouse_down(fast)", afterKeyOutPut: "mouse_down(fast)"), 348 | CustomizeKey(afterDisplaySymbol: "mouse_down(slow)", afterKeyOutPut: "mouse_down(slow)"), 349 | CustomizeKey(afterDisplaySymbol: "mouse_left", afterKeyOutPut: "mouse_left"), 350 | CustomizeKey(afterDisplaySymbol: "mouse_left(fast)", afterKeyOutPut: "mouse_left(fast)"), 351 | CustomizeKey(afterDisplaySymbol: "mouse_left(slow)", afterKeyOutPut: "mouse_left(slow)"), 352 | CustomizeKey(afterDisplaySymbol: "mouse_right", afterKeyOutPut: "mouse_right"), 353 | CustomizeKey(afterDisplaySymbol: "mouse_right(fast)", afterKeyOutPut: "mouse_right(fast)"), 354 | CustomizeKey(afterDisplaySymbol: "mouse_right(slow)", afterKeyOutPut: "mouse_right(slow)"), 355 | CustomizeKey(afterDisplaySymbol: "scroll_up", afterKeyOutPut: "scroll_up"), 356 | CustomizeKey(afterDisplaySymbol: "scroll_up(fast)", afterKeyOutPut: "scroll_up(fast)"), 357 | CustomizeKey(afterDisplaySymbol: "scroll_up(slow)", afterKeyOutPut: "scroll_up(slow)"), 358 | CustomizeKey(afterDisplaySymbol: "scroll_down", afterKeyOutPut: "scroll_down"), 359 | CustomizeKey(afterDisplaySymbol: "scroll_down(fast)", afterKeyOutPut: "scroll_down(fast)"), 360 | CustomizeKey(afterDisplaySymbol: "scroll_down(slow)", afterKeyOutPut: "scroll_down(slow)"), 361 | CustomizeKey(afterDisplaySymbol: "scroll_left", afterKeyOutPut: "scroll_left"), 362 | CustomizeKey(afterDisplaySymbol: "scroll_left(fast)", afterKeyOutPut: "scroll_left(fast)"), 363 | CustomizeKey(afterDisplaySymbol: "scroll_left(slow)", afterKeyOutPut: "scroll_left(slow)"), 364 | CustomizeKey(afterDisplaySymbol: "scroll_right", afterKeyOutPut: "scroll_right"), 365 | CustomizeKey(afterDisplaySymbol: "scroll_right(fast)", afterKeyOutPut: "scroll_right(fast)"), 366 | CustomizeKey(afterDisplaySymbol: "scroll_right(slow)", afterKeyOutPut: "scroll_right(slow)"), 367 | CustomizeKey(afterDisplaySymbol: "speed_multi_plier(2.0)", afterKeyOutPut: "speed_multi_plier(2.0)"), 368 | CustomizeKey(afterDisplaySymbol: "speed_multi_plier(0.5)", afterKeyOutPut: "speed_multi_plier(0.5)"), 369 | CustomizeKey(afterDisplaySymbol: "speed_multi_plier(0.25)", afterKeyOutPut: "speed_multi_plier(0.25)"), 370 | CustomizeKey(afterDisplaySymbol: "speed_multi_plier(0.125)", afterKeyOutPut: "speed_multi_plier(0.125)"), 371 | 372 | CustomizeKey(afterDisplaySymbol: "button1", afterKeyOutPut: "button1"), 373 | CustomizeKey(afterDisplaySymbol: "button2", afterKeyOutPut: "button2"), 374 | CustomizeKey(afterDisplaySymbol: "button3", afterKeyOutPut: "button3"), 375 | CustomizeKey(afterDisplaySymbol: "button4", afterKeyOutPut: "button4"), 376 | CustomizeKey(afterDisplaySymbol: "button5", afterKeyOutPut: "button5"), 377 | CustomizeKey(afterDisplaySymbol: "button6", afterKeyOutPut: "button6"), 378 | CustomizeKey(afterDisplaySymbol: "button7", afterKeyOutPut: "button7"), 379 | CustomizeKey(afterDisplaySymbol: "button8", afterKeyOutPut: "button8"), 380 | CustomizeKey(afterDisplaySymbol: "button9", afterKeyOutPut: "button9"), 381 | CustomizeKey(afterDisplaySymbol: "button10", afterKeyOutPut: "button10"), 382 | CustomizeKey(afterDisplaySymbol: "button11", afterKeyOutPut: "button11"), 383 | CustomizeKey(afterDisplaySymbol: "button12", afterKeyOutPut: "button12"), 384 | CustomizeKey(afterDisplaySymbol: "button13", afterKeyOutPut: "button13"), 385 | CustomizeKey(afterDisplaySymbol: "button14", afterKeyOutPut: "button14"), 386 | CustomizeKey(afterDisplaySymbol: "button15", afterKeyOutPut: "button15"), 387 | CustomizeKey(afterDisplaySymbol: "button16", afterKeyOutPut: "button16"), 388 | CustomizeKey(afterDisplaySymbol: "button17", afterKeyOutPut: "button17"), 389 | CustomizeKey(afterDisplaySymbol: "button18", afterKeyOutPut: "button18"), 390 | CustomizeKey(afterDisplaySymbol: "button19", afterKeyOutPut: "button19"), 391 | CustomizeKey(afterDisplaySymbol: "button20", afterKeyOutPut: "button20"), 392 | CustomizeKey(afterDisplaySymbol: "button21", afterKeyOutPut: "button21"), 393 | CustomizeKey(afterDisplaySymbol: "button22", afterKeyOutPut: "button22"), 394 | CustomizeKey(afterDisplaySymbol: "button23", afterKeyOutPut: "button23"), 395 | CustomizeKey(afterDisplaySymbol: "button24", afterKeyOutPut: "button24"), 396 | CustomizeKey(afterDisplaySymbol: "button25", afterKeyOutPut: "button25"), 397 | CustomizeKey(afterDisplaySymbol: "button26", afterKeyOutPut: "button26"), 398 | CustomizeKey(afterDisplaySymbol: "button27", afterKeyOutPut: "button27"), 399 | CustomizeKey(afterDisplaySymbol: "button28", afterKeyOutPut: "button28"), 400 | CustomizeKey(afterDisplaySymbol: "button29", afterKeyOutPut: "button29"), 401 | CustomizeKey(afterDisplaySymbol: "button30", afterKeyOutPut: "button30"), 402 | CustomizeKey(afterDisplaySymbol: "button31", afterKeyOutPut: "button31"), 403 | CustomizeKey(afterDisplaySymbol: "button32", afterKeyOutPut: "button32"), 404 | ] 405 | ) 406 | 407 | static let allCategories: [CustomKeyCategory] = [ 408 | basicKeys, symbolKeys, controlKeys, keyPadKeys, specialKeys, functionKeys, internationalKeys, mouseKeys 409 | ] 410 | } 411 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/CustomizeKey/CustomizeKeyTabView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomizeKeyTabView.swift 3 | // SwiftData Test Project2 4 | // 5 | // Created by qdpb on 2024/09/14. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CustomizeKeyTabView: View { 11 | @State private var searchText: String = "" 12 | @State private var selectedTab: String = "" // 現在選択中のタブを管理 13 | // @Binding var externalSearchFieldFocuse: Bool // PresetViewからのバインディング 14 | @FocusState private var internalSearchFieldFocus: Bool // 独自のFocusState 15 | // 16 | // 全カテゴリーのキーをフィルタリング 17 | var filteredAllKeys: [CustomizeKey] { 18 | let allKeys = CustomKeyDataSet.allCategories.flatMap { $0.keys } 19 | if searchText.isEmpty { 20 | return allKeys 21 | } else { 22 | return allKeys.filter { key in 23 | key.afterDisplaySymbol.localizedCaseInsensitiveContains(searchText) 24 | // key.afterKeyOutPut.localizedCaseInsensitiveContains(searchText) 25 | } 26 | } 27 | } 28 | 29 | let columns = [ 30 | GridItem(.adaptive(minimum: 65 - 65 * 0.07 + 2.5, maximum: 100)) 31 | ] 32 | 33 | var body: some View { 34 | ZStack { 35 | TabView(selection: $selectedTab) { 36 | ForEach(CustomKeyDataSet.allCategories, id: \.id) { category in 37 | ScrollView(.vertical) { 38 | LazyVGrid(columns: columns, spacing: 5) { 39 | ForEach(category.keys, id: \.id) { key in 40 | CustomizeKeyView_1u(customizeKey: key) 41 | } 42 | } 43 | .padding() 44 | } 45 | .tabItem { 46 | Text(category.name) 47 | } 48 | .tag(category.name) 49 | } 50 | 51 | VStack { 52 | ScrollView(.vertical) { 53 | LazyVGrid(columns: columns, spacing: 5) { 54 | ForEach(filteredAllKeys, id: \.id) { key in 55 | CustomizeKeyView_1u(customizeKey: key) 56 | } 57 | } 58 | .padding() 59 | } 60 | 61 | } 62 | .tabItem { 63 | Text("All") 64 | } 65 | .tag("All") 66 | } 67 | 68 | if selectedTab == "All" { 69 | VStack { 70 | HStack { 71 | Spacer() 72 | // 検索バーを表示する 73 | TextField("Search in All Keys", text: $searchText) 74 | .background().cornerRadius(6) 75 | .frame(width: 150) 76 | .textFieldStyle(RoundedBorderTextFieldStyle()) 77 | .padding(.trailing, 10) 78 | .focused($internalSearchFieldFocus) 79 | .onSubmit{internalSearchFieldFocus = false} 80 | } 81 | 82 | Spacer() 83 | } 84 | // .onChange(of: externalSearchFieldFocuse) { oldValue, newValue in 85 | // internalSearchFieldFocus = newValue 86 | // } 87 | } 88 | } 89 | } 90 | } 91 | 92 | 93 | // CustomizeKey and CustomKeyDataSet structures remain the same 94 | //ビューを小分けしにたら処理が軽くなるんじゃないかと試したけど無意味でした 95 | 96 | //struct CustomizeKeyTabView: View { 97 | // let columns = [ 98 | // GridItem(.adaptive(minimum: 70, maximum: 200)) // 最小・最大幅を調整 99 | // ] 100 | // 101 | // var body: some View { 102 | // TabView { 103 | // ForEach(CustomKeyDataSet.allCategories, id: \.id) { category in 104 | // CustomizeCategoryView(category: category, columns: columns) 105 | // .tabItem { 106 | // Text(category.name) 107 | // } 108 | // } 109 | // } 110 | // } 111 | //} 112 | // 113 | //struct CustomizeCategoryView: View { 114 | // let category: CustomKeyCategory 115 | // let columns: [GridItem] 116 | // 117 | // var body: some View { 118 | // ScrollView(.vertical) { 119 | // CustomizeKeyGridView(keys: category.keys, columns: columns) 120 | // .padding() 121 | // } 122 | // } 123 | //} 124 | // 125 | //struct CustomizeKeyGridView: View { 126 | // let keys: [CustomizeKey] 127 | // let columns: [GridItem] 128 | // 129 | // var body: some View { 130 | // LazyVGrid(columns: columns, spacing: 5) { 131 | // ForEach(keys, id: \.id) { key in 132 | // CustomizeKeyItemView(customizeKey: key) 133 | // } 134 | // } 135 | // } 136 | //} 137 | // 138 | //struct CustomizeKeyItemView: View { 139 | // let customizeKey: CustomizeKey 140 | // 141 | // var body: some View { 142 | // CustomizeKeyView_1u(customizeKey: customizeKey) 143 | // } 144 | //} 145 | 146 | //#Preview { 147 | // CustomizeKeyTabView() 148 | //} 149 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/CustomizeKey/CustomizeKeyView_1u.swift: -------------------------------------------------------------------------------- 1 | ///CustomizeKeyクラスの定義とそのひとつ分のビューの定義。 2 | /// 3 | import SwiftUI 4 | import UniformTypeIdentifiers 5 | 6 | //書き換えデータをドラッグしていく元のキー。レイヤーキーなどもここに入るはず。 7 | final class CustomizeKey: Codable, Transferable, Identifiable { 8 | let id: UUID 9 | //まず、変更後の表示シンボルと、打たれる文字(辞書鍵になってるやつ) 10 | let layerKeyNumber: Int 11 | let afterDisplaySymbol: String 12 | let isUsingSFSymbol: Bool 13 | let afterKeyOutPut: String 14 | 15 | let isCustomized: Bool 16 | //修飾キー 17 | let tapWithModifier: Bool 18 | let tapWithShift: Bool 19 | let isTapIncludeShift: Bool//記号をドロップした後にDetail View側でシフトとかをトグルできないようにするためのブール値 20 | let tapWithControl: Bool 21 | let isTapIncludeControl: Bool 22 | let tapWithOption: Bool 23 | let isTapIncludeOption: Bool 24 | let tapWithCommand: Bool 25 | let isTapIncludeCommand: Bool 26 | 27 | let userCustomJSONEnabled: Bool 28 | let userCustomJSONContent: String 29 | 30 | let helpText: String? 31 | 32 | //簡易 33 | init( 34 | afterDisplaySymbol: String, 35 | afterKeyOutPut: String, 36 | isUsingSFSymbol:Bool = false, 37 | helpText: String? = nil, 38 | layerKeyNumber: Int = 0 39 | ) { 40 | self.id = UUID() 41 | self.layerKeyNumber = layerKeyNumber 42 | self.afterDisplaySymbol = afterDisplaySymbol 43 | self.isUsingSFSymbol = isUsingSFSymbol 44 | self.afterKeyOutPut = afterKeyOutPut 45 | 46 | self.isCustomized = true 47 | self.tapWithModifier = false 48 | 49 | self.tapWithShift = false 50 | self.isTapIncludeShift = false 51 | self.tapWithControl = false 52 | self.isTapIncludeControl = false 53 | self.tapWithOption = false 54 | self.isTapIncludeOption = false 55 | self.tapWithCommand = false 56 | self.isTapIncludeCommand = false 57 | 58 | self.userCustomJSONEnabled = false 59 | self.userCustomJSONContent = "" 60 | self.helpText = helpText 61 | } 62 | //全部入り 63 | init( 64 | id: UUID = UUID(), 65 | layerKeyNumber: Int = 0, 66 | afterDisplaySymbol: String, 67 | afterKeyOutPut: String, 68 | isCustomized: Bool = true, 69 | 70 | isTapWithModifier: Bool = false, 71 | tapWithShift: Bool = false, 72 | isTapIncludeShift: Bool = false, 73 | tapWithControl: Bool = false, 74 | isTapIncludeControl: Bool = false, 75 | tapWithOption: Bool = false, 76 | isTapIncludeOption: Bool = false, 77 | tapWithCommand: Bool = false, 78 | isTapIncludeCommand: Bool = false, 79 | 80 | userCustomJSONEnabled: Bool = false, 81 | userCustomJSONContent: String = "", 82 | isUsingSFSymbol:Bool = false, 83 | helpText: String? = nil 84 | 85 | ) { 86 | self.id = id 87 | self.layerKeyNumber = layerKeyNumber 88 | self.afterDisplaySymbol = afterDisplaySymbol 89 | self.afterKeyOutPut = afterKeyOutPut 90 | self.isCustomized = true 91 | 92 | self.tapWithModifier = isTapWithModifier 93 | self.tapWithShift = tapWithShift 94 | self.isTapIncludeShift = isTapIncludeShift 95 | self.tapWithControl = tapWithControl 96 | self.isTapIncludeControl = isTapIncludeControl 97 | self.tapWithOption = tapWithOption 98 | self.isTapIncludeOption = isTapIncludeOption 99 | self.tapWithCommand = tapWithCommand 100 | self.isTapIncludeCommand = isTapIncludeCommand 101 | 102 | self.userCustomJSONEnabled = userCustomJSONEnabled 103 | self.userCustomJSONContent = userCustomJSONContent 104 | self.isUsingSFSymbol = isUsingSFSymbol 105 | self.helpText = helpText 106 | } 107 | 108 | 109 | static var transferRepresentation: some TransferRepresentation { 110 | CodableRepresentation(for: CustomizeKey.self, contentType: .customizekey) 111 | } 112 | } 113 | 114 | extension UTType { 115 | static var customizekey: UTType { UTType(exportedAs: "com.example.customizekey")} 116 | } 117 | 118 | struct CustomizeKeyView_1u: View { 119 | let customizeKey: CustomizeKey 120 | private var backgroundColor: Color { 121 | if customizeKey.afterKeyOutPut == "layer1" { 122 | LayerColor.layer1.customizeKeyBackGroundColor 123 | } else if customizeKey.afterKeyOutPut == "layer2" { 124 | LayerColor.layer2.customizeKeyBackGroundColor 125 | } else if customizeKey.afterKeyOutPut == "layer3" { 126 | LayerColor.layer3.customizeKeyBackGroundColor 127 | } else if customizeKey.afterKeyOutPut == "layer4" { 128 | LayerColor.layer4.customizeKeyBackGroundColor 129 | } else if customizeKey.afterKeyOutPut == "layer5" { 130 | LayerColor.layer5.customizeKeyBackGroundColor 131 | } else if customizeKey.afterKeyOutPut == "layer6" { 132 | LayerColor.layer6.customizeKeyBackGroundColor 133 | } else if customizeKey.afterKeyOutPut == "layer7" { 134 | LayerColor.layer7.customizeKeyBackGroundColor 135 | } else if customizeKey.afterKeyOutPut == "layer8" { 136 | LayerColor.layer8.customizeKeyBackGroundColor 137 | } else { 138 | LayerColor.layer0.customizeKeyBackGroundColor 139 | } 140 | } 141 | var body: some View { 142 | ZStack { 143 | if customizeKey.isUsingSFSymbol { 144 | Image(systemName: customizeKey.afterDisplaySymbol) 145 | } else { 146 | Text(customizeKey.afterDisplaySymbol) 147 | } 148 | } 149 | .foregroundColor(.white) 150 | .font(.system(size: 20)) 151 | .frame(width: 65 - 65 * 0.07, height: 65 - 65 * 0.07) 152 | .background(backgroundColor.opacity(0.5)) 153 | .cornerRadius(65 * 0.07) 154 | .draggable(customizeKey) 155 | .help(customizeKey.helpText ?? "keycode: \(customizeKey.afterKeyOutPut)") 156 | } 157 | } 158 | 159 | #Preview { 160 | return CustomizeKeyView_1u(customizeKey: CustomizeKey(afterDisplaySymbol: "A", afterKeyOutPut: "A")) 161 | } 162 | 163 | 164 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/EnterCustomShapeView.swift: -------------------------------------------------------------------------------- 1 | ///エンターのカスタムシェイプの定義。 2 | 3 | import SwiftUI 4 | 5 | struct EnterShape_JIS: Shape { 6 | let frameValue: CGFloat 7 | private var paddingValue: CGFloat { 8 | frameValue * 0.07 9 | } 10 | private var roundValue: CGFloat { 11 | frameValue * 0.07 12 | } 13 | 14 | func path(in rect: CGRect) -> Path { 15 | Path { path in 16 | // スタートポイント(左上の角丸終わりから時計回りに描画) 17 | let startPoint = CGPoint(x: paddingValue + roundValue, y: paddingValue) 18 | // 1. 左上から右上の丸みの始まりまでのライン 19 | path.move(to: startPoint) 20 | path.addLine(to: CGPoint(x: rect.width - paddingValue - roundValue, y: paddingValue)) 21 | 22 | // 2. 右上の角の丸みを描画 23 | path.addArc(center: CGPoint(x: rect.width - paddingValue - roundValue, y: paddingValue + roundValue), 24 | radius: roundValue, 25 | startAngle: .degrees(270), 26 | endAngle: .degrees(0), 27 | clockwise: false) 28 | 29 | // 3. 右側のライン(右上から右下まで) 30 | path.addLine(to: CGPoint(x: rect.width - paddingValue, y: rect.height - paddingValue - roundValue)) 31 | 32 | // 4. 右下の丸みを描画 33 | path.addArc(center: CGPoint(x: rect.width - paddingValue - roundValue, y: rect.height - paddingValue - roundValue), 34 | radius: roundValue, 35 | startAngle: .degrees(0), 36 | endAngle: .degrees(90), 37 | clockwise: false) 38 | 39 | // 5. 下側のラインを描画 (エンターキー下部の水平ライン) 40 | path.addLine(to: CGPoint(x: rect.width / 6 + paddingValue + roundValue, y: rect.height - paddingValue)) 41 | 42 | // 6. 左下の角の丸みを描画 43 | path.addArc(center: CGPoint(x: rect.width / 6 + paddingValue + roundValue, y: rect.height - paddingValue - roundValue), 44 | radius: roundValue, 45 | startAngle: .degrees(90), 46 | endAngle: .degrees(180), 47 | clockwise: false) 48 | 49 | // 7. 左側のライン1本目を描画 50 | path.addLine(to: CGPoint(x: rect.width / 6 + paddingValue, y: rect.height / 2 - paddingValue + roundValue)) 51 | // 8. 左中央の丸みを描画 52 | path.addArc(center: CGPoint(x: rect.width / 6 + paddingValue - roundValue, y: rect.height / 2 - paddingValue + roundValue), 53 | radius: roundValue, 54 | startAngle: .degrees(0), 55 | endAngle: .degrees(-90), 56 | clockwise: true) 57 | // 9. 中央のラインを描画 58 | path.addLine(to: CGPoint(x: paddingValue + roundValue, y: rect.height / 2 - paddingValue)) 59 | 60 | // 10. 左下の角の丸みを描画 61 | path.addArc(center: CGPoint(x: paddingValue + roundValue, y: rect.height / 2 - paddingValue - roundValue), 62 | radius: roundValue, 63 | startAngle: .degrees(90), 64 | endAngle: .degrees(180), 65 | clockwise: false) 66 | // 11. 左側のライン2本目 67 | path.addLine(to: CGPoint(x: paddingValue, y: paddingValue + roundValue)) 68 | 69 | //12. 左上の丸みを描画 70 | path.addArc(center: CGPoint(x: paddingValue + roundValue, y: paddingValue + roundValue), 71 | radius: roundValue, 72 | startAngle: .degrees(180), 73 | endAngle: .degrees(270), 74 | clockwise: false) 75 | 76 | // パスを閉じる 77 | path.closeSubpath() 78 | } 79 | } 80 | } 81 | 82 | struct EnterShape_JIS_HighLight: Shape { 83 | let frameValue: CGFloat 84 | private var centerRoundValue: CGFloat { 85 | frameValue * 0.07 86 | } 87 | private var roundValue: CGFloat { 88 | frameValue * 0.14 89 | } 90 | 91 | func path(in rect: CGRect) -> Path { 92 | Path { path in 93 | // スタートポイント(左上の角丸終わりから時計回りに描画) 94 | let startPoint = CGPoint(x: roundValue, y: 0) 95 | // 1. 左上から右上の丸みの始まりまでのライン 96 | path.move(to: startPoint) 97 | path.addLine(to: CGPoint(x: rect.width - roundValue, y: 0)) 98 | 99 | // 2. 右上の角の丸みを描画 100 | path.addArc(center: CGPoint(x: rect.width - roundValue, y: roundValue), 101 | radius: roundValue, 102 | startAngle: .degrees(270), 103 | endAngle: .degrees(0), 104 | clockwise: false) 105 | 106 | // 3. 右側のライン(右上から右下まで) 107 | path.addLine(to: CGPoint(x: rect.width, y: rect.height - roundValue)) 108 | 109 | // 4. 右下の丸みを描画 110 | path.addArc(center: CGPoint(x: rect.width - roundValue, y: rect.height - roundValue), 111 | radius: roundValue, 112 | startAngle: .degrees(0), 113 | endAngle: .degrees(90), 114 | clockwise: false) 115 | 116 | // 5. 下側のラインを描画 (エンターキー下部の水平ライン) 117 | path.addLine(to: CGPoint(x: rect.width / 6 + roundValue, y: rect.height)) 118 | 119 | // 6. 左下の角の丸みを描画 120 | path.addArc(center: CGPoint(x: rect.width / 6 + roundValue, y: rect.height - roundValue), 121 | radius: roundValue, 122 | startAngle: .degrees(90), 123 | endAngle: .degrees(180), 124 | clockwise: false) 125 | 126 | // 7. 左側のライン1本目を描画 127 | path.addLine(to: CGPoint(x: rect.width / 6, y: rect.height / 2 + roundValue)) 128 | // 8. 左中央の丸みを描画 129 | path.addArc(center: CGPoint(x: rect.width / 6 - centerRoundValue, y: rect.height / 2 + centerRoundValue), 130 | radius: centerRoundValue, 131 | startAngle: .degrees(0), 132 | endAngle: .degrees(-90), 133 | clockwise: true) 134 | // 9. 中央のラインを描画 135 | path.addLine(to: CGPoint(x: roundValue, y: rect.height / 2)) 136 | 137 | // 10. 左下の角の丸みを描画 138 | path.addArc(center: CGPoint(x: roundValue, y: rect.height / 2 - roundValue), 139 | radius: roundValue, 140 | startAngle: .degrees(90), 141 | endAngle: .degrees(180), 142 | clockwise: false) 143 | // 11. 左側のライン2本目 144 | path.addLine(to: CGPoint(x: 0, y: roundValue)) 145 | 146 | //12. 左上の丸みを描画 147 | path.addArc(center: CGPoint(x: roundValue, y: roundValue), 148 | radius: roundValue, 149 | startAngle: .degrees(180), 150 | endAngle: .degrees(270), 151 | clockwise: false) 152 | 153 | // パスを閉じる 154 | path.closeSubpath() 155 | } 156 | } 157 | } 158 | 159 | struct EnterShape_UK: Shape { 160 | let frameValue: CGFloat 161 | private var paddingValue: CGFloat { 162 | frameValue * 0.07 163 | } 164 | private var roundValue: CGFloat { 165 | frameValue * 0.07 166 | } 167 | 168 | 169 | func path(in rect: CGRect) -> Path { 170 | Path { path in 171 | // スタートポイント(左上の角丸終わりから時計回りに描画) 172 | let startPoint = CGPoint(x: paddingValue + roundValue, y: paddingValue) 173 | // 1. 左上から右上の丸みの始まりまでのライン 174 | path.move(to: startPoint) 175 | path.addLine(to: CGPoint(x: rect.width - paddingValue - roundValue, y: paddingValue)) 176 | 177 | // 2. 右上の角の丸みを描画 178 | path.addArc(center: CGPoint(x: rect.width - paddingValue - roundValue, y: paddingValue + roundValue), 179 | radius: roundValue, 180 | startAngle: .degrees(270), 181 | endAngle: .degrees(0), 182 | clockwise: false) 183 | 184 | // 3. 右側のライン(右上から右下まで) 185 | path.addLine(to: CGPoint(x: rect.width - paddingValue, y: rect.height - paddingValue - roundValue)) 186 | 187 | // 4. 右下の丸みを描画 188 | path.addArc(center: CGPoint(x: rect.width - paddingValue - roundValue, y: rect.height - paddingValue - roundValue), 189 | radius: roundValue, 190 | startAngle: .degrees(0), 191 | endAngle: .degrees(90), 192 | clockwise: false) 193 | 194 | // 5. 下側のラインを描画 (エンターキー下部の水平ライン) 195 | path.addLine(to: CGPoint(x: rect.width / 4 + paddingValue + roundValue, y: rect.height - paddingValue)) 196 | 197 | // 6. 左下の角の丸みを描画 198 | path.addArc(center: CGPoint(x: rect.width / 4 + paddingValue + roundValue, y: rect.height - paddingValue - roundValue), 199 | radius: roundValue, 200 | startAngle: .degrees(90), 201 | endAngle: .degrees(180), 202 | clockwise: false) 203 | 204 | // 7. 左側のライン1本目を描画 205 | path.addLine(to: CGPoint(x: rect.width / 4 + paddingValue, y: rect.height / 2 - paddingValue + roundValue)) 206 | // 8. 左中央の丸みを描画 207 | path.addArc(center: CGPoint(x: rect.width / 4 + paddingValue - roundValue, y: rect.height / 2 - paddingValue + roundValue), 208 | radius: roundValue, 209 | startAngle: .degrees(0), 210 | endAngle: .degrees(-90), 211 | clockwise: true) 212 | // 9. 中央のラインを描画 213 | path.addLine(to: CGPoint(x: paddingValue + roundValue, y: rect.height / 2 - paddingValue)) 214 | 215 | // 10. 左下の角の丸みを描画 216 | path.addArc(center: CGPoint(x: paddingValue + roundValue, y: rect.height / 2 - paddingValue - roundValue), 217 | radius: roundValue, 218 | startAngle: .degrees(90), 219 | endAngle: .degrees(180), 220 | clockwise: false) 221 | // 11. 左側のライン2本目 222 | path.addLine(to: CGPoint(x: paddingValue, y: paddingValue + roundValue)) 223 | 224 | //12. 左上の丸みを描画 225 | path.addArc(center: CGPoint(x: paddingValue + roundValue, y: paddingValue + roundValue), 226 | radius: roundValue, 227 | startAngle: .degrees(180), 228 | endAngle: .degrees(270), 229 | clockwise: false) 230 | 231 | // パスを閉じる 232 | path.closeSubpath() 233 | } 234 | } 235 | } 236 | struct EnterShape_UK_HighLight: Shape { 237 | let frameValue: CGFloat 238 | private var centerRoundValue: CGFloat { 239 | frameValue * 0.07 240 | } 241 | private var roundValue: CGFloat { 242 | frameValue * 0.14 243 | } 244 | 245 | 246 | func path(in rect: CGRect) -> Path { 247 | Path { path in 248 | // スタートポイント(左上の角丸終わりから時計回りに描画) 249 | let startPoint = CGPoint(x: roundValue, y: 0) 250 | // 1. 左上から右上の丸みの始まりまでのライン 251 | path.move(to: startPoint) 252 | path.addLine(to: CGPoint(x: rect.width - roundValue, y: 0)) 253 | 254 | // 2. 右上の角の丸みを描画 255 | path.addArc(center: CGPoint(x: rect.width - roundValue, y: roundValue), 256 | radius: roundValue, 257 | startAngle: .degrees(270), 258 | endAngle: .degrees(0), 259 | clockwise: false) 260 | 261 | // 3. 右側のライン(右上から右下まで) 262 | path.addLine(to: CGPoint(x: rect.width, y: rect.height - roundValue)) 263 | 264 | // 4. 右下の丸みを描画 265 | path.addArc(center: CGPoint(x: rect.width - roundValue, y: rect.height - roundValue), 266 | radius: roundValue, 267 | startAngle: .degrees(0), 268 | endAngle: .degrees(90), 269 | clockwise: false) 270 | 271 | // 5. 下側のラインを描画 (エンターキー下部の水平ライン) 272 | path.addLine(to: CGPoint(x: rect.width / 4 + roundValue, y: rect.height)) 273 | 274 | // 6. 左下の角の丸みを描画 275 | path.addArc(center: CGPoint(x: rect.width / 4 + roundValue, y: rect.height - roundValue), 276 | radius: roundValue, 277 | startAngle: .degrees(90), 278 | endAngle: .degrees(180), 279 | clockwise: false) 280 | 281 | // 7. 左側のライン1本目を描画 282 | path.addLine(to: CGPoint(x: rect.width / 4, y: rect.height / 2 + roundValue)) 283 | // 8. 左中央の丸みを描画 284 | path.addArc(center: CGPoint(x: rect.width / 4 - centerRoundValue, y: rect.height / 2 + centerRoundValue), 285 | radius: centerRoundValue, 286 | startAngle: .degrees(0), 287 | endAngle: .degrees(-90), 288 | clockwise: true) 289 | // 9. 中央のラインを描画 290 | path.addLine(to: CGPoint(x: roundValue, y: rect.height / 2)) 291 | 292 | // 10. 左下の角の丸みを描画 293 | path.addArc(center: CGPoint(x: roundValue, y: rect.height / 2 - roundValue), 294 | radius: roundValue, 295 | startAngle: .degrees(90), 296 | endAngle: .degrees(180), 297 | clockwise: false) 298 | // 11. 左側のライン2本目 299 | path.addLine(to: CGPoint(x: 0, y: roundValue)) 300 | 301 | //12. 左上の丸みを描画 302 | path.addArc(center: CGPoint(x: roundValue, y: roundValue), 303 | radius: roundValue, 304 | startAngle: .degrees(180), 305 | endAngle: .degrees(270), 306 | clockwise: false) 307 | 308 | // パスを閉じる 309 | path.closeSubpath() 310 | } 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/ExportKeyboardView/CustomUTType.swift: -------------------------------------------------------------------------------- 1 | ///.staplerファイルの定義とロードとエンコードの処理 2 | /// 3 | 4 | import Foundation 5 | import UniformTypeIdentifiers 6 | import SwiftUI 7 | 8 | extension UTType { 9 | public static let stapler = UTType(exportedAs: "com.example.stapler") 10 | } 11 | 12 | func exportPreset(_ preset: Preset) { 13 | let savePanel = NSSavePanel() 14 | savePanel.allowedContentTypes = [.stapler] // カスタムUTType 15 | savePanel.nameFieldStringValue = "\(preset.presetName).stapler" 16 | savePanel.begin { response in 17 | if response == .OK, let url = savePanel.url { 18 | do { 19 | let jsonData = try JSONEncoder().encode(preset) // PresetをJSONにエンコード 20 | try jsonData.write(to: url) // ファイルに書き込み 21 | print("Preset saved to \(url)") 22 | NSWorkspace.shared.activateFileViewerSelecting([url]) 23 | } catch { 24 | print("Failed to save preset: \(error)") 25 | } 26 | } 27 | } 28 | } 29 | 30 | func loadPreset(completion: @escaping (Preset?) -> Void) { 31 | let openPanel = NSOpenPanel() 32 | // openPanel.allowedContentTypes = [.stapler]//ここうまく動かない。下のパターンでもだめ。何が原因か探る必要あり。 33 | // openPanel.allowedFileTypes = ["stapeler"] 34 | openPanel.begin { response in 35 | if response == .OK, let url = openPanel.url { 36 | do { 37 | let jsonData = try Data(contentsOf: url) 38 | let loadedPreset = try JSONDecoder().decode(Preset.self, from: jsonData) 39 | print("Preset loaded: \(loadedPreset)") 40 | completion(loadedPreset) // 成功時にPresetを返す 41 | } catch { 42 | print("Failed to load preset: \(error)") 43 | completion(nil) // エラー時にはnilを返す 44 | } 45 | } else { 46 | completion(nil) // キャンセルされた場合 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/ExportKeyboardView/ExportSheetView.swift: -------------------------------------------------------------------------------- 1 | ///出力するときのシート用のビュー。 2 | 3 | 4 | import SwiftUI 5 | import UniformTypeIdentifiers 6 | import PDFKit 7 | 8 | 9 | struct CustomShapeButtonStyle: ButtonStyle { 10 | let shape: S 11 | let fillColor: Color 12 | let frameSize: CGSize 13 | 14 | func makeBody(configuration: Configuration) -> some View { 15 | shape 16 | .fill(fillColor) 17 | .frame(width: frameSize.width, height: frameSize.height) 18 | .overlay( 19 | configuration.label 20 | ) 21 | .scaleEffect(configuration.isPressed ? 0.9 : 1.0) // 押した時のアニメーション 22 | // .animation(.easeInOut, value: configuration.isPressed) 23 | } 24 | } 25 | 26 | struct ExportSheetView: View { 27 | let preset: Preset 28 | let keySize: CGFloat = 65 29 | @State var showingAlert: Bool = false 30 | @State var alertMessage: String = "" 31 | @Environment(\.dismiss) private var dismiss 32 | 33 | @State private var showSuccessCheckMark_otherFile = false 34 | @State private var showSuccessCheckMark_JSONFile = false 35 | @State private var animateScale = false 36 | 37 | var body: some View { 38 | ZStack { 39 | mainSheetView 40 | .alert(isPresented: $showingAlert) { 41 | Alert(title: Text("エクスポート結果"), message: Text(alertMessage), dismissButton: .default(Text("OK"))) 42 | } 43 | // 成功時のチェックマーク表示 44 | if showSuccessCheckMark_otherFile { 45 | SuccessCheckMarkView_otherFile(isPresented: $showSuccessCheckMark_otherFile, animateScale: $animateScale) 46 | } 47 | if showSuccessCheckMark_JSONFile { 48 | SuccessCheckMarkView_JSON(isPresented: $showSuccessCheckMark_JSONFile, animateScale: $animateScale) 49 | } 50 | } 51 | .animation(.easeInOut, value: showSuccessCheckMark_otherFile) 52 | .animation(.easeInOut, value: showSuccessCheckMark_JSONFile) 53 | } 54 | 55 | private var mainSheetView: some View { 56 | VStack(spacing: 0) { 57 | ZStack { 58 | HStack { 59 | Button(action: {dismiss()}) { 60 | Image(systemName: "xmark.circle") 61 | .font(.system(size: 35)) 62 | } 63 | .buttonStyle(CustomShapeButtonStyle( 64 | shape: Circle(), 65 | fillColor: .clear, 66 | frameSize: CGSize(width: 40, height: 40))) 67 | .padding() 68 | Spacer() 69 | } 70 | HStack { 71 | Spacer() 72 | Text("\(preset.presetName)").font(.largeTitle) 73 | Spacer() 74 | } 75 | VStack { 76 | Spacer() 77 | HStack{ 78 | Spacer() 79 | Text("VendorID: \(preset.vendorID)") 80 | Text("ProductID: \(preset.productID)") 81 | Divider().frame(height: 10) 82 | Text("KeyCode Region: \(preset.keyCodeRegion)") 83 | } 84 | .font(.caption) 85 | .padding() 86 | } 87 | } 88 | Divider() 89 | // プリセットを受け取って、レイヤーまで一覧できるキーボードビュー 90 | KeyboardView_AllLayer(keySize: keySize, preset: preset) 91 | Divider() 92 | HStack { 93 | Menu { 94 | Button { 95 | exportPNG_AllLayer() 96 | } label: { 97 | Label("Export All Layer as PNG", systemImage: "photo") 98 | } 99 | Button { 100 | exportPDF_AllLayer() 101 | } label: { 102 | Label("Export All Layer as PDF", systemImage: "photo") 103 | } 104 | Button { 105 | exportPDF_EachLayer() 106 | } label: { 107 | Label("Export EachLayer as PDF", systemImage: "photo.stack") 108 | } 109 | } label: { 110 | Label("Export Image", systemImage: "photo") 111 | .padding() 112 | } 113 | Button{ 114 | exportPreset(preset) 115 | } label: { 116 | Label("Share Preset as stapler", systemImage: "square.and.arrow.up") 117 | } 118 | Button{ 119 | exportJSON() 120 | } label: { 121 | Label ("Export as json", systemImage: "document.badge.gearshape") 122 | } 123 | 124 | } 125 | .padding() 126 | } 127 | } 128 | 129 | // 共通のエクスポート結果表示処理 130 | func handleExportResult(success: Bool, message: String? = nil, fileURL: URL? = nil) { 131 | if success { 132 | showExportSuccessMessage(fileURL: fileURL) 133 | } else { 134 | showExportFailureMessage(errorMessage: message) 135 | } 136 | } 137 | func exportJSON() { 138 | JSONExporter.exportJSON(preset, showingAlert: $showingAlert, alertMessage: $alertMessage, animationBool: $showSuccessCheckMark_JSONFile) 139 | } 140 | 141 | func exportPNG_AllLayer() { 142 | let allLayer = KeyboardView_AllLayer(keySize: 100, preset: preset) 143 | let renderer = ImageRenderer(content: allLayer) 144 | 145 | let savePanel = NSSavePanel() 146 | savePanel.allowedContentTypes = [UTType.png] 147 | savePanel.nameFieldStringValue = "\(preset.presetName).png" 148 | 149 | savePanel.begin { response in 150 | if response == .OK, let url = savePanel.url { 151 | if let imageData = renderer.nsImage?.tiffRepresentation, 152 | let bitmap = NSBitmapImageRep(data: imageData), 153 | let pngData = bitmap.representation(using: .png, properties: [:]) { 154 | do { 155 | try pngData.write(to: url) 156 | handleExportResult(success: true, fileURL: url) 157 | } catch { 158 | handleExportResult(success: false, message: error.localizedDescription) 159 | } 160 | } else { 161 | handleExportResult(success: false, message: "画像の生成に失敗しました。") 162 | } 163 | } else { 164 | showExportCancelledMessage() 165 | } 166 | } 167 | } 168 | 169 | // PDF出力の処理 170 | func exportPDF_AllLayer() { 171 | let allLayer = KeyboardView_AllLayer(keySize: keySize, preset: preset) 172 | let renderer = ImageRenderer(content: allLayer) 173 | 174 | let savePanel = NSSavePanel() 175 | savePanel.allowedContentTypes = [UTType.pdf] 176 | savePanel.nameFieldStringValue = "\(preset.presetName).pdf" 177 | 178 | savePanel.begin { response in 179 | if response == .OK, let url = savePanel.url { 180 | renderer.render { size, context in 181 | var box = CGRect(x: 0, y: 0, width: size.width, height: size.height) 182 | guard let pdfContext = CGContext(url as CFURL, mediaBox: &box, nil) else { 183 | return 184 | } 185 | 186 | pdfContext.beginPDFPage(nil) 187 | context(pdfContext) 188 | pdfContext.endPDFPage() 189 | pdfContext.closePDF() 190 | 191 | handleExportResult(success: true, fileURL: url) 192 | } 193 | } else { 194 | showExportCancelledMessage() 195 | } 196 | } 197 | } 198 | func exportPDF_EachLayer() { 199 | // 各レイヤーのビューを作成 200 | let eachLayer012 = VStack { 201 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer0).padding(.vertical, 10) 202 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer1).padding(.vertical, 10) 203 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer2).padding(.vertical, 10) 204 | } 205 | let eachLayer345 = VStack { 206 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer3).padding(.vertical, 10) 207 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer4).padding(.vertical, 10) 208 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer5).padding(.vertical, 10) 209 | } 210 | let eachLayer678 = VStack { 211 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer6).padding(.vertical, 10) 212 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer7).padding(.vertical, 10) 213 | KeyboardView_EachLayer(keySize: 100, preset: preset, layer: preset.layer8).padding(.vertical, 10) 214 | } 215 | // PDFの保存パネル 216 | let savePanel = NSSavePanel() 217 | savePanel.allowedContentTypes = [UTType.pdf] 218 | savePanel.nameFieldStringValue = "\(preset.presetName)_forEachLayer.pdf" 219 | 220 | savePanel.begin { response in 221 | if response == .OK, let url = savePanel.url { 222 | // PDFのレンダリング処理を開始 223 | let renderers = [ 224 | ImageRenderer(content: eachLayer012), 225 | ImageRenderer(content: eachLayer345), 226 | ImageRenderer(content: eachLayer678) 227 | 228 | ] 229 | 230 | // PDFデータの準備 231 | let pdfData = NSMutableData() 232 | let pdfConsumer = CGDataConsumer(data: pdfData as CFMutableData)! 233 | 234 | // 最初のレイヤーのサイズを取得してmediaBoxを設定 235 | var initialSize: CGSize = .zero 236 | renderers.first?.render { size, _ in 237 | initialSize = size 238 | } 239 | var mediaBox = CGRect(origin: .zero, size: initialSize) 240 | 241 | guard let pdfContext = CGContext(consumer: pdfConsumer, mediaBox: &mediaBox, nil) else { 242 | showExportFailureMessage(errorMessage: "Failed to create PDF context") 243 | return 244 | } 245 | 246 | for (index, renderer) in renderers.enumerated() { 247 | renderer.render { size, context in 248 | let box = CGRect(origin: .zero, size: size) 249 | print("Layer \(index) rendered size: \(size)") 250 | 251 | // 新しいPDFページの開始(各ページに正確なサイズを設定) 252 | let pageInfo = [kCGPDFContextMediaBox: box] as CFDictionary 253 | pdfContext.beginPDFPage(pageInfo) 254 | context(pdfContext) // 各レイヤーのビューをレンダリング 255 | pdfContext.endPDFPage() // ページを閉じる 256 | } 257 | } 258 | pdfContext.closePDF() 259 | 260 | // PDFデータをファイルに保存 261 | do { 262 | try pdfData.write(to: url) 263 | showExportSuccessMessage(fileURL: url) // 成功時の処理 264 | } catch { 265 | showExportFailureMessage(errorMessage: "Failed to write PDF: \(error)") // ファイル保存中のエラー処理 266 | } 267 | } else { 268 | showExportCancelledMessage() // ユーザーがキャンセルした場合の処理 269 | } 270 | } 271 | } 272 | // 成功時のメッセージ表示 273 | func showExportSuccessMessage(fileURL: URL?) { 274 | print("ファイルが正常に保存されました。") 275 | // alertMessage = "ファイルが正常に保存されました。" 276 | // showingAlert = true 277 | withAnimation { 278 | showSuccessCheckMark_otherFile = true 279 | } 280 | // クイックルックやFinderで開く 281 | if let fileURL = fileURL { 282 | NSWorkspace.shared.activateFileViewerSelecting([fileURL]) 283 | } 284 | } 285 | 286 | // 失敗時のメッセージ表示 287 | func showExportFailureMessage(errorMessage: String?) { 288 | alertMessage = errorMessage ?? "エクスポート中にエラーが発生しました。" 289 | showingAlert = true 290 | print(alertMessage) 291 | } 292 | 293 | // キャンセル時のメッセージ表示 294 | func showExportCancelledMessage() { 295 | print("保存がキャンセルされました。") 296 | } 297 | } 298 | 299 | 300 | struct SuccessCheckMarkView_JSON: View { 301 | @Binding var isPresented: Bool 302 | @Binding var animateScale: Bool 303 | var body: some View { 304 | 305 | 306 | VStack(spacing: 20) { 307 | Image(systemName: "checkmark.circle") 308 | .symbolEffect(.bounce.up, options: .repeat(3), isActive: isPresented) 309 | .font(.system(size: 60)) 310 | .foregroundColor(.green) 311 | } 312 | .padding() 313 | .frame(width: 300, height: 200) 314 | .scaleEffect(animateScale ? 1.0 : 0.5) // 初期状態と表示後の大きさ 315 | .onAppear { 316 | withAnimation/*(.easeInOut(duration: 0.3)) */{ 317 | animateScale = true // 表示と同時にスケールアップ 318 | } 319 | // playNotificationSound() // 通知音を鳴らす 320 | playCustomSound() 321 | autoDismiss() // 一定時間後に自動で非表示 322 | } 323 | .onDisappear { 324 | animateScale = false // アラートが非表示になった時にリセット 325 | } 326 | } 327 | 328 | 329 | // 一定時間後にアラートを自動的に非表示にする関数 330 | private func autoDismiss() { 331 | DispatchQueue.main.asyncAfter(deadline: .now() + 3) { 332 | isPresented = false 333 | } 334 | } 335 | 336 | // 通知音を鳴らす関数 337 | private func playNotificationSound() { 338 | let sound = NSSound(named: NSSound.Name("Submarine")) // システム通知音を指定 339 | sound?.play() // サウンドを再生 340 | } 341 | // カスタム音声ファイルを再生する関数 342 | private func playCustomSound() { 343 | if let soundURL = Bundle.main.url(forResource: "Success1", withExtension: "wav") { // "customSound.mp3"ファイルを指定 344 | let sound = NSSound(contentsOf: soundURL, byReference: false) // ファイルパスからサウンドをロード 345 | sound?.play() // カスタムサウンドを再生 346 | } else { 347 | print("カスタムサウンドファイルが見つかりませんでした") 348 | } 349 | } 350 | } 351 | 352 | 353 | struct SuccessCheckMarkView_otherFile: View { 354 | @Binding var isPresented: Bool 355 | @Binding var animateScale: Bool 356 | var body: some View { 357 | 358 | 359 | VStack(spacing: 20) { 360 | Image(systemName: "checkmark.circle") 361 | .symbolEffect(.bounce.up, options: .repeat(3), isActive: isPresented) 362 | .font(.system(size: 60)) 363 | .foregroundColor(.green) 364 | } 365 | .padding() 366 | .frame(width: 300, height: 200) 367 | .scaleEffect(animateScale ? 1.0 : 0.5) // 初期状態と表示後の大きさ 368 | .onAppear { 369 | withAnimation/*(.easeInOut(duration: 0.3)) */{ 370 | animateScale = true // 表示と同時にスケールアップ 371 | } 372 | 373 | autoDismiss() // 一定時間後に自動で非表示 374 | } 375 | .onDisappear { 376 | animateScale = false // アラートが非表示になった時にリセット 377 | } 378 | } 379 | 380 | 381 | // 一定時間後にアラートを自動的に非表示にする関数 382 | private func autoDismiss() { 383 | DispatchQueue.main.asyncAfter(deadline: .now() + 3) { 384 | isPresented = false 385 | } 386 | } 387 | } 388 | 389 | 390 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/ExportKeyboardView/Success1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Keyboard/ExportKeyboardView/Success1.wav -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/ExportKeyboardView/Success2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9dpbQ/Stapler-mini-v0/7939b748c37213fb0e04f4bdd383523d72949760/Stapler-mini-v0/Stapler-mini-v0/Keyboard/ExportKeyboardView/Success2.wav -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/KeyboardView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct BuiltInKeyboardLayerView_US: View { 4 | @Binding var selectedKeyboardKey: KeyboardKey 5 | let keySize: CGFloat 6 | var layer: [KeyboardKey] 7 | 8 | var body: some View { 9 | 10 | VStack(alignment: .leading, spacing: 0) { 11 | HStack (spacing: 0) {//Row1 12 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[0], unitSize: 1.5, baseSize: keySize) 13 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[1], unitSize: 1, baseSize: keySize) 14 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[2], unitSize: 1, baseSize: keySize) 15 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[3], unitSize: 1, baseSize: keySize) 16 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[4], unitSize: 1, baseSize: keySize) 17 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[5], unitSize: 1, baseSize: keySize) 18 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[6], unitSize: 1, baseSize: keySize) 19 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[7], unitSize: 1, baseSize: keySize) 20 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[8], unitSize: 1, baseSize: keySize) 21 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[9], unitSize: 1, baseSize: keySize) 22 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[10], unitSize: 1, baseSize: keySize) 23 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[11], unitSize: 1, baseSize: keySize) 24 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[12], unitSize: 1, baseSize: keySize) 25 | 26 | 27 | } 28 | HStack (spacing: 0) {//Row2 29 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[13], unitSize: 1, baseSize: keySize) 30 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[14], unitSize: 1, baseSize: keySize) 31 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[15], unitSize: 1, baseSize: keySize) 32 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[16], unitSize: 1, baseSize: keySize) 33 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[17], unitSize: 1, baseSize: keySize) 34 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[18], unitSize: 1, baseSize: keySize) 35 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[19], unitSize: 1, baseSize: keySize) 36 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[20], unitSize: 1, baseSize: keySize) 37 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[21], unitSize: 1, baseSize: keySize) 38 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[22], unitSize: 1, baseSize: keySize) 39 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[23], unitSize: 1, baseSize: keySize) 40 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[24], unitSize: 1, baseSize: keySize) 41 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[25], unitSize: 1, baseSize: keySize) 42 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[26], unitSize: 1.5, baseSize: keySize) 43 | 44 | 45 | 46 | 47 | } 48 | HStack (spacing: 0) {//Row3 49 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[27], unitSize: 1.5, baseSize: keySize) 50 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[28], unitSize: 1, baseSize: keySize) 51 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[29], unitSize: 1, baseSize: keySize) 52 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[30], unitSize: 1, baseSize: keySize) 53 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[31], unitSize: 1, baseSize: keySize) 54 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[32], unitSize: 1, baseSize: keySize) 55 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[33], unitSize: 1, baseSize: keySize) 56 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[34], unitSize: 1, baseSize: keySize) 57 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[35], unitSize: 1, baseSize: keySize) 58 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[36], unitSize: 1, baseSize: keySize) 59 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[37], unitSize: 1, baseSize: keySize) 60 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[38], unitSize: 1, baseSize: keySize) 61 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[39], unitSize: 1, baseSize: keySize) 62 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[40], unitSize: 1, baseSize: keySize) 63 | 64 | 65 | 66 | } 67 | HStack (spacing: 0) {//Row4 68 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[41], unitSize: 1.75, baseSize: keySize) 69 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[42], unitSize: 1, baseSize: keySize) 70 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[43], unitSize: 1, baseSize: keySize) 71 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[44], unitSize: 1, baseSize: keySize) 72 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[45], unitSize: 1, baseSize: keySize) 73 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[46], unitSize: 1, baseSize: keySize) 74 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[47], unitSize: 1, baseSize: keySize) 75 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[48], unitSize: 1, baseSize: keySize) 76 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[49], unitSize: 1, baseSize: keySize) 77 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[50], unitSize: 1, baseSize: keySize) 78 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[51], unitSize: 1, baseSize: keySize) 79 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[52], unitSize: 1, baseSize: keySize) 80 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[53], unitSize: 1.75, baseSize: keySize) 81 | 82 | 83 | } 84 | HStack (spacing: 0) {//Row5 85 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[54], unitSize: 2.25, baseSize: keySize) 86 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[55], unitSize: 1, baseSize: keySize) 87 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[56], unitSize: 1, baseSize: keySize) 88 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[57], unitSize: 1, baseSize: keySize) 89 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[58], unitSize: 1, baseSize: keySize) 90 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[59], unitSize: 1, baseSize: keySize) 91 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[60], unitSize: 1, baseSize: keySize) 92 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[61], unitSize: 1, baseSize: keySize) 93 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[62], unitSize: 1, baseSize: keySize) 94 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[63], unitSize: 1, baseSize: keySize) 95 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[64], unitSize: 1, baseSize: keySize) 96 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[65], unitSize: 2.25, baseSize: keySize) 97 | 98 | } 99 | HStack (spacing: 0) {//Row6 100 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[66], unitSize: 1, baseSize: keySize) 101 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[67], unitSize: 1, baseSize: keySize) 102 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[68], unitSize: 1, baseSize: keySize) 103 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[69], unitSize: 1.25, baseSize: keySize) 104 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[70], unitSize: 5, baseSize: keySize) 105 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[71], unitSize: 1.25, baseSize: keySize) 106 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[72], unitSize: 1, baseSize: keySize) 107 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[73], unitSize: 1, baseSize: keySize) 108 | VStack (spacing: 0) {//ここにarrowの上下がくるなぁ〜専用のビューを作らないとダメだね 109 | KeyboardKeyView_arrow(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[74], unitSize: 1, baseSize: keySize) 110 | KeyboardKeyView_arrow(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[75], unitSize: 1, baseSize: keySize) 111 | } 112 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[76], unitSize: 1, baseSize: keySize) 113 | } 114 | } 115 | } 116 | } 117 | 118 | //#Preview { 119 | // let preset = Preset(presetName: "test", keyboardLayout: KeyboardLayout.US) 120 | // @State var selected = KeyboardKey(beforeDisplaySymbol: "1", beforeKeyOutPut: "2") 121 | // BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selected ,layer: preset.layer0) 122 | //} 123 | 124 | struct BuiltInKeyboardLayerView_JIS: View { 125 | @Binding var selectedKeyboardKey: KeyboardKey 126 | let keySize: CGFloat 127 | var layer: [KeyboardKey] 128 | var body: some View { 129 | ZStack { 130 | VStack(alignment: .trailing ,spacing: 0) { 131 | Spacer() 132 | HStack (spacing: 0){ 133 | Spacer().frame(width: keySize * 13.25 - keySize * 0.07 * 4 + keySize * 0.07 / 2 ) 134 | KeyboardKeyView_enter_JIS(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[53], baseSize: keySize) 135 | } 136 | Spacer() 137 | } 138 | VStack(alignment: .leading ,spacing: 0) { 139 | HStack (spacing: 0) {//Row1 140 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[0], unitSize: 1.5, baseSize: keySize) 141 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[1], unitSize: 1, baseSize: keySize) 142 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[2], unitSize: 1, baseSize: keySize) 143 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[3], unitSize: 1, baseSize: keySize) 144 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[4], unitSize: 1, baseSize: keySize) 145 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[5], unitSize: 1, baseSize: keySize) 146 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[6], unitSize: 1, baseSize: keySize) 147 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[7], unitSize: 1, baseSize: keySize) 148 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[8], unitSize: 1, baseSize: keySize) 149 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[9], unitSize: 1, baseSize: keySize) 150 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[10], unitSize: 1, baseSize: keySize) 151 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[11], unitSize: 1, baseSize: keySize) 152 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[12], unitSize: 1, baseSize: keySize) 153 | 154 | 155 | } 156 | HStack (spacing: 0) {//Row2 157 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[13], unitSize: 1.25, baseSize: keySize) 158 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[14], unitSize: 1, baseSize: keySize) 159 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[15], unitSize: 1, baseSize: keySize) 160 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[16], unitSize: 1, baseSize: keySize) 161 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[17], unitSize: 1, baseSize: keySize) 162 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[18], unitSize: 1, baseSize: keySize) 163 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[19], unitSize: 1, baseSize: keySize) 164 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[20], unitSize: 1, baseSize: keySize) 165 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[21], unitSize: 1, baseSize: keySize) 166 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[22], unitSize: 1, baseSize: keySize) 167 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[23], unitSize: 1, baseSize: keySize) 168 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[24], unitSize: 1, baseSize: keySize) 169 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[25], unitSize: 1, baseSize: keySize) 170 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[26], unitSize: 1.25, baseSize: keySize)//BS 171 | 172 | 173 | } 174 | HStack (spacing: 0) {//Row3 175 | 176 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[27], unitSize: 1, baseSize: keySize) 177 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[28], unitSize: 1, baseSize: keySize) 178 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[29], unitSize: 1, baseSize: keySize) 179 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[30], unitSize: 1, baseSize: keySize) 180 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[31], unitSize: 1, baseSize: keySize) 181 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[32], unitSize: 1, baseSize: keySize) 182 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[33], unitSize: 1, baseSize: keySize) 183 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[34], unitSize: 1, baseSize: keySize) 184 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[35], unitSize: 1, baseSize: keySize) 185 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[36], unitSize: 1, baseSize: keySize) 186 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[37], unitSize: 1, baseSize: keySize) 187 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[38], unitSize: 1, baseSize: keySize) 188 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[39], unitSize: 1, baseSize: keySize)//「 189 | 190 | 191 | 192 | 193 | } 194 | HStack (spacing: 0) {//Row4 195 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[40], unitSize: 1.25, baseSize: keySize) 196 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[41], unitSize: 1, baseSize: keySize) 197 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[42], unitSize: 1, baseSize: keySize) 198 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[43], unitSize: 1, baseSize: keySize) 199 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[44], unitSize: 1, baseSize: keySize) 200 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[45], unitSize: 1, baseSize: keySize) 201 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[46], unitSize: 1, baseSize: keySize) 202 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[47], unitSize: 1, baseSize: keySize) 203 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[48], unitSize: 1, baseSize: keySize) 204 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[49], unitSize: 1, baseSize: keySize) 205 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[50], unitSize: 1, baseSize: keySize) 206 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[51], unitSize: 1, baseSize: keySize) 207 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[52], unitSize: 1, baseSize: keySize) 208 | // KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[53], unitSize: 1.25)//エンター 209 | 210 | 211 | } 212 | HStack (spacing: 0) {//Row5 213 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[54], unitSize: 1.75, baseSize: keySize) 214 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[55], unitSize: 1, baseSize: keySize) 215 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[56], unitSize: 1, baseSize: keySize) 216 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[57], unitSize: 1, baseSize: keySize) 217 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[58], unitSize: 1, baseSize: keySize) 218 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[59], unitSize: 1, baseSize: keySize) 219 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[60], unitSize: 1, baseSize: keySize) 220 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[61], unitSize: 1, baseSize: keySize) 221 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[62], unitSize: 1, baseSize: keySize) 222 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[63], unitSize: 1, baseSize: keySize) 223 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[64], unitSize: 1, baseSize: keySize) 224 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[65], unitSize: 1, baseSize: keySize) 225 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[66], unitSize: 1.75, baseSize: keySize) 226 | 227 | 228 | 229 | } 230 | HStack (spacing: 0) {//Row6 231 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[67], unitSize: 1, baseSize: keySize) 232 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[68], unitSize: 1, baseSize: keySize) 233 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[69], unitSize: 1.25, baseSize: keySize) 234 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[70], unitSize: 1.25, baseSize: keySize) 235 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[71], unitSize: 3.5, baseSize: keySize) 236 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[72], unitSize: 1.25, baseSize: keySize) 237 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[73], unitSize: 1.25, baseSize: keySize) 238 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[74], unitSize: 1, baseSize: keySize) 239 | 240 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[75], unitSize: 1, baseSize: keySize) 241 | VStack (spacing: 0) { 242 | KeyboardKeyView_arrow(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[76], unitSize: 1, baseSize: keySize) 243 | KeyboardKeyView_arrow(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[77], unitSize: 1, baseSize: keySize) 244 | } 245 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[78], unitSize: 1, baseSize: keySize) 246 | } 247 | } 248 | } 249 | } 250 | } 251 | 252 | //#Preview { 253 | // let preset = Preset(presetName: "test", keyboardLayout: KeyboardLayout.JIS) 254 | // @State var selected = KeyboardKey(beforeDisplaySymbol: "1", beforeKeyOutPut: "2") 255 | // BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selected, keySize: 75 ,layer: preset.layer0) 256 | //} 257 | 258 | struct BuiltInKeyboardLayerView_UK: View { 259 | @Binding var selectedKeyboardKey: KeyboardKey 260 | let keySize: CGFloat 261 | var layer: [KeyboardKey] 262 | 263 | var body: some View { 264 | ZStack { 265 | VStack(alignment: .trailing ,spacing: 0) { 266 | Spacer() 267 | HStack (spacing: 0){ 268 | Spacer().frame(width: keySize * 13.75 - keySize * 0.07 * 4 + keySize * 0.07 / 2) 269 | KeyboardKeyView_enter_UK(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[53], baseSize: keySize) 270 | } 271 | Spacer() 272 | } 273 | VStack(alignment: .leading, spacing: 0) { 274 | HStack (spacing: 0) {//Row1 275 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[0], unitSize: 1.5, baseSize: keySize) 276 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[1], unitSize: 1, baseSize: keySize) 277 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[2], unitSize: 1, baseSize: keySize) 278 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[3], unitSize: 1, baseSize: keySize) 279 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[4], unitSize: 1, baseSize: keySize) 280 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[5], unitSize: 1, baseSize: keySize) 281 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[6], unitSize: 1, baseSize: keySize) 282 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[7], unitSize: 1, baseSize: keySize) 283 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[8], unitSize: 1, baseSize: keySize) 284 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[9], unitSize: 1, baseSize: keySize) 285 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[10], unitSize: 1, baseSize: keySize) 286 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[11], unitSize: 1, baseSize: keySize) 287 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[12], unitSize: 1, baseSize: keySize) 288 | 289 | 290 | } 291 | HStack (spacing: 0) {//Row2 292 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[13], unitSize: 1, baseSize: keySize) 293 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[14], unitSize: 1, baseSize: keySize) 294 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[15], unitSize: 1, baseSize: keySize) 295 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[16], unitSize: 1, baseSize: keySize) 296 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[17], unitSize: 1, baseSize: keySize) 297 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[18], unitSize: 1, baseSize: keySize) 298 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[19], unitSize: 1, baseSize: keySize) 299 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[20], unitSize: 1, baseSize: keySize) 300 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[21], unitSize: 1, baseSize: keySize) 301 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[22], unitSize: 1, baseSize: keySize) 302 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[23], unitSize: 1, baseSize: keySize) 303 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[24], unitSize: 1, baseSize: keySize) 304 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[25], unitSize: 1, baseSize: keySize) 305 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[26], unitSize: 1.5, baseSize: keySize) 306 | } 307 | HStack (spacing: 0) {//Row3 308 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[27], unitSize: 1.5, baseSize: keySize) 309 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[28], unitSize: 1, baseSize: keySize) 310 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[29], unitSize: 1, baseSize: keySize) 311 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[30], unitSize: 1, baseSize: keySize) 312 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[31], unitSize: 1, baseSize: keySize) 313 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[32], unitSize: 1, baseSize: keySize) 314 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[33], unitSize: 1, baseSize: keySize) 315 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[34], unitSize: 1, baseSize: keySize) 316 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[35], unitSize: 1, baseSize: keySize) 317 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[36], unitSize: 1, baseSize: keySize) 318 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[37], unitSize: 1, baseSize: keySize) 319 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[38], unitSize: 1, baseSize: keySize) 320 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[39], unitSize: 1, baseSize: keySize) 321 | 322 | 323 | 324 | } 325 | HStack (spacing: 0) {//Row4 326 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[40], unitSize: 1.75, baseSize: keySize) 327 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[41], unitSize: 1, baseSize: keySize) 328 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[42], unitSize: 1, baseSize: keySize) 329 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[43], unitSize: 1, baseSize: keySize) 330 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[44], unitSize: 1, baseSize: keySize) 331 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[45], unitSize: 1, baseSize: keySize) 332 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[46], unitSize: 1, baseSize: keySize) 333 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[47], unitSize: 1, baseSize: keySize) 334 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[48], unitSize: 1, baseSize: keySize) 335 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[49], unitSize: 1, baseSize: keySize) 336 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[50], unitSize: 1, baseSize: keySize) 337 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[51], unitSize: 1, baseSize: keySize) 338 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[52], unitSize: 1, baseSize: keySize) 339 | 340 | } 341 | HStack (spacing: 0) {//Row5 342 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[54], unitSize: 1.25, baseSize: keySize) 343 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[55], unitSize: 1, baseSize: keySize) 344 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[56], unitSize: 1, baseSize: keySize) 345 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[57], unitSize: 1, baseSize: keySize) 346 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[58], unitSize: 1, baseSize: keySize) 347 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[59], unitSize: 1, baseSize: keySize) 348 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[60], unitSize: 1, baseSize: keySize) 349 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[61], unitSize: 1, baseSize: keySize) 350 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[62], unitSize: 1, baseSize: keySize) 351 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[63], unitSize: 1, baseSize: keySize) 352 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[64], unitSize: 1, baseSize: keySize) 353 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[65], unitSize: 1, baseSize: keySize) 354 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[66], unitSize: 2.25, baseSize: keySize) 355 | 356 | 357 | } 358 | HStack (spacing: 0) {//Row6 359 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[67], unitSize: 1, baseSize: keySize) 360 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[68], unitSize: 1, baseSize: keySize) 361 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[69], unitSize: 1, baseSize: keySize) 362 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[70], unitSize: 1.25, baseSize: keySize) 363 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[71], unitSize: 5, baseSize: keySize) 364 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[72], unitSize: 1.25, baseSize: keySize) 365 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[73], unitSize: 1, baseSize: keySize) 366 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[74], unitSize: 1, baseSize: keySize) 367 | VStack(spacing: 0) { 368 | KeyboardKeyView_arrow(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[75], unitSize: 1, baseSize: keySize) 369 | KeyboardKeyView_arrow(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[76], unitSize: 1, baseSize: keySize) 370 | } 371 | KeyboardKeyView(selectedKeyboardKey: $selectedKeyboardKey, keyboardKey: layer[77], unitSize: 1, baseSize: keySize) 372 | 373 | } 374 | } 375 | 376 | } 377 | } 378 | } 379 | 380 | //#Preview { 381 | // let preset = Preset(presetName: "test", keyboardLayout: KeyboardLayout.UK) 382 | // @State var selected = KeyboardKey(beforeDisplaySymbol: "1", beforeKeyOutPut: "2") 383 | // BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selected ,layer: preset.layer0) 384 | //} 385 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/PresetView.swift: -------------------------------------------------------------------------------- 1 | ///PresetView:Presetを引数にとるビュー。 2 | ///KeyboardView:Presetのレイアウトで分岐してそれぞれのレイアウトを表示する 3 | ///CustomizeKeytab View:ドラッグ元のビュー。 4 | 5 | 6 | import SwiftUI 7 | 8 | //class FocusManager: ObservableObject { 9 | // @FocusState var isNameFocused: Bool = false//これでもダメだった。どうやってみんなフォーカスステート管理してるん? 10 | // @Published var isVendorFocused: Bool = false 11 | // @Published var isProductFocused: Bool = false 12 | // @Published var isSearchFocused: Bool = false 13 | // 14 | // func escapeAllFocus() { 15 | // isNameFocused = false 16 | // isVendorFocused = false 17 | // isProductFocused = false 18 | // isSearchFocused = false 19 | // } 20 | //} 21 | 22 | 23 | struct PresetView: View { 24 | @Binding var preset: Preset 25 | @Binding var selectedKeyboardKey: KeyboardKey 26 | @FocusState var nameFocus: Bool 27 | @FocusState var vendorFocus: Bool 28 | @FocusState var productFocus: Bool 29 | // @State var searchFieldFocus: Bool 30 | 31 | @State var pickerIndex: Int = 0 32 | 33 | var body: some View { 34 | ZStack { 35 | Color.clear 36 | .contentShape(Rectangle()) 37 | .frame(maxWidth: .infinity, maxHeight: .infinity) // 画面全体をカバー 38 | .onTapGesture { 39 | escape() 40 | } 41 | VStack { 42 | presetDetailView.padding() 43 | KeyboardView(preset: $preset, selectedKeyboardKey: $selectedKeyboardKey) 44 | CustomizeKeyTabView(/*externalSearchFieldFocuse: $searchFieldFocus*/) 45 | } 46 | 47 | } 48 | .onAppear { 49 | escape() 50 | } 51 | 52 | } 53 | private var presetDetailView: some View { 54 | VStack { 55 | HStack {//プリセット名、ベンダーID、ANSIかJISかなどをここに 56 | Spacer() 57 | TextField("Preset Name", text: $preset.presetName) 58 | .focused($nameFocus) 59 | .onSubmit { 60 | nameFocus = false 61 | } 62 | .textFieldStyle(.roundedBorder) 63 | .frame(width: 300) 64 | Text("VendorID:") 65 | TextField("Vendor ID", text: $preset.vendorID) 66 | .focused($vendorFocus) 67 | .onSubmit { 68 | vendorFocus = false 69 | } 70 | .textFieldStyle(.roundedBorder) 71 | .frame(width: 100) 72 | Text("ProductID:") 73 | TextField("Product ID", text: $preset.productID) 74 | .focused($productFocus) 75 | .onSubmit { 76 | productFocus = false 77 | } 78 | .textFieldStyle(.roundedBorder) 79 | .frame(width: 100) 80 | Picker("", selection: $preset.keyCodeRegion) { 81 | Text("ANSI").tag(KeyCodeRegion.ansi) 82 | Text("JIS").tag(KeyCodeRegion.jis) 83 | Text("ISO").tag(KeyCodeRegion.iso) 84 | } 85 | .pickerStyle(SegmentedPickerStyle()) 86 | .frame(width: 200) 87 | Spacer() 88 | } 89 | } 90 | } 91 | private func escape() { 92 | selectedKeyboardKey = .initial 93 | nameFocus = false 94 | vendorFocus = false 95 | productFocus = false 96 | // searchFieldFocus = false 97 | } 98 | } 99 | 100 | 101 | class LayerColorManager: ObservableObject { 102 | @Published var currentLayerColor: LayerColor = .layer0 103 | } 104 | 105 | struct KeyboardView: View { 106 | @Binding var preset: Preset 107 | @Binding var selectedKeyboardKey: KeyboardKey 108 | @State private var selectedLayer = 0 109 | 110 | @State private var selectedLayerColor: LayerColor = .layer0 111 | private let keySize: CGFloat = 65 112 | var body: some View { 113 | VStack { 114 | HStack { 115 | Spacer() 116 | ForEach(0..<9) { index in 117 | Button(action: { 118 | selectedLayer = index 119 | selectedLayerColor = colorForTab(index: selectedLayer) 120 | 121 | }) { 122 | if index == 0 { 123 | Text("Default") 124 | .bold() 125 | .frame(width: 80, height: 25) 126 | } else { 127 | Text("Layer \(index)") 128 | .frame(width: 80, height: 25) 129 | } 130 | } 131 | .buttonStyle(ParallelogramButtonStyle(isSelected: selectedLayer == index, tabIndex: index)) 132 | .padding(.horizontal, 5) 133 | 134 | } 135 | 136 | Spacer() 137 | 138 | } 139 | .padding(.horizontal) 140 | 141 | VStack{ 142 | switch preset.keyboardLayout { 143 | case .US: 144 | // レイヤーによって表示されるキーボードレイアウトを切り替える 145 | switch selectedLayer { 146 | case 0: 147 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer0) 148 | case 1: 149 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer1) 150 | case 2: 151 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer2) 152 | case 3: 153 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer3) 154 | case 4: 155 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer4) 156 | case 5: 157 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer5) 158 | case 6: 159 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer6) 160 | case 7: 161 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer7) 162 | case 8: 163 | BuiltInKeyboardLayerView_US(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer8) 164 | 165 | default: 166 | EmptyView() 167 | } 168 | case .UK: 169 | switch selectedLayer { 170 | case 0: 171 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer0) 172 | case 1: 173 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer1) 174 | case 2: 175 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer2) 176 | case 3: 177 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer3) 178 | case 4: 179 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer4) 180 | case 5: 181 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer5) 182 | case 6: 183 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer6) 184 | case 7: 185 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer7) 186 | case 8: 187 | BuiltInKeyboardLayerView_UK(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer8) 188 | 189 | default: 190 | EmptyView() 191 | } 192 | case .JIS: 193 | switch selectedLayer { 194 | case 0: 195 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer0) 196 | case 1: 197 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer1) 198 | case 2: 199 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer2) 200 | case 3: 201 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer3) 202 | case 4: 203 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer4) 204 | case 5: 205 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer5) 206 | case 6: 207 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer6) 208 | case 7: 209 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer7) 210 | case 8: 211 | BuiltInKeyboardLayerView_JIS(selectedKeyboardKey: $selectedKeyboardKey, keySize: keySize, layer: preset.layer8) 212 | default: 213 | EmptyView() 214 | } 215 | } 216 | } 217 | .padding(keySize * 0.035) 218 | .background(.gray.opacity(0.5)) 219 | .cornerRadius(keySize * 0.14 + keySize * 0.035) 220 | .padding() 221 | 222 | } 223 | } 224 | // タブのインデックスに応じたレイヤーの色を取得 225 | private func colorForTab(index: Int) -> LayerColor { 226 | switch index { 227 | case 1: 228 | return .layer1 229 | case 2: 230 | return .layer2 231 | case 3: 232 | return .layer3 233 | case 4: 234 | return .layer4 235 | case 5: 236 | return .layer5 237 | case 6: 238 | return .layer6 239 | case 7: 240 | return .layer7 241 | case 8: 242 | return .layer8 243 | default: 244 | return .layer0 245 | } 246 | } 247 | } 248 | 249 | struct ParallelogramShape: Shape { 250 | func path(in rect: CGRect) -> Path { 251 | var path = Path() 252 | 253 | let skewAmount: CGFloat = rect.maxX * 0.15 254 | 255 | path.move(to: CGPoint(x: skewAmount, y: rect.minY))//左上から時計まわりに 256 | path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY)) 257 | path.addLine(to: CGPoint(x: rect.maxX - skewAmount, y: rect.maxY)) 258 | path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY)) 259 | path.addLine(to: CGPoint(x: skewAmount, y: rect.minY)) 260 | 261 | return path 262 | } 263 | } 264 | struct ParallelogramButtonStyle: ButtonStyle { 265 | let isSelected: Bool 266 | let tabIndex: Int 267 | 268 | func makeBody(configuration: Configuration) -> some View { 269 | configuration.label 270 | .foregroundColor(.white) 271 | .background( 272 | ParallelogramShape() 273 | .fill(backgroundColor(isSelected: isSelected, 274 | tabIndex: tabIndex, 275 | isPressed: configuration.isPressed)) 276 | ) 277 | .scaleEffect(configuration.isPressed ? 0.90 : 1.0) 278 | // .animation(.bouncy, value: configuration.isPressed) 279 | } 280 | 281 | // 背景色を決定する関数 282 | private func backgroundColor(isSelected: Bool, tabIndex: Int, isPressed: Bool) -> Color { 283 | if isSelected { 284 | if tabIndex == 0 { 285 | return .black 286 | } else { 287 | return LayerColor.fromIndex(tabIndex).buttonAndHighLightColor 288 | } 289 | } else { 290 | return isPressed ? Color(red: 80/255, green: 80/255, blue: 88/255/*, opacity: 0.4*/) : Color(red: 96/255, green: 96/255, blue: 104/255) 291 | } 292 | } 293 | } 294 | 295 | enum LayerColor { 296 | case layer0 297 | case layer1 298 | case layer2 299 | case layer3 300 | case layer4 301 | case layer5 302 | case layer6 303 | case layer7 304 | case layer8 305 | 306 | var buttonAndHighLightColor: Color { 307 | switch self { 308 | case .layer0: 309 | return .primary 310 | case .layer1: 311 | return .orange 312 | case .layer2: 313 | return .green 314 | case .layer3: 315 | return .purple 316 | case .layer4: 317 | return .blue 318 | case.layer5: 319 | return .yellow 320 | case .layer6: 321 | return .red 322 | case.layer7: 323 | return .cyan 324 | case .layer8: 325 | return .indigo 326 | 327 | } 328 | } 329 | var textColor: Color { 330 | switch self { 331 | case .layer0: 332 | return .white 333 | case .layer1: 334 | return .orange 335 | case .layer2: 336 | return .green 337 | case .layer3: 338 | return .purple 339 | case .layer4: 340 | return .blue 341 | case.layer5: 342 | return .yellow 343 | case .layer6: 344 | return .red 345 | case.layer7: 346 | return .cyan 347 | case .layer8: 348 | return .indigo 349 | } 350 | } 351 | var textColor_export: Color { 352 | switch self { 353 | case .layer0: 354 | return .gray 355 | case .layer1: 356 | return .orange 357 | case .layer2: 358 | return .green 359 | case .layer3: 360 | return .purple 361 | case .layer4: 362 | return .blue 363 | case.layer5: 364 | return .yellow 365 | case .layer6: 366 | return .red 367 | case.layer7: 368 | return .cyan 369 | case .layer8: 370 | return .indigo 371 | } 372 | } 373 | var customizeKeyBackGroundColor: Color { 374 | switch self { 375 | case .layer0: 376 | return .black 377 | case .layer1: 378 | return .orange 379 | case .layer2: 380 | return .green 381 | case .layer3: 382 | return .purple 383 | case .layer4: 384 | return .blue 385 | case.layer5: 386 | return .yellow 387 | case .layer6: 388 | return .red 389 | case.layer7: 390 | return .cyan 391 | case .layer8: 392 | return .indigo 393 | } 394 | } 395 | 396 | static func fromIndex(_ index: Int) -> LayerColor { 397 | switch index { 398 | case 1: 399 | return .layer1 400 | case 2: 401 | return .layer2 402 | case 3: 403 | return .layer3 404 | case 4: 405 | return .layer4 406 | case 5: 407 | return .layer5 408 | case 6: 409 | return .layer6 410 | case 7: 411 | return .layer7 412 | case 8: 413 | return .layer8 414 | default: 415 | return .layer0 416 | } 417 | } 418 | } 419 | //#Preview { 420 | // KeyboardView() 421 | //} 422 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Keyboard/SelectedDetailView.swift: -------------------------------------------------------------------------------- 1 | ///右側サイドバー(Inspector)の 2 | ///選択したKeyboardKeyの詳細な情報を表示するビュー 3 | /// 4 | import SwiftUI 5 | 6 | struct SelectedDetailView: View { 7 | 8 | @Binding var selectedKeyboardKey: KeyboardKey 9 | let selectedPreset: Preset? 10 | @FocusState private var isFocused_customJSON: Bool 11 | @FocusState private var isFocused_tapDisplaySymbol: Bool 12 | @FocusState private var isFocused_holdDisplaySymbol: Bool 13 | 14 | private var highLightColor_tap: Color { //レイヤー移動のキーが入ってる時の色 15 | LayerColor.fromIndex(selectedKeyboardKey.layerKeyNumber_tap).buttonAndHighLightColor 16 | } 17 | private var highLightColor_hold: Color { //レイヤー移動のキーが入ってる時の色 18 | LayerColor.fromIndex(selectedKeyboardKey.layerKeyNumber_hold).buttonAndHighLightColor 19 | } 20 | private var textColor: Color { //レイヤーに応じて色を変化 21 | LayerColor.fromIndex(selectedKeyboardKey.layerNumber).textColor 22 | } 23 | var body: some View { 24 | ZStack { 25 | Color.clear 26 | .contentShape(Rectangle()) 27 | .frame(maxWidth: .infinity, maxHeight: .infinity) // 画面全体をカバー 28 | .onTapGesture { 29 | isFocused_customJSON = false 30 | isFocused_tapDisplaySymbol = false 31 | isFocused_holdDisplaySymbol = false 32 | } 33 | if selectedKeyboardKey.isInitial { 34 | initialKeyboardKeyView 35 | } else { 36 | VStack { 37 | if !selectedKeyboardKey.isTapHoldEnabled { 38 | tapView 39 | } else { 40 | tapHoldView 41 | } 42 | Toggle(isOn: $selectedKeyboardKey.userCustomJSONEnabled) {Text("User Custom JSON")} 43 | // .help("When the toggle is on, a JSON is generated including the text from the text field, ignoring other states.") 44 | .toggleStyle(.switch) 45 | .onChange(of: selectedKeyboardKey.userCustomJSONEnabled, initial: false) {oldValue, newValue in 46 | if newValue {//トグルがオンになった時、KeyboardKeyひとつ分のJSONを返すようにする 47 | let exporter = JSONExporter() 48 | do { 49 | if let jsonContent = try exporter.exportKeyboardKey_userCustomJSON( 50 | selectedKeyboardKey, 51 | keyCodeRegion: selectedPreset?.keyCodeRegion ?? .ansi, 52 | vendorID: selectedPreset?.vendorID ?? "1452", 53 | productID: selectedPreset?.productID ?? "635" 54 | ) { 55 | selectedKeyboardKey.userCustomJSONContent = jsonContent 56 | } else { 57 | // JSONが生成されなかった場合(例:カスタマイズされていない場合) 58 | selectedKeyboardKey.userCustomJSONContent = "There is no customization." 59 | } 60 | } catch { 61 | // エラーが発生した場合の処理 62 | print("Error generating JSON: \(error)") 63 | selectedKeyboardKey.userCustomJSONContent = "Error: Unable to generate JSON" 64 | 65 | // オプション:ユーザーにエラーを通知 66 | // showErrorAlert(message: "Failed to generate JSON. Please try again.") 67 | } 68 | } 69 | if !newValue {//トグルがオフになった時 70 | 71 | isFocused_customJSON = false 72 | } 73 | } 74 | TextEditor(text: $selectedKeyboardKey.userCustomJSONContent) 75 | .disabled(!selectedKeyboardKey.userCustomJSONEnabled) 76 | .focused($isFocused_customJSON) 77 | .foregroundColor(selectedKeyboardKey.userCustomJSONEnabled ? .primary : .gray) 78 | } 79 | .padding() 80 | } 81 | } 82 | 83 | } 84 | private var initialKeyboardKeyView: some View { 85 | VStack { 86 | Text("Select any key on the keyboard view.") 87 | .font(.headline) 88 | .foregroundColor(.secondary) 89 | .padding() 90 | } 91 | } 92 | private func modifierFontSize_tap() -> CGFloat { 93 | var activeModifierCount = 0 94 | if selectedKeyboardKey.tapWithShift { activeModifierCount += 1 } 95 | if selectedKeyboardKey.tapWithControl { activeModifierCount += 1 } 96 | if selectedKeyboardKey.tapWithCommand { activeModifierCount += 1 } 97 | if selectedKeyboardKey.tapWithOption { activeModifierCount += 1 } 98 | if selectedKeyboardKey.tapWithFn { activeModifierCount += 1 } 99 | 100 | switch activeModifierCount { 101 | case 0: 102 | return 15 103 | case 1: 104 | return 15 105 | case 2: 106 | return 10 107 | default: 108 | return 6 109 | } 110 | 111 | } 112 | private func modifierFontSize_hold() -> CGFloat { 113 | var activeModifierCount = 0 114 | if selectedKeyboardKey.holdWithShift { activeModifierCount += 1 } 115 | if selectedKeyboardKey.holdWithControl { activeModifierCount += 1 } 116 | if selectedKeyboardKey.holdWithCommand { activeModifierCount += 1 } 117 | if selectedKeyboardKey.holdWithOption { activeModifierCount += 1 } 118 | if selectedKeyboardKey.holdWithFn { activeModifierCount += 1 } 119 | 120 | switch activeModifierCount { 121 | case 0: 122 | return 15 123 | case 1: 124 | return 15 125 | case 2: 126 | return 10 127 | default: 128 | return 6 129 | } 130 | 131 | } 132 | private var modifierContent_tap: some View { 133 | VStack(spacing: 0) { 134 | if selectedKeyboardKey.tapWithModifier { 135 | Spacer() 136 | HStack(spacing: 0) { 137 | if selectedKeyboardKey.tapWithShift { 138 | Image(systemName: "shift") 139 | } 140 | if selectedKeyboardKey.tapWithControl { 141 | Image(systemName: "control") 142 | } 143 | } 144 | HStack(spacing: 0) { 145 | if selectedKeyboardKey.tapWithCommand { 146 | Image(systemName: "command") 147 | } 148 | if selectedKeyboardKey.tapWithOption { 149 | Image(systemName: "option") 150 | } 151 | } 152 | if selectedKeyboardKey.tapWithFn { 153 | Image(systemName: "globe") 154 | } 155 | Spacer() 156 | } else { 157 | EmptyView() 158 | } 159 | } 160 | .font(.system(size: modifierFontSize_tap())) 161 | } 162 | private var modifierContent_hold: some View { 163 | VStack(spacing: 0) { 164 | if selectedKeyboardKey.holdWithModifier { 165 | Spacer() 166 | HStack(spacing: 0) { 167 | if selectedKeyboardKey.holdWithShift { 168 | Image(systemName: "shift") 169 | } 170 | if selectedKeyboardKey.holdWithControl { 171 | Image(systemName: "control") 172 | } 173 | } 174 | HStack(spacing: 0) { 175 | if selectedKeyboardKey.holdWithCommand { 176 | Image(systemName: "command") 177 | } 178 | if selectedKeyboardKey.holdWithOption { 179 | Image(systemName: "option") 180 | } 181 | } 182 | if selectedKeyboardKey.holdWithFn { 183 | Image(systemName: "globe") 184 | } 185 | Spacer() 186 | } else { 187 | EmptyView() 188 | } 189 | } 190 | .font(.system(size: modifierFontSize_hold())) 191 | } 192 | 193 | private var tapView: some View { 194 | VStack { 195 | Text("Tap Key").font(.caption) 196 | if selectedKeyboardKey.afterKeyOutPut != "" { 197 | HStack(spacing: 0) { 198 | if selectedKeyboardKey.layerKeyNumber_tap > 0 { 199 | // modifierContent_tap.foregroundStyle(highLightColor) 200 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: highLightColor_tap) 201 | } else { 202 | modifierContent_tap.foregroundStyle(textColor) 203 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: textColor) 204 | } 205 | } 206 | .frame(width: 65, height: 65) 207 | .background(.black) 208 | .cornerRadius(65 * 0.07) 209 | .dropDestination(for: CustomizeKey.self) { items, location in 210 | guard let item = items.first else { return false } 211 | selectedKeyboardKey.applyTapKeyCustomization(from: item) 212 | return true 213 | } 214 | } else { 215 | Text("Drop here") 216 | .font(.caption) 217 | .foregroundColor(.white) 218 | .frame(width: 65, height: 65) 219 | .background(.black) 220 | .cornerRadius(65 * 0.07) 221 | .dropDestination(for: CustomizeKey.self) { items, location in 222 | guard let item = items.first else { return false } 223 | selectedKeyboardKey.applyTapKeyCustomization(from: item) 224 | return true 225 | } 226 | } 227 | HStack { 228 | Spacer() 229 | Text("Enable Tap Hold") 230 | Spacer() 231 | Toggle(isOn: $selectedKeyboardKey.isTapHoldEnabled) {Text("")}.toggleStyle(.switch) 232 | Spacer() 233 | } 234 | 235 | Toggle(isOn: $selectedKeyboardKey.tapWithModifier) { Text("Tap with Modifier")}.toggleStyle(.button) 236 | HStack { 237 | Toggle("⇧",isOn: $selectedKeyboardKey.tapWithShift) 238 | .toggleStyle(.button) 239 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeShift) 240 | Toggle("^",isOn: $selectedKeyboardKey.tapWithControl) 241 | .toggleStyle(.button) 242 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeControl) 243 | } 244 | HStack { 245 | Toggle("⌘",isOn: $selectedKeyboardKey.tapWithCommand) 246 | .toggleStyle(.button) 247 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeCommand) 248 | Toggle("⌥",isOn: $selectedKeyboardKey.tapWithOption) 249 | .toggleStyle(.button) 250 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeOption) 251 | } 252 | Toggle("fn", isOn: $selectedKeyboardKey.tapWithFn) 253 | .toggleStyle(.button) 254 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeFn) 255 | 256 | Toggle("SFSymbol", isOn: $selectedKeyboardKey.isAfterTapSFSymbol) 257 | .toggleStyle(.checkbox) 258 | TextField(selectedKeyboardKey.isAfterTapSFSymbol ? "SymbolName:" : "DisplayName:", text: $selectedKeyboardKey.afterDisplaySymbol) 259 | .focused($isFocused_tapDisplaySymbol) 260 | .disabled(!selectedKeyboardKey.isCustomized) 261 | Text("keycode: \(selectedKeyboardKey.beforeKeyOutPut) → \(selectedKeyboardKey.afterKeyOutPut)") 262 | .font(.caption2) 263 | 264 | } 265 | } 266 | private var tapHoldView: some View { 267 | VStack { 268 | HStack { 269 | Spacer() 270 | VStack { 271 | Text("Tap Key").font(.caption) 272 | ZStack { 273 | if selectedKeyboardKey.afterKeyOutPut != "" { //すでに何かしらドロップされたあとの表示 274 | HStack { 275 | if selectedKeyboardKey.layerKeyNumber_tap > 0 { //holdにレイヤー移動キーが入ってる場合の表示 276 | // modifierContent_tap.foregroundStyle(highLightColor) 277 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: highLightColor_tap) 278 | } else { 279 | modifierContent_tap.foregroundStyle(textColor) 280 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: textColor) 281 | } 282 | } 283 | } else { //まだドロップされていない状態の時の表示 284 | Text("Drop here") 285 | .font(.caption2) 286 | .foregroundColor(.white) 287 | } 288 | } 289 | .frame(width: 65, height: 65) 290 | .background(.black) 291 | .cornerRadius(65 * 0.07) 292 | .dropDestination(for: CustomizeKey.self) { items, location in 293 | guard let item = items.first else { return false } 294 | selectedKeyboardKey.applyTapKeyCustomization(from: item) 295 | return true 296 | } 297 | } 298 | Spacer() 299 | VStack { 300 | Text("Hold Key").font(.caption) 301 | ZStack { 302 | if selectedKeyboardKey.holdKeyOutPut != "" { 303 | HStack(spacing: 0) { 304 | if selectedKeyboardKey.layerKeyNumber_hold > 0 { 305 | // modifierContent_hold.foregroundStyle(highLightColor_hold) 306 | symbolOrText(selectedKeyboardKey.holdDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterHoldSFSymbol, size: 20, color: highLightColor_hold) 307 | } else { 308 | modifierContent_hold.foregroundStyle(textColor) 309 | symbolOrText(selectedKeyboardKey.holdDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterHoldSFSymbol, size: 20, color: textColor) 310 | } 311 | } 312 | } else { 313 | Text("Drop here") 314 | .font(.caption2) 315 | .foregroundColor(.white) 316 | } 317 | } 318 | .frame(width: 65, height: 65) 319 | .background(.black) 320 | .cornerRadius(65 * 0.07) 321 | .dropDestination(for: CustomizeKey.self) { items, location in 322 | guard let item = items.first else { return false } 323 | selectedKeyboardKey.applyHoldKeyCustomization(from: item) 324 | return true 325 | } 326 | } 327 | Spacer() 328 | } 329 | HStack { 330 | Spacer() 331 | Text("Tap Hold") 332 | Spacer() 333 | Toggle(isOn: $selectedKeyboardKey.isTapHoldEnabled) {Text("")}.toggleStyle(.switch) 334 | Spacer() 335 | } 336 | Picker("", selection: $selectedKeyboardKey.tapHoldType) { 337 | ForEach(TapHoldType.allCases, id: \.self) { type in 338 | Text(type.rawValue.capitalized).tag(type) 339 | } 340 | } 341 | .pickerStyle(SegmentedPickerStyle()) 342 | VStack { 343 | Text("Tap Hold Threshold: \(Int(selectedKeyboardKey.tapHoldThreshold)) ms") 344 | Slider(value: $selectedKeyboardKey.tapHoldThreshold, in: 40...500, step: 20) 345 | .disabled(selectedKeyboardKey.tapHoldType != .basic) 346 | .onChange(of: selectedKeyboardKey.tapHoldThreshold) {oldValue, newValue in 347 | // ハプティックフィードバックを発生させる 348 | //レスポンスが終わってるけど、他のビューが重いから?コメントアウトしても良い気がするな 349 | NSHapticFeedbackManager.defaultPerformer.perform(.alignment , performanceTime: .now) 350 | } 351 | .padding(.horizontal) 352 | } 353 | HStack { 354 | VStack { 355 | Toggle("Tap with Modifier", isOn: $selectedKeyboardKey.tapWithModifier) 356 | .toggleStyle(.button) 357 | 358 | //Tap 359 | HStack { 360 | Toggle("⇧",isOn: $selectedKeyboardKey.tapWithShift) 361 | .toggleStyle(.button) 362 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeShift) 363 | Toggle("^",isOn: $selectedKeyboardKey.tapWithControl) 364 | .toggleStyle(.button) 365 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeControl) 366 | } 367 | HStack { 368 | Toggle("⌘",isOn: $selectedKeyboardKey.tapWithCommand) 369 | .toggleStyle(.button) 370 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeCommand) 371 | Toggle("⌥",isOn: $selectedKeyboardKey.tapWithOption) 372 | .toggleStyle(.button) 373 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeOption) 374 | } 375 | Toggle("fn", isOn: $selectedKeyboardKey.tapWithFn) 376 | .toggleStyle(.button) 377 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeFn) 378 | } 379 | Divider().frame(height: 100) 380 | VStack { 381 | Toggle("Hold with Modifier", isOn: $selectedKeyboardKey.holdWithModifier) 382 | .toggleStyle(.button) 383 | 384 | //Hold 385 | HStack { 386 | Toggle("⇧",isOn: $selectedKeyboardKey.holdWithShift) 387 | .toggleStyle(.button) 388 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeShift) 389 | Toggle("^",isOn: $selectedKeyboardKey.holdWithControl) 390 | .toggleStyle(.button) 391 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeControl) 392 | } 393 | HStack { 394 | Toggle("⌘",isOn: $selectedKeyboardKey.holdWithCommand) 395 | .toggleStyle(.button) 396 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeCommand) 397 | Toggle("⌥",isOn: $selectedKeyboardKey.holdWithOption) 398 | .toggleStyle(.button) 399 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeOption) 400 | } 401 | Toggle("fn", isOn: $selectedKeyboardKey.holdWithFn) 402 | .toggleStyle(.button) 403 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeFn) 404 | } 405 | } 406 | HStack { 407 | VStack { 408 | Toggle("SFSymbol", isOn: $selectedKeyboardKey.isAfterTapSFSymbol) 409 | .toggleStyle(.checkbox) 410 | TextField(selectedKeyboardKey.isAfterTapSFSymbol ? "SymbolName:": "DisplayName", text: $selectedKeyboardKey.afterDisplaySymbol) 411 | .focused($isFocused_tapDisplaySymbol) 412 | .disabled(!selectedKeyboardKey.isCustomized) 413 | Text("Tap \(selectedKeyboardKey.beforeKeyOutPut) → \(selectedKeyboardKey.afterKeyOutPut)") 414 | .font(.caption2) 415 | } 416 | VStack { 417 | Toggle("SFSymbol", isOn: $selectedKeyboardKey.isAfterHoldSFSymbol) 418 | .toggleStyle(.checkbox) 419 | TextField(selectedKeyboardKey.isAfterHoldSFSymbol ? "SymbolName:": "DisplayName", text: $selectedKeyboardKey.holdDisplaySymbol) 420 | .focused($isFocused_holdDisplaySymbol) 421 | .disabled(!selectedKeyboardKey.isCustomized) 422 | Text("Hold \(selectedKeyboardKey.beforeKeyOutPut) → \(selectedKeyboardKey.holdKeyOutPut)") 423 | .font(.caption2) 424 | } 425 | } 426 | } 427 | } 428 | private func symbolOrText(_ content: String, isSymbol: Bool, size: CGFloat, color: Color) -> some View { 429 | Group { 430 | if isSymbol { 431 | Image(systemName: content) 432 | .font(.system(size: size)) 433 | } else { 434 | Text(content) 435 | .font(.system(size: size)) 436 | } 437 | } 438 | .foregroundColor(color) 439 | } 440 | } 441 | 442 | struct SelectedDetailView_PopOver: View { 443 | @Binding var selectedKeyboardKey: KeyboardKey 444 | private var highLightColor_tap: Color { //レイヤー移動のキーが入ってる時の色 445 | LayerColor.fromIndex(selectedKeyboardKey.layerKeyNumber_tap).buttonAndHighLightColor 446 | } 447 | private var highLightColor_hold: Color { //レイヤー移動のキーが入ってる時の色 448 | LayerColor.fromIndex(selectedKeyboardKey.layerKeyNumber_hold).buttonAndHighLightColor 449 | } 450 | private var textColor: Color { //レイヤーに応じて色を変化 451 | LayerColor.fromIndex(selectedKeyboardKey.layerNumber).textColor 452 | } 453 | 454 | var body: some View { 455 | VStack { 456 | if !selectedKeyboardKey.isTapHoldEnabled { 457 | tapView 458 | } else { 459 | tapHoldView 460 | } 461 | } 462 | .padding() 463 | .frame(width: 300) 464 | .padding() 465 | } 466 | private func modifierFontSize_tap() -> CGFloat { 467 | var activeModifierCount = 0 468 | if selectedKeyboardKey.tapWithShift { activeModifierCount += 1 } 469 | if selectedKeyboardKey.tapWithControl { activeModifierCount += 1 } 470 | if selectedKeyboardKey.tapWithCommand { activeModifierCount += 1 } 471 | if selectedKeyboardKey.tapWithOption { activeModifierCount += 1 } 472 | if selectedKeyboardKey.tapWithFn { activeModifierCount += 1 } 473 | 474 | switch activeModifierCount { 475 | case 0: 476 | return 15 477 | case 1: 478 | return 15 479 | case 2: 480 | return 10 481 | default: 482 | return 6 483 | } 484 | } 485 | private func modifierFontSize_hold() -> CGFloat { 486 | var activeModifierCount = 0 487 | if selectedKeyboardKey.holdWithShift { activeModifierCount += 1 } 488 | if selectedKeyboardKey.holdWithControl { activeModifierCount += 1 } 489 | if selectedKeyboardKey.holdWithCommand { activeModifierCount += 1 } 490 | if selectedKeyboardKey.holdWithOption { activeModifierCount += 1 } 491 | if selectedKeyboardKey.holdWithFn { activeModifierCount += 1 } 492 | 493 | switch activeModifierCount { 494 | case 0: 495 | return 15 496 | case 1: 497 | return 15 498 | case 2: 499 | return 10 500 | default: 501 | return 6 502 | } 503 | } 504 | 505 | private var modifierContent_tap: some View { 506 | VStack(spacing: 0) { 507 | if selectedKeyboardKey.tapWithModifier { 508 | Spacer() 509 | HStack(spacing: 0) { 510 | if selectedKeyboardKey.tapWithShift { 511 | Image(systemName: "shift") 512 | } 513 | if selectedKeyboardKey.tapWithControl { 514 | Image(systemName: "control") 515 | } 516 | } 517 | HStack(spacing: 0) { 518 | if selectedKeyboardKey.tapWithCommand { 519 | Image(systemName: "command") 520 | } 521 | if selectedKeyboardKey.tapWithOption { 522 | Image(systemName: "option") 523 | } 524 | } 525 | if selectedKeyboardKey.tapWithFn { 526 | Image(systemName: "globe") 527 | } 528 | Spacer() 529 | } else { 530 | EmptyView() 531 | } 532 | } 533 | .font(.system(size: modifierFontSize_tap())) 534 | } 535 | private var modifierContent_hold: some View { 536 | VStack(spacing: 0) { 537 | if selectedKeyboardKey.holdWithModifier { 538 | Spacer() 539 | HStack(spacing: 0) { 540 | if selectedKeyboardKey.holdWithShift { 541 | Image(systemName: "shift") 542 | } 543 | if selectedKeyboardKey.holdWithControl { 544 | Image(systemName: "control") 545 | } 546 | } 547 | HStack(spacing: 0) { 548 | if selectedKeyboardKey.holdWithCommand { 549 | Image(systemName: "command") 550 | } 551 | if selectedKeyboardKey.holdWithOption { 552 | Image(systemName: "option") 553 | } 554 | } 555 | if selectedKeyboardKey.holdWithFn { 556 | Image(systemName: "globe") 557 | } 558 | Spacer() 559 | } else { 560 | EmptyView() 561 | } 562 | } 563 | .font(.system(size: modifierFontSize_hold())) 564 | } 565 | 566 | private var tapView: some View { 567 | VStack { 568 | Text("Tap Key").font(.caption) 569 | HStack(spacing: 0) { 570 | if selectedKeyboardKey.afterKeyOutPut != "" { 571 | if selectedKeyboardKey.layerKeyNumber_tap > 0 { 572 | // modifierContent_tap.foregroundStyle(highLightColor_tap) 573 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: highLightColor_tap) 574 | } else { 575 | modifierContent_tap.foregroundStyle(textColor) 576 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: textColor) 577 | } 578 | 579 | } else { 580 | Text("Drop here") 581 | .font(.caption) 582 | .foregroundColor(.white) 583 | 584 | } 585 | } 586 | .frame(width: 65, height: 65) 587 | .background(.black) 588 | .cornerRadius(65 * 0.07) 589 | .dropDestination(for: CustomizeKey.self) { items, location in 590 | guard let item = items.first else { return false } 591 | selectedKeyboardKey.applyTapKeyCustomization(from: item) 592 | return true 593 | } 594 | 595 | HStack { 596 | Spacer() 597 | Text("Enable Tap Hold") 598 | Spacer() 599 | Toggle(isOn: $selectedKeyboardKey.isTapHoldEnabled) {Text("")}.toggleStyle(.switch) 600 | Spacer() 601 | } 602 | 603 | Toggle(isOn: $selectedKeyboardKey.tapWithModifier) { Text("Tap with Modifier")}.toggleStyle(.button) 604 | HStack { 605 | Toggle("⇧",isOn: $selectedKeyboardKey.tapWithShift) 606 | .toggleStyle(.button) 607 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeShift) 608 | Toggle("^",isOn: $selectedKeyboardKey.tapWithControl) 609 | .toggleStyle(.button) 610 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeControl) 611 | } 612 | HStack { 613 | Toggle("⌘",isOn: $selectedKeyboardKey.tapWithCommand) 614 | .toggleStyle(.button) 615 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeCommand) 616 | Toggle("⌥",isOn: $selectedKeyboardKey.tapWithOption) 617 | .toggleStyle(.button) 618 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeOption) 619 | } 620 | Toggle("fn", isOn: $selectedKeyboardKey.tapWithFn) 621 | .toggleStyle(.button) 622 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeFn) 623 | 624 | } 625 | } 626 | private var tapHoldView: some View { 627 | VStack { 628 | HStack { 629 | Spacer() 630 | VStack { 631 | Text("Tap Key").font(.caption) 632 | ZStack { 633 | VStack { 634 | if selectedKeyboardKey.afterKeyOutPut != "" { //すでに何かしらドロップされたあとの表示 635 | HStack(spacing: 0) { 636 | if selectedKeyboardKey.layerKeyNumber_tap > 0 { 637 | // modifierContent_tap.foregroundStyle(highLightColor_tap) 638 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: highLightColor_tap) 639 | } else { 640 | modifierContent_tap.foregroundStyle(textColor) 641 | symbolOrText(selectedKeyboardKey.afterDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterTapSFSymbol, size: 20, color: textColor) 642 | } 643 | } 644 | } else { //まだドロップされていない状態の時の表示 645 | Text("Drop here") 646 | .font(.caption2) 647 | .foregroundColor(.white) 648 | 649 | } 650 | } 651 | } 652 | .frame(width: 65, height: 65) 653 | .background(.black) 654 | .cornerRadius(65 * 0.07) 655 | .dropDestination(for: CustomizeKey.self) { items, location in 656 | guard let item = items.first else { return false } 657 | selectedKeyboardKey.applyTapKeyCustomization(from: item) 658 | return true 659 | } 660 | } 661 | Spacer() 662 | VStack { 663 | Text("Hold Key").font(.caption) 664 | ZStack { 665 | VStack { 666 | if selectedKeyboardKey.holdKeyOutPut != "" { 667 | HStack(spacing: 0) { 668 | if selectedKeyboardKey.layerKeyNumber_hold > 0 { 669 | modifierContent_hold.foregroundStyle(highLightColor_hold) 670 | symbolOrText(selectedKeyboardKey.holdDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterHoldSFSymbol, size: 20, color: highLightColor_hold) 671 | } else { 672 | modifierContent_hold.foregroundStyle(textColor) 673 | symbolOrText(selectedKeyboardKey.holdDisplaySymbol, isSymbol: selectedKeyboardKey.isAfterHoldSFSymbol, size: 20, color: textColor) 674 | } 675 | } 676 | } else { 677 | Text("Drop here") 678 | .foregroundColor(.white) 679 | .font(.caption2) 680 | } 681 | } 682 | } 683 | .frame(width: 65, height: 65) 684 | .background(.black) 685 | .cornerRadius(65 * 0.07) 686 | .dropDestination(for: CustomizeKey.self) { items, location in 687 | guard let item = items.first else { return false } 688 | selectedKeyboardKey.applyHoldKeyCustomization(from: item) 689 | return true 690 | } 691 | } 692 | Spacer() 693 | } 694 | HStack { 695 | Spacer() 696 | Text("Enable Tap Hold") 697 | Spacer() 698 | Toggle(isOn: $selectedKeyboardKey.isTapHoldEnabled) {Text("")}.toggleStyle(.switch) 699 | Spacer() 700 | } 701 | HStack { 702 | VStack { 703 | Toggle("Tap with Modifier", isOn: $selectedKeyboardKey.tapWithModifier) 704 | .toggleStyle(.button) 705 | 706 | //Tap 707 | HStack { 708 | Toggle("⇧",isOn: $selectedKeyboardKey.tapWithShift) 709 | .toggleStyle(.button) 710 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeShift) 711 | Toggle("^",isOn: $selectedKeyboardKey.tapWithControl) 712 | .toggleStyle(.button) 713 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeControl) 714 | } 715 | HStack { 716 | Toggle("⌘",isOn: $selectedKeyboardKey.tapWithCommand) 717 | .toggleStyle(.button) 718 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeCommand) 719 | Toggle("⌥",isOn: $selectedKeyboardKey.tapWithOption) 720 | .toggleStyle(.button) 721 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeOption) 722 | } 723 | Toggle("fn", isOn: $selectedKeyboardKey.tapWithFn) 724 | .toggleStyle(.button) 725 | .disabled(!selectedKeyboardKey.tapWithModifier || selectedKeyboardKey.isTapIncludeFn) 726 | } 727 | Divider().frame(height: 100) 728 | VStack { 729 | Toggle("Hold with Modifier", isOn: $selectedKeyboardKey.holdWithModifier) 730 | .toggleStyle(.button) 731 | 732 | //Hold 733 | HStack { 734 | Toggle("⇧",isOn: $selectedKeyboardKey.holdWithShift) 735 | .toggleStyle(.button) 736 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeShift) 737 | Toggle("^",isOn: $selectedKeyboardKey.holdWithControl) 738 | .toggleStyle(.button) 739 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeControl) 740 | } 741 | HStack { 742 | Toggle("⌘",isOn: $selectedKeyboardKey.holdWithCommand) 743 | .toggleStyle(.button) 744 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeCommand) 745 | Toggle("⌥",isOn: $selectedKeyboardKey.holdWithOption) 746 | .toggleStyle(.button) 747 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeOption) 748 | } 749 | Toggle("fn", isOn: $selectedKeyboardKey.holdWithFn) 750 | .toggleStyle(.button) 751 | .disabled(!selectedKeyboardKey.holdWithModifier || selectedKeyboardKey.isHoldIncludeFn) 752 | } 753 | } 754 | } 755 | } 756 | private func symbolOrText(_ content: String, isSymbol: Bool, size: CGFloat, color: Color) -> some View { 757 | Group { 758 | if isSymbol { 759 | Image(systemName: content) 760 | .font(.system(size: size)) 761 | } else { 762 | Text(content) 763 | .font(.system(size: size)) 764 | } 765 | } 766 | .foregroundColor(color) 767 | } 768 | } 769 | 770 | //#Preview { 771 | // SelectedDetailView() 772 | //} 773 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/PresetLabelView.swift: -------------------------------------------------------------------------------- 1 | //Navigation用のラベルビュー。テキストをクリックしたり、右クリしたりしてリネーム、デリートが行えるような感じ。 2 | import SwiftUI 3 | 4 | struct PresetLabelView: View { 5 | let preset: Preset 6 | @Binding var isEditing: Bool 7 | @Binding var selectedPresetID: UUID? 8 | @FocusState.Binding var isFocused: Bool 9 | 10 | var onDelete: () -> Void 11 | 12 | var body: some View { 13 | if isEditing && selectedPresetID == preset.id { 14 | // 1. テキスト編集中のラベル 15 | HStack { 16 | TextField("Preset Name", 17 | text: Binding( 18 | get: { preset.presetName }, 19 | set: { newName in 20 | preset.presetName = newName 21 | }) 22 | ) 23 | .background(.clear) 24 | .focused($isFocused) 25 | .onAppear { 26 | isFocused = true 27 | } 28 | .onSubmit { 29 | isEditing = false 30 | } 31 | } 32 | } else if selectedPresetID == preset.id { 33 | // 2. 選択中の要素のラベル 34 | ZStack { 35 | HStack { 36 | Text(preset.presetName) 37 | .onTapGesture(count: 1) {//テキストをクリックすると編集状態に移行する。 38 | isEditing = true 39 | // print("isEditing is true now!") 40 | } 41 | .contextMenu { 42 | Button("Rename") { 43 | isEditing = true 44 | } 45 | Button("Delete", role: .destructive) { 46 | onDelete() 47 | }.keyboardShortcut(.delete, modifiers: .command) 48 | } 49 | Spacer() 50 | } 51 | HStack(alignment: .bottom) { 52 | Spacer() 53 | Text("\(preset.keyboardLayout)") 54 | .font(.caption2) 55 | .foregroundStyle(.secondary) 56 | } 57 | } 58 | } else { 59 | // 3. 選択されていないラベル 60 | ZStack { 61 | HStack { 62 | Text(preset.presetName) 63 | Spacer() 64 | } 65 | HStack(alignment: .bottom) { 66 | Spacer() 67 | Text("\(preset.keyboardLayout)") 68 | .font(.caption2) 69 | .foregroundStyle(.secondary) 70 | } 71 | } 72 | } 73 | 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Stapler-mini-v0App.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import SwiftUI 4 | import SwiftData 5 | 6 | @main 7 | struct Stapler_mini_v0_App: App { 8 | @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate 9 | 10 | init() { 11 | NSWindow.allowsAutomaticWindowTabbing = false 12 | } 13 | 14 | var body: some Scene { 15 | WindowGroup { 16 | ContentView() 17 | .onReceive(NotificationCenter.default.publisher(for: NSApplication.didFinishLaunchingNotification)) { _ in 18 | Task { @MainActor in 19 | guard let modelContainer = try? await prepareModelContainer() else { return } 20 | appDelegate.modelContainer = modelContainer 21 | } 22 | } 23 | } 24 | .modelContainer(for: [Preset.self], isUndoEnabled: true) 25 | .commands { 26 | CommandGroup(replacing: .newItem) {} //File>NewWindow 27 | // Editメニューのカスタマイズ 28 | CommandGroup(replacing: .pasteboard) {} // Edit>Copy Paste... 29 | // CommandGroup(replacing: .textEditing) {} // Edit>AutoFill,Start Dictation, Emoji & Symbolsがわからないが、必要なさそうだから消したい。 30 | 31 | 32 | CommandGroup(replacing: .help) { 33 | Button("アプリの使い方") { 34 | // ヘルプを表示するアクション 35 | NSWorkspace.shared.open(URL(string: "https://note.com/9dpb/n/n471a998bdef8")!) 36 | } 37 | Button("Discordコミュニティで質問する") { 38 | // ヘルプを表示するアクション 39 | NSWorkspace.shared.open(URL(string: "https://discord.gg/yVhZfsE2zS")!) 40 | } 41 | } 42 | } 43 | } 44 | 45 | @MainActor 46 | private func prepareModelContainer() async throws -> ModelContainer { 47 | let schema = Schema([Preset.self]) 48 | let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) 49 | return try ModelContainer(for: schema, configurations: [modelConfiguration]) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/Stapler_mini_v0.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-write 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | English 3 | */ 4 | "selectedDetailView_select" = "Please select any key on the keyboard view."; 5 | "selectedDetailView_enableTapHold" = "Tap Hold"; 6 | 7 | "addPresetView_selectLayout" = "Chose keyboard layout"; 8 | "addPresetView_cansel" = "Cancel"; 9 | "addPresetView_createPreset" = "Create a Preset"; 10 | -------------------------------------------------------------------------------- /Stapler-mini-v0/Stapler-mini-v0/ja.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | 日本語 3 | そのうちやります。 4 | */ 5 | "selectedDetailView_select" = "キーボードのキーを選択してください。"; 6 | "selectedDetailView_enableTapHold" = "Tap Hold"; 7 | 8 | "addPresetView_selectLayout" = "キーボードレイアウトを選択してください"; 9 | "addPresetView_cansel" = "キャンセル"; 10 | "addPresetView_createPreset" = "プリセットを作る"; 11 | --------------------------------------------------------------------------------