Skip to content

Commit b8d7cf1

Browse files
committed
add windows kanata
1 parent e298396 commit b8d7cf1

3 files changed

Lines changed: 237 additions & 24 deletions

File tree

conf/kanata/kanata.vbs

Lines changed: 0 additions & 3 deletions
This file was deleted.

scripts/kanata.sh

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
install_kanata_deepin() (
2+
# Build Kanata locally because the Deepin repositories do not package it.
23
without_nix_env sudo apt install -y curl build-essential pkg-config libayatana-appindicator3-dev
34

45
local temporary_dir
@@ -20,6 +21,7 @@ install_kanata_deepin() (
2021
https://github.com/rszyma/kanata-tray/releases/latest/download/kanata-tray-linux
2122
sudo install -m 0755 "$tray_binary" /usr/local/bin/kanata-tray
2223

24+
# Allow Kanata to create virtual input devices and keep the tray per user.
2325
sudo groupadd --system --force uinput
2426
sudo usermod -aG input,uinput "$USER"
2527
sudo install -m 0644 "$DOTFILES_DIR/conf/kanata/99-kanata.rules" /etc/udev/rules.d/99-kanata.rules
@@ -37,6 +39,7 @@ install_kanata_deepin() (
3739
)
3840

3941
kanata_macos_run() {
42+
# Homebrew must run outside a Nix-provided environment.
4043
if declare -F without_nix_env >/dev/null 2>&1; then
4144
without_nix_env "$@"
4245
else
@@ -47,6 +50,7 @@ kanata_macos_run() {
4750
install_kanata_macos() (
4851
set -e
4952

53+
# The macOS setup is maintained for Apple Silicon only.
5054
if [[ "$(uname -s)" != Darwin || "$(uname -m)" != arm64 ]]; then
5155
echo "error: macOS Kanata installation requires Apple Silicon (Darwin arm64)" >&2
5256
exit 1
@@ -67,6 +71,7 @@ install_kanata_macos() (
6771
mkdir -p "$(dirname "$kanata_config")"
6872
ln -sfn "$DOTFILES_DIR/conf/kanata/kanata.kbd" "$kanata_config"
6973

74+
# Kanata needs a system LaunchDaemon; the tray remains a user LaunchAgent.
7075
local daemon_plist="$temporary_dir/dev.kanata.kanata.plist"
7176
cat > "$daemon_plist" <<PLIST
7277
<?xml version="1.0" encoding="UTF-8"?>
@@ -189,11 +194,89 @@ PLIST
189194
" spctl --assess --type execute --verbose '$tray_binary_path'"
190195
)
191196

197+
install_kanata_windows() (
198+
set -e
199+
200+
# Winget currently publishes the Kanata GUI package for x64 only.
201+
case "$(uname -m)" in
202+
x86_64|amd64) ;;
203+
*)
204+
printf 'error: Windows Kanata installation requires x86_64/amd64, got %s\n' "$(uname -m)" >&2
205+
exit 1
206+
;;
207+
esac
208+
209+
if [[ -z "${LOCALAPPDATA:-}" || -z "${USERDOMAIN:-}" || -z "${USERNAME:-}" ]]; then
210+
printf '%s\n' 'error: LOCALAPPDATA, USERDOMAIN, and USERNAME must be set' >&2
211+
exit 1
212+
fi
213+
214+
winget install --exact --id jtroo.kanata_gui --source winget \
215+
--accept-source-agreements --accept-package-agreements
216+
217+
# Winget owns the executable path, so locate the installed portable package.
218+
local package_root="${LOCALAPPDATA}/Microsoft/WinGet/Packages"
219+
local kanata_filename="kanata_windows_gui_winIOv2_x64.exe"
220+
local -a kanata_matches=()
221+
if [[ -d "$package_root" ]]; then
222+
local absolute_package_root
223+
absolute_package_root="$(CDPATH= cd -- "$package_root" && pwd -P)"
224+
while IFS= read -r -d '' kanata_match; do
225+
kanata_matches+=("$kanata_match")
226+
done < <(find "$absolute_package_root" -type f -name "$kanata_filename" -print0)
227+
fi
228+
229+
case "${#kanata_matches[@]}" in
230+
0)
231+
printf 'error: could not find %s beneath %s\n' "$kanata_filename" "$package_root" >&2
232+
exit 1
233+
;;
234+
1)
235+
local kanata_exe="${kanata_matches[0]}"
236+
;;
237+
*)
238+
printf 'error: found %d matching Kanata executables beneath %s; expected exactly one:\n' \
239+
"${#kanata_matches[@]}" "$package_root" >&2
240+
printf ' %s\n' "${kanata_matches[@]}" >&2
241+
exit 1
242+
;;
243+
esac
244+
245+
# Keep the user configuration outside Winget's versioned package directory.
246+
local kanata_dir="${LOCALAPPDATA}/kanata"
247+
local kanata_cfg="${kanata_dir}/kanata.kbd"
248+
mkdir -p "$kanata_dir"
249+
install -m 0644 "$DOTFILES_DIR/conf/kanata/kanata.kbd" "$kanata_cfg"
250+
251+
# Task Scheduler has no working-directory option; use absolute paths instead.
252+
local run_as="${USERDOMAIN}\\${USERNAME}"
253+
schtasks.exe //Create \
254+
//TN "Kanata" \
255+
//SC ONLOGON \
256+
//RU "$run_as" \
257+
//IT \
258+
//TR "\"${kanata_exe}\" --cfg \"${kanata_cfg}\"" \
259+
//F
260+
schtasks.exe //Run //TN "Kanata"
261+
262+
printf '%s\n' \
263+
'Warning: the default LLHOOK/winIOv2 build does not remap administrator-elevated applications unless Kanata itself is elevated.' \
264+
'The Windows installer intentionally does not install Interception.' \
265+
'Future Kanata upgrades are managed via winget.'
266+
)
267+
192268
install_kanata() {
193-
if [[ "$(uname -s)" == Darwin ]]; then
269+
# Route native platforms before consulting Linux distribution metadata.
270+
local os_name
271+
os_name="$(uname -s)"
272+
if [[ "$os_name" == Darwin ]]; then
194273
install_kanata_macos
195274
return
196275
fi
276+
if [[ "$os_name" == MINGW* || "$os_name" == MSYS* || "$os_name" == CYGWIN* ]]; then
277+
install_kanata_windows
278+
return
279+
fi
197280

198281
case "${DISTRIB_ID:-}" in
199282
Arch|EndeavourOS)
@@ -205,7 +288,7 @@ install_kanata() {
205288
install_kanata_deepin || return
206289
;;
207290
*)
208-
echo "error: kanata install is only configured for Arch/EndeavourOS/Deepin" >&2
291+
echo "error: kanata install is only configured for Windows, Arch/EndeavourOS, or Deepin" >&2
209292
exit 1
210293
;;
211294
esac

scripts/pkg.sh

Lines changed: 152 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,97 @@ without_nix_env() {
2222
env -u NIX_PATH -u NIX_PROFILES -u NIX_SSL_CERT_FILE -u NIX_REMOTE -u IN_NIX_SHELL PATH="$clean_path" "$@"
2323
}
2424

25+
install_clash_party_deepin() (
26+
set -e
27+
28+
local architecture
29+
architecture="$(without_nix_env dpkg --print-architecture)" || exit 1
30+
case "$architecture" in
31+
amd64|arm64)
32+
;;
33+
*)
34+
echo "error: unsupported Clash Party architecture: $architecture" >&2
35+
exit 1
36+
;;
37+
esac
38+
39+
local temporary_dir
40+
temporary_dir="$(without_nix_env mktemp -d)" || exit 1
41+
trap 'rm -rf "$temporary_dir"' EXIT
42+
43+
local release_file="$temporary_dir/release.json"
44+
without_nix_env curl \
45+
--location \
46+
--silent \
47+
--show-error \
48+
--fail \
49+
--header 'Accept: application/vnd.github+json' \
50+
--output "$release_file" \
51+
https://api.github.com/repos/mihomo-party-org/clash-party/releases/latest || exit 1
52+
53+
local tag_name
54+
tag_name="$(without_nix_env jq -er '
55+
select(.draft == false and .prerelease == false)
56+
| .tag_name
57+
| select(type == "string" and length > 0)
58+
' "$release_file")" || exit 1
59+
60+
local version="${tag_name#v}"
61+
local deb_name="clash-party-linux-${version}-${architecture}.deb"
62+
local checksum_name="${deb_name}.sha256"
63+
local deb_url
64+
local checksum_url
65+
deb_url="$(without_nix_env jq -er --arg name "$deb_name" "
66+
[.assets[] | select(.name == \$name and .state == \"uploaded\") | .browser_download_url]
67+
| select(length == 1)
68+
| .[0]
69+
| select(type == \"string\" and length > 0)
70+
" "$release_file")" || exit 1
71+
checksum_url="$(without_nix_env jq -er --arg name "$checksum_name" "
72+
[.assets[] | select(.name == \$name and .state == \"uploaded\") | .browser_download_url]
73+
| select(length == 1)
74+
| .[0]
75+
| select(type == \"string\" and length > 0)
76+
" "$release_file")" || exit 1
77+
78+
without_nix_env curl --location --silent --show-error --fail --output "$temporary_dir/$deb_name" "$deb_url" || exit 1
79+
without_nix_env curl --location --silent --show-error --fail --output "$temporary_dir/$checksum_name" "$checksum_url" || exit 1
80+
81+
local expected_checksum
82+
expected_checksum="$(< "$temporary_dir/$checksum_name")"
83+
if [[ ! "$expected_checksum" =~ ^[[:xdigit:]]{64}$ ]]; then
84+
echo "error: invalid Clash Party checksum for $deb_name" >&2
85+
exit 1
86+
fi
87+
88+
local actual_checksum
89+
actual_checksum="$(without_nix_env sha256sum "$temporary_dir/$deb_name")" || exit 1
90+
actual_checksum="${actual_checksum%% *}"
91+
if [[ "${actual_checksum,,}" != "${expected_checksum,,}" ]]; then
92+
echo "error: Clash Party checksum mismatch for $deb_name" >&2
93+
exit 1
94+
fi
95+
96+
cd "$temporary_dir"
97+
without_nix_env sudo apt install -y "./$deb_name" || exit 1
98+
)
99+
25100
install_deepin_packages() {
26101
PACKAGE_FILE="deepin.list"
27102
if [[ ! -f "$DOTFILES_DIR/package/$PACKAGE_FILE" ]]; then
28103
echo "error:$PACKAGE_FILE not exsit!"
29104
exit 1
30105
fi
31106
echo "deb https://pro-store-packages.uniontech.com/appstore eagle-pro appstore" | sudo tee /etc/apt/sources.list.d/appstoreuos.list
32-
without_nix_env sudo apt update
33-
cat "$DOTFILES_DIR/package/$PACKAGE_FILE" | grep -vE '^\s*#' | grep -vE '^\s*$' | xargs -r without_nix_env sudo apt install -y
107+
without_nix_env sudo apt update || return
108+
without_nix_env sudo apt install -y curl jq || return
109+
110+
local packages=()
111+
mapfile -t packages < <(grep -vE '^\s*(#|$)' "$DOTFILES_DIR/package/$PACKAGE_FILE")
112+
if ((${#packages[@]} > 0)); then
113+
without_nix_env sudo apt install -y "${packages[@]}" || return
114+
fi
115+
install_clash_party_deepin
34116
}
35117

36118
install_arch_packages() {
@@ -64,7 +146,34 @@ install_windows_packages() {
64146
cat "$DOTFILES_DIR/package/$PACKAGE_FILE" | grep -vE '^\s*#' | grep -vE '^\s*$' | xargs -r -I {} winget install --id "{}" --exact --accept-package-agreements --accept-source-agreements
65147
}
66148

149+
install_macos_packages() {
150+
local package_file="$DOTFILES_DIR/package/macos.list"
151+
local package
152+
153+
if [[ ! -f "$package_file" ]]; then
154+
echo "error: macos.list not found" >&2
155+
return 1
156+
fi
157+
if ! command -v brew >/dev/null 2>&1; then
158+
echo "error: Homebrew (brew) is required for macOS packages" >&2
159+
return 1
160+
fi
161+
162+
brew update || return 1
163+
while IFS= read -r package || [[ -n "$package" ]]; do
164+
package="${package#${package%%[![:space:]]*}}"
165+
package="${package%${package##*[![:space:]]}}"
166+
[[ -z "$package" || "${package#\#}" != "$package" ]] && continue
167+
brew install --cask "$package" || return 1
168+
done < "$package_file"
169+
}
170+
67171
default_pkg_target() {
172+
if [[ "$(uname -s)" == "Darwin" ]]; then
173+
echo macos
174+
return
175+
fi
176+
68177
if [[ "${OS:-}" == "Windows_NT" ]]; then
69178
echo windows
70179
return
@@ -79,7 +188,7 @@ default_pkg_target() {
79188
;;
80189
*)
81190
echo "error: cannot infer package target for DISTRIB_ID='${DISTRIB_ID:-}'" >&2
82-
echo "usage: $0 pkg <arch|deepin|termux|windows>" >&2
191+
echo "usage: $0 pkg <arch|deepin|termux|windows|macos>" >&2
83192
exit 1
84193
;;
85194
esac
@@ -112,6 +221,15 @@ update_system_packages() {
112221
windows)
113222
winget upgrade --all --accept-package-agreements --accept-source-agreements
114223
;;
224+
macos)
225+
if command -v brew >/dev/null 2>&1; then
226+
brew update
227+
brew upgrade --cask
228+
else
229+
echo "error: Homebrew (brew) is required for macOS updates" >&2
230+
return 1
231+
fi
232+
;;
115233
esac
116234
}
117235

@@ -131,51 +249,66 @@ install_packages() {
131249
case "$target" in
132250
deepin)
133251
install_deepin_packages
134-
install_linux_fonts
135252
link_linux_configs
136253
;;
137254
arch)
138255
install_arch_packages
139-
install_linux_fonts
140256
link_linux_configs
141257
;;
142258
termux)
143259
install_termux_packages
144-
install_linux_fonts
145260
link_linux_configs
146261
;;
147262
windows)
148263
install_windows_packages
149-
install_windows_fonts
150264
link_windows_configs
151265
;;
266+
macos)
267+
install_macos_packages || return 1
268+
link_macos_configs || return 1
269+
;;
152270
*)
153271
echo "error: unknown package target: $target" >&2
154272
exit 1
155273
;;
156274
esac
157275
}
158276

159-
run_pkg() {
277+
run_fonts() {
160278
local target="${1:-}"
161279
if [[ -z "$target" ]]; then
162280
target="$(default_pkg_target)"
163281
fi
164282

165-
install_packages "$target" || true
166-
save_pkg_target "$target"
167-
}
168-
169-
install_kanata() {
170-
case "${DISTRIB_ID:-}" in
171-
Arch|EndeavourOS)
172-
yay -Sy --noconfirm kanata
173-
sudo ln -sfn "$DOTFILES_DIR/conf/kanata/kanata.kbd" /etc/kanata.kbd
174-
sudo systemctl enable --now kanata
283+
case "$target" in
284+
deepin|arch|termux)
285+
install_linux_fonts
286+
;;
287+
windows)
288+
install_windows_fonts
289+
;;
290+
macos)
291+
install_macos_fonts || return 1
175292
;;
176293
*)
177-
echo "error: kanata install is only configured for Arch/EndeavourOS" >&2
294+
echo "error: unknown font target: $target" >&2
178295
exit 1
179296
;;
180297
esac
181298
}
299+
300+
run_pkg() {
301+
local target="${1:-}"
302+
if [[ -z "$target" ]]; then
303+
target="$(default_pkg_target)"
304+
fi
305+
306+
if [[ "$target" == "macos" ]]; then
307+
install_packages "$target" || return 1
308+
save_pkg_target "$target"
309+
return
310+
fi
311+
312+
install_packages "$target" || true
313+
save_pkg_target "$target"
314+
}

0 commit comments

Comments
 (0)