feat: add chinese hanyu input methods

This commit is contained in:
Youwen Wu 2025-08-03 16:12:08 +08:00
parent 8c56482975
commit fcee8ea9e3
Signed by: youwen
GPG key ID: 865658ED1FE61EC3
5 changed files with 256 additions and 90 deletions

View file

@ -65,6 +65,13 @@ in
Whether to enable `hyprsunset` as a daemon. Whether to enable `hyprsunset` as a daemon.
''; '';
}; };
fcitx5.enable = lib.mkOption {
type = lib.types.bool;
default = osConfig.i18n.inputMethod.enable && (osConfig.i18n.inputMethod.type == "fcitx5");
description = ''
Whether to execute fcitx5 at startup.
'';
};
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
@ -86,9 +93,14 @@ in
enable = true; enable = true;
plugins = [ pkgs.hyprlandPlugins.hyprscroller ]; plugins = [ pkgs.hyprlandPlugins.hyprscroller ];
settings = { settings = {
exec-once = [ exec-once =
"hyprctl dispatch workspace 100000" [
]; "hyprctl dispatch workspace 100000"
]
++ (lib.optionals cfg.fcitx5.enable [
"fcitx5 -d -r"
"fcitx5-remote -r"
]);
"$mod" = "SUPER"; "$mod" = "SUPER";
"$Left" = "H"; "$Left" = "H";
"$Right" = "L"; "$Right" = "L";

View file

@ -1,97 +1,105 @@
{ config, lib, ... }: { config, lib, ... }:
let
cfg = config.liminalOS.desktop.hyprland;
in
{ {
config.wayland.windowManager.hyprland.settings.windowrulev2 = config.wayland.windowManager.hyprland.settings.windowrulev2 =
lib.mkIf config.liminalOS.desktop.hyprland.enable lib.mkIf config.liminalOS.desktop.hyprland.enable
[ (
"opacity 0.90 0.90,class:^(librewolf)$" [
"opacity 0.90 0.90,class:^(floorp)$" "opacity 0.90 0.90,class:^(librewolf)$"
"opacity 0.90 0.90,class:^(firefox)$" "opacity 0.90 0.90,class:^(floorp)$"
"opacity 0.90 0.90,class:^(zen-alpha)$" "opacity 0.90 0.90,class:^(firefox)$"
"opacity 0.90 0.90,class:^(zen-beta)$" "opacity 0.90 0.90,class:^(zen-alpha)$"
"opacity 0.90 0.90,class:^(zen)$" "opacity 0.90 0.90,class:^(zen-beta)$"
"opacity 0.90 0.90,class:^(Brave-browser)$" "opacity 0.90 0.90,class:^(zen)$"
"opacity 0.80 0.80,class:^(Steam)$" "opacity 0.90 0.90,class:^(Brave-browser)$"
"opacity 0.80 0.80,class:^(steam)$" "opacity 0.80 0.80,class:^(Steam)$"
"opacity 0.80 0.80,class:^(steamwebhelper)$" "opacity 0.80 0.80,class:^(steam)$"
"opacity 0.80 0.80,class:^(Spotify)$" "opacity 0.80 0.80,class:^(steamwebhelper)$"
"opacity 0.80 0.80,initialTitle:^(Spotify Premium)$" "opacity 0.80 0.80,class:^(Spotify)$"
"opacity 0.80 0.80,initialTitle:^(Spotify Free)$" "opacity 0.80 0.80,initialTitle:^(Spotify Premium)$"
"opacity 0.80 0.80,class:^(code-oss)$" "opacity 0.80 0.80,initialTitle:^(Spotify Free)$"
"opacity 0.80 0.80,class:^(Code)$" "opacity 0.80 0.80,class:^(code-oss)$"
"opacity 0.80 0.80,class:^(code-url-handler)$" "opacity 0.80 0.80,class:^(Code)$"
"opacity 0.80 0.80,class:^(code-insiders-url-handler)$" "opacity 0.80 0.80,class:^(code-url-handler)$"
"opacity 0.80 0.80,class:^(kitty)$" "opacity 0.80 0.80,class:^(code-insiders-url-handler)$"
"opacity 0.80 0.80,class:^(neovide)$" "opacity 0.80 0.80,class:^(kitty)$"
"opacity 0.80 0.80,class:^(org.kde.dolphin)$" "opacity 0.80 0.80,class:^(neovide)$"
"opacity 0.80 0.80,class:^(org.gnome.Nautilus)$" "opacity 0.80 0.80,class:^(org.kde.dolphin)$"
"opacity 0.80 0.80,class:^(org.kde.ark)$" "opacity 0.80 0.80,class:^(org.gnome.Nautilus)$"
"opacity 0.80 0.80,class:^(nwg-look)$" "opacity 0.80 0.80,class:^(org.kde.ark)$"
"opacity 0.80 0.80,class:^(qt5ct)$" "opacity 0.80 0.80,class:^(nwg-look)$"
"opacity 0.80 0.80,class:^(qt6ct)$" "opacity 0.80 0.80,class:^(qt5ct)$"
"opacity 0.80 0.80,class:^(kvantummanager)$" "opacity 0.80 0.80,class:^(qt6ct)$"
"opacity 0.80 0.80,class:^(waypaper)$" "opacity 0.80 0.80,class:^(kvantummanager)$"
"opacity 0.80 0.80,class:^(org.pulseaudio.pavucontrol)$" "opacity 0.80 0.80,class:^(waypaper)$"
"opacity 0.80 0.80,class:^(com.github.wwmm.easyeffects)$" "opacity 0.80 0.80,class:^(org.pulseaudio.pavucontrol)$"
"opacity 0.80 0.80,class:^(thunderbird)$" "opacity 0.80 0.80,class:^(com.github.wwmm.easyeffects)$"
"opacity 0.80 0.80,class:^(thunderbird)$"
"opacity 0.90 0.90,class:^(com.github.rafostar.Clapper)$ # Clapper-Gtk" "opacity 0.90 0.90,class:^(com.github.rafostar.Clapper)$ # Clapper-Gtk"
"opacity 0.80 0.80,class:^(com.github.tchx84.Flatseal)$ # Flatseal-Gtk" "opacity 0.80 0.80,class:^(com.github.tchx84.Flatseal)$ # Flatseal-Gtk"
"opacity 0.80 0.80,class:^(hu.kramo.Cartridges)$ # Cartridges-Gtk" "opacity 0.80 0.80,class:^(hu.kramo.Cartridges)$ # Cartridges-Gtk"
"opacity 0.80 0.80,class:^(com.obsproject.Studio)$ # Obs-Qt" "opacity 0.80 0.80,class:^(com.obsproject.Studio)$ # Obs-Qt"
"opacity 0.80 0.80,class:^(gnome-boxes)$ # Boxes-Gtk" "opacity 0.80 0.80,class:^(gnome-boxes)$ # Boxes-Gtk"
"opacity 0.80 0.80,class:^(discord)$ # Discord-Electron" "opacity 0.80 0.80,class:^(discord)$ # Discord-Electron"
"opacity 0.80 0.80,class:^(vesktop)$ # Vesktop-Electron" "opacity 0.80 0.80,class:^(vesktop)$ # Vesktop-Electron"
"opacity 0.80 0.80,class:^(Element)$ # Vesktop-Electron" "opacity 0.80 0.80,class:^(Element)$ # Vesktop-Electron"
"opacity 0.80 0.80,class:^(ArmCord)$ # ArmCord-Electron" "opacity 0.80 0.80,class:^(ArmCord)$ # ArmCord-Electron"
"opacity 0.80 0.80,class:^(app.drey.Warp)$ # Warp-Gtk" "opacity 0.80 0.80,class:^(app.drey.Warp)$ # Warp-Gtk"
"opacity 0.80 0.80,class:^(net.davidotek.pupgui2)$ # ProtonUp-Qt" "opacity 0.80 0.80,class:^(net.davidotek.pupgui2)$ # ProtonUp-Qt"
"opacity 0.80 0.80,class:^(yad)$ # Protontricks-Gtk" "opacity 0.80 0.80,class:^(yad)$ # Protontricks-Gtk"
"opacity 0.80 0.80,class:^(signal)$ # Signal-Gtk" "opacity 0.80 0.80,class:^(signal)$ # Signal-Gtk"
"opacity 0.80 0.80,class:^(io.github.alainm23.planify)$ # planify-Gtk" "opacity 0.80 0.80,class:^(io.github.alainm23.planify)$ # planify-Gtk"
"opacity 0.80 0.80,class:^(io.gitlab.theevilskeleton.Upscaler)$ # Upscaler-Gtk" "opacity 0.80 0.80,class:^(io.gitlab.theevilskeleton.Upscaler)$ # Upscaler-Gtk"
"opacity 0.80 0.80,class:^(com.github.unrud.VideoDownloader)$ # VideoDownloader-Gtk" "opacity 0.80 0.80,class:^(com.github.unrud.VideoDownloader)$ # VideoDownloader-Gtk"
"opacity 0.80 0.80,class:^(lutris)$ # Lutris game launcher" "opacity 0.80 0.80,class:^(lutris)$ # Lutris game launcher"
"opacity 0.80 0.70,class:^(pavucontrol)$" "opacity 0.80 0.70,class:^(pavucontrol)$"
"opacity 0.80 0.70,class:^(blueman-manager)$" "opacity 0.80 0.70,class:^(blueman-manager)$"
"opacity 0.80 0.70,class:^(nm-applet)$" "opacity 0.80 0.70,class:^(nm-applet)$"
"opacity 0.80 0.70,class:^(nm-connection-editor)$" "opacity 0.80 0.70,class:^(nm-connection-editor)$"
"opacity 0.80 0.70,class:^(org.kde.polkit-kde-authentication-agent-1)$" "opacity 0.80 0.70,class:^(org.kde.polkit-kde-authentication-agent-1)$"
"float,class:^(org.kde.dolphin)$,title:^(Progress Dialog Dolphin)$" "float,class:^(org.kde.dolphin)$,title:^(Progress Dialog Dolphin)$"
"float,class:^(org.kde.dolphin)$,title:^(Copying Dolphin)$" "float,class:^(org.kde.dolphin)$,title:^(Copying Dolphin)$"
"float,title:^(Picture-in-Picture)$" "float,title:^(Picture-in-Picture)$"
"float,class:^(librewolf)$,title:^(Library)$" "float,class:^(librewolf)$,title:^(Library)$"
"float,class:^(floorp)$,title:^(Library)$" "float,class:^(floorp)$,title:^(Library)$"
"float,class:^(zen-alpha)$,title:^(Library)$" "float,class:^(zen-alpha)$,title:^(Library)$"
"float,class:^(zen-beta)$,title:^(Library)$" "float,class:^(zen-beta)$,title:^(Library)$"
"float,class:^(zen)$,title:^(Library)$" "float,class:^(zen)$,title:^(Library)$"
''float,class:^(zen)$,title:^(.*Extension: \(Bitwarden Password Manager\).*)$'' ''float,class:^(zen)$,title:^(.*Extension: \(Bitwarden Password Manager\).*)$''
"float,class:^(vlc)$" "float,class:^(vlc)$"
"float,class:^(kvantummanager)$" "float,class:^(kvantummanager)$"
"float,class:^(qt5ct)$" "float,class:^(qt5ct)$"
"float,class:^(qt6ct)$" "float,class:^(qt6ct)$"
"float,class:^(nwg-look)$" "float,class:^(nwg-look)$"
"float,class:^(org.kde.ark)$" "float,class:^(org.kde.ark)$"
"float,class:^(org.pulseaudio.pavucontrol)$" "float,class:^(org.pulseaudio.pavucontrol)$"
"float,class:^(com.github.rafostar.Clapper)$ # Clapper-Gtk" "float,class:^(com.github.rafostar.Clapper)$ # Clapper-Gtk"
"float,class:^(app.drey.Warp)$ # Warp-Gtk" "float,class:^(app.drey.Warp)$ # Warp-Gtk"
"float,class:^(net.davidotek.pupgui2)$ # ProtonUp-Qt" "float,class:^(net.davidotek.pupgui2)$ # ProtonUp-Qt"
"float,class:^(yad)$ # Protontricks-Gtk" "float,class:^(yad)$ # Protontricks-Gtk"
"float,class:^(eog)$ # Imageviewer-Gtk" "float,class:^(eog)$ # Imageviewer-Gtk"
"float,class:^(io.github.alainm23.planify)$ # planify-Gtk" "float,class:^(io.github.alainm23.planify)$ # planify-Gtk"
"float,class:^(io.gitlab.theevilskeleton.Upscaler)$ # Upscaler-Gtk" "float,class:^(io.gitlab.theevilskeleton.Upscaler)$ # Upscaler-Gtk"
"float,class:^(com.github.unrud.VideoDownloader)$ # VideoDownloader-Gkk" "float,class:^(com.github.unrud.VideoDownloader)$ # VideoDownloader-Gkk"
"float,class:^(blueman-manager)$" "float,class:^(blueman-manager)$"
"float,class:^(nm-applet)$" "float,class:^(nm-applet)$"
"float,class:^(nm-connection-editor)$" "float,class:^(nm-connection-editor)$"
"float,class:^(org.kde.polkit-kde-authentication-agent-1)$" "float,class:^(org.kde.polkit-kde-authentication-agent-1)$"
"opacity 0.80 0.80,class:^(org.freedesktop.impl.portal.desktop.gtk)$" "opacity 0.80 0.80,class:^(org.freedesktop.impl.portal.desktop.gtk)$"
"opacity 0.80 0.80,class:^(org.freedesktop.impl.portal.desktop.hyprland)$" "opacity 0.80 0.80,class:^(org.freedesktop.impl.portal.desktop.hyprland)$"
''size 70% 70%,class:^(zen)$,title:^(.*Extension: \(Bitwarden Password Manager\).*)$'' ''size 70% 70%,class:^(zen)$,title:^(.*Extension: \(Bitwarden Password Manager\).*)$''
"size 50% 50%,class:^(org.pulseaudio.pavucontrol)" "size 50% 50%,class:^(org.pulseaudio.pavucontrol)"
"stayfocused, class:^(pinentry-)" # fix pinentry losing focus "stayfocused, class:^(pinentry-)" # fix pinentry losing focus
]; ]
++ (lib.optionals cfg.fcitx5.enable [
"pseudo, class:^(fcitx)"
])
);
} }

View file

@ -15,6 +15,7 @@
./wine ./wine
./wsl ./wsl
./graphics ./graphics
./localization
]; ];
options.liminalOS.enable = lib.mkOption { options.liminalOS.enable = lib.mkOption {

View file

@ -0,0 +1,143 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.liminalOS.desktop.localization;
in
{
options.liminalOS.desktop.localization = {
chinese.input.enable = lib.mkEnableOption "Chinese input method using fcitx5.";
chinese.script = lib.mkOption {
type = lib.types.enum [
"simplified"
"traditional"
];
default = "simplified";
description = ''
Whether to use simplified or traditional characters.
'';
};
};
config = lib.mkIf cfg.chinese.input.enable {
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5.waylandFrontend = true;
fcitx5.addons = with pkgs; [
fcitx5-gtk
fcitx5-chinese-addons
fcitx5-tokyonight
];
fcitx5.settings.globalOptions = {
Hotkey = {
# Enumerate when press trigger key repeatedly
EnumerateWithTriggerKeys = true;
# Temporally switch between first and current Input Method
AltTriggerKeys = null;
# Enumerate Input Method Forward
EnumerateForwardKeys = null;
# Enumerate Input Method Backward
EnumerateBackwardKeys = null;
# Skip first input method while enumerating
EnumerateSkipFirst = false;
# Enumerate Input Method Group Forward
EnumerateGroupForwardKeys = null;
# Enumerate Input Method Group Backward
EnumerateGroupBackwardKeys = null;
# Activate Input Method
ActivateKeys = null;
# Deactivate Input Method
DeactivateKeys = null;
# Default Previous page
PrevPage = null;
# Default Next page
NextPage = null;
# Default Previous Candidate
PrevCandidate = null;
# Default Next Candidate
NextCandidate = null;
# Toggle embedded preedit
TogglePreedit = null;
# Time limit in milliseconds for triggering modifier key shortcuts
ModifierOnlyKeyTimeout = 250;
};
"Hotkey/TriggerKeys" = {
"0" = "Control+Super+space";
"1" = "Zenkaku_Hankaku";
"2" = "Hangul";
};
Behavior = {
# Active By Default;
ActiveByDefault = false;
# Reset state on Focus In;
resetStateWhenFocusIn = "No";
# Share Input State;
ShareInputState = "No";
# Show preedit in application;
PreeditEnabledByDefault = true;
# Show Input Method Information when switch input method;
ShowInputMethodInformation = true;
# Show Input Method Information when changing focus;
showInputMethodInformationWhenFocusIn = false;
# Show compact input method information;
CompactInputMethodInformation = true;
# Show first input method information;
ShowFirstInputMethodInformation = true;
# Default page size;
DefaultPageSize = 10;
# Override Xkb Option;
OverrideXkbOption = false;
# Custom Xkb Option;
CustomXkbOption = "";
# Force Enabled Addons;
EnabledAddons = "";
# Force Disabled Addons;
DisabledAddons = "";
# Preload input method to be used by default;
PreloadInputMethod = true;
# Allow input method in the password field;
AllowInputMethodForPassword = false;
# Show preedit text when typing password;
ShowPreeditForPassword = false;
# Interval of saving user data in minutes;
AutoSavePeriod = 30;
};
};
fcitx5.settings.inputMethod = {
"Groups/0" = {
# Group Name
Name = "Default";
# Layout
"Default Layout" = "us";
# Default Input Method
DefaultIM = "pinyin";
};
"Groups/0/Items/0" = {
# Name
Name = "keyboard-us";
# Layout
Layout = "";
};
"Groups/0/Items/1" = {
# Name
Name = "pinyin";
# Layout
Layout = "";
};
"GroupOrder" = {
"0" = "Default";
};
};
};
};
}

View file

@ -144,6 +144,8 @@
polarity = lib.mkDefault "dark"; polarity = lib.mkDefault "dark";
}; };
liminalOS.desktop.localization.chinese.input.enable = true;
environment.etc.polarity.text = lib.mkDefault "dusk"; environment.etc.polarity.text = lib.mkDefault "dusk";
specialisation = { specialisation = {