diff --git a/README.md b/README.md index beed8db..c66c0c1 100644 --- a/README.md +++ b/README.md @@ -113,39 +113,50 @@ Both **VNI** and **Telex** are fully supported. Switch via **Ctrl+LeftShift** or ## Installation -### Build from Source +### One-Command Install (recommended) + +Works on both **Linux Mint** and **Ubuntu** (including 24.04+ Wayland): ```bash -# Dependencies (Ubuntu/Debian) -sudo apt install git curl build-essential pkg-config \ - libx11-dev libxtst-dev libevdev-dev libdbus-1-dev +git clone https://github.com/vndangkhoa/vietc.git /tmp/vietc \ + && cd /tmp/vietc && sudo ./install.sh +``` -# Clone and build +The script will: +1. Install build + runtime dependencies +2. Compile all binaries +3. Install to `/usr/bin/` +4. Set up uinput udev rules +5. Add your user to the `input` group + +**After install:** Log out and log back in, then launch `vietc-tray` from your application menu. + +### Manual Build & Run + +```bash +# Install dependencies +sudo apt install git curl build-essential pkg-config \ + libx11-dev libxtst-dev libevdev-dev libdbus-1-dev wl-clipboard + +# Enable accessibility (Ubuntu Wayland — for password detection) +gsettings set org.gnome.desktop.a11y.applications screen-reader-enabled true + +# Build git clone https://github.com/vndangkhoa/vietc.git cd vietc cargo build --release -# Add user to input group (for keyboard capture) -sudo usermod -aG input $USER -# Log out and log back in - -# Run +# Run (Mint — no sudo needed for uinput) ./target/release/vietc + +# Run (Ubuntu — needs sudo for keyboard grab) +sudo ./target/release/vietc ``` -### Wayland (Ubuntu 24.04+) — Additional steps +### Uninstall ```bash -sudo apt install wl-clipboard -gsettings set org.gnome.desktop.a11y.applications screen-reader-enabled true -``` - -### uinput Access (recommended) - -```bash -sudo modprobe uinput -echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-uinput.rules -sudo udevadm control --reload-rules && sudo udevadm trigger +sudo ./uninstall.sh ``` --- diff --git a/install.sh b/install.sh index 21a37b8..6ea1ee2 100755 --- a/install.sh +++ b/install.sh @@ -3,285 +3,110 @@ # Viet+ — Vietnamese Input Method Installer set -euo pipefail -# Color codes for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -BLUE='\033[0;34m' -NC='\033[0;69m' # No Color -NC='\033[0m' +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'; NC='\033[0m' -echo -e "${BLUE}=== Viet+ Installation Script ===${NC}" +[ "$EUID" -ne 0 ] && echo -e "${RED}Please run with sudo.${NC}" && exit 1 -# Check for root privilege requirement -check_root() { - if [ "$EUID" -ne 0 ]; then - echo -e "${RED}Error: This script must be run as root (or with sudo) to install system files and update permissions.${NC}" - echo -e "Please re-run as: ${YELLOW}sudo $0${NC}" - exit 1 - fi -} +echo -e "${GREEN}=== Viet+ Installer ===${NC}" -# Detect distribution -detect_distro() { - if [ -f /etc/os-release ]; then - . /etc/os-release - DISTRO=$ID - DISTRO_LIKE=${ID_LIKE:-""} - else - echo -e "${RED}Error: Cannot detect Linux distribution (/etc/os-release missing).${NC}" - exit 1 - fi - echo -e "Detected OS: ${GREEN}${DISTRO}${NC}" -} +# Detect distro +[ -f /etc/os-release ] && . /etc/os-release +DISTRO="${ID:-unknown}" +echo "Detected: $DISTRO" -# Install dependencies using package manager -install_dependencies() { - local mode=$1 # "build" or "run" - echo -e "Installing ${mode} dependencies..." - +# Install dependencies +install_deps() { case "$DISTRO" in - ubuntu|debian|raspbian|pop|mint|linuxmint|neon|zorin|elementary) + ubuntu|debian|linuxmint|mint|pop|neon|zorin|elementary) export DEBIAN_FRONTEND=noninteractive apt-get update -y - if [ "$mode" = "build" ]; then - apt-get install -y build-essential pkg-config libx11-dev libxtst-dev libdbus-1-dev libevdev-dev libwayland-dev curl - fi - apt-get install -y libevdev2 libdbus-1-3 libx11-6 libxtst6 xclip wl-clipboard libwayland-client0 curl + apt-get install -y build-essential pkg-config libx11-dev libxtst-dev \ + libdbus-1-dev libevdev-dev curl git + apt-get install -y libevdev2 libdbus-1-3 libx11-6 libxtst6 xclip wl-clipboard ;; fedora|rhel|centos) - if [ "$mode" = "build" ]; then - dnf install -y gcc pkgconfig libX11-devel libXtst-devel dbus-devel libevdev-devel - fi + dnf install -y gcc pkgconfig libX11-devel libXtst-devel dbus-devel libevdev-devel curl git dnf install -y libevdev libX11 libXtst dbus-libs xclip wl-clipboard ;; - arch|manjaro|arco) - if [ "$mode" = "build" ]; then - pacman -Sy --needed --noconfirm base-devel pkgconf libx11 libxtst dbus libevdev - fi + arch|manjaro) + pacman -Sy --needed --noconfirm base-devel pkgconf libx11 libxtst dbus libevdev curl git pacman -Sy --needed --noconfirm libevdev libx11 libxtst dbus xclip wl-clipboard ;; *) - if [[ "$DISTRO_LIKE" == *"ubuntu"* || "$DISTRO_LIKE" == *"debian"* ]]; then - export DEBIAN_FRONTEND=noninteractive - apt-get update -y - if [ "$mode" = "build" ]; then - apt-get install -y build-essential pkg-config libx11-dev libxtst-dev libdbus-1-dev libevdev-dev libwayland-dev curl - fi - apt-get install -y libevdev2 libdbus-1-3 libx11-6 libxtst6 xclip wl-clipboard libwayland-client0 curl - else - echo -e "${YELLOW}Warning: Unsupported distribution '${DISTRO}'. Please make sure you have the following packages installed manually:${NC}" - echo -e " - libevdev, libdbus-1, libx11, libxtst, xclip, wl-clipboard" - if [ "$mode" = "build" ]; then - echo -e " - gcc, pkg-config, and development headers for the above libraries." - fi - fi + echo -e "${YELLOW}Unsupported: $DISTRO. Install deps manually.${NC}" ;; esac } -# Check for Rust compiler (needed only for source build) -check_rust() { - if [ -n "${SUDO_USER:-}" ]; then - local user_home - user_home="$(getent passwd "$SUDO_USER" 2>/dev/null | cut -d: -f6 || echo "/home/$SUDO_USER")" - export CARGO_HOME="$user_home/.cargo" - export RUSTUP_HOME="$user_home/.rustup" - export PATH="$CARGO_HOME/bin:$PATH" - fi +install_deps - if ! command -v cargo >/dev/null 2>&1; then - echo -e "${YELLOW}Rust toolchain not found.${NC}" - read -p "Would you like to install Rust toolchain now? [Y/n] " -n 1 -r - echo - if [[ $REPLY =~ ^[Nn]$ ]]; then - echo -e "${RED}Error: Cargo is required to build from source.${NC}" - exit 1 - fi - echo "Installing Rust via rustup.rs..." - # Run rustup installer as the original non-root user if SUDO_USER is set - if [ -n "${SUDO_USER:-}" ]; then - su - "$SUDO_USER" -c "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y" - else - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - export PATH="$HOME/.cargo/bin:$PATH" - fi - fi - echo -e "Rust version: ${GREEN}$(rustc --version)${NC}" -} - -# Determine if we are installing from source tree or prebuilt binaries -check_root # Need root to perform OS checks and dependencies install -detect_distro - -SOURCE_DIR="" -if [ -f "./Cargo.toml" ] && [ -d "./engine" ] && [ -d "./ui" ]; then - SOURCE_DIR=$(pwd) - echo -e "Status: Running from ${GREEN}Source Tree${NC}" -else - echo -e "Status: Running from ${GREEN}Release Package${NC}" +# Install Rust if missing +if ! command -v cargo &>/dev/null; then + echo "Installing Rust..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + export PATH="$HOME/.cargo/bin:$PATH" fi -# 1. Compile or Stage Binaries -if [ -n "$SOURCE_DIR" ]; then - install_dependencies "build" - check_rust - - echo -e "=== Compiling Viet+ ===" - # Build core components - cargo build --release - # Build UI - (cd ui && cargo build --release) - # Compile C helper - gcc -O2 -o target/release/vietc-xrecord packaging/deb/vietc-xrecord.c -lX11 -lXtst - - BIN_DAEMON="target/release/vietc" - BIN_CLI="target/release/vietc-cli" - BIN_UINPUTD="target/release/vietc-uinputd" - BIN_TRAY="ui/target/release/vietc-tray" - BIN_XRECORD="target/release/vietc-xrecord" - - FILE_RULES="packaging/99-vietc.rules" - FILE_DESKTOP="packaging/deb/vietc.desktop" - FILE_CONFIG="vietc.toml" - DIR_ICONS="packaging/icons" -else - # Install from prebuilt release folder - install_dependencies "run" - - BIN_DAEMON="bin/vietc-daemon" - BIN_CLI="bin/vietc-cli" - BIN_UINPUTD="bin/vietc-uinputd" - BIN_TRAY="bin/vietc-tray" - BIN_XRECORD="bin/vietc-xrecord" - - FILE_RULES="udev/99-vietc.rules" - FILE_DESKTOP="desktop/vietc.desktop" - FILE_CONFIG="config/config.toml" - DIR_ICONS="icons" - - # Validation - if [ ! -f "$BIN_DAEMON" ] && [ -f "bin/vietc" ]; then - BIN_DAEMON="bin/vietc" # Fallback if not renamed in build - fi -fi - -# Kill running instances before installing new files -echo "Stopping any running Viet+ processes..." +# Kill old processes pkill -x vietc-tray 2>/dev/null || true pkill -x vietc-daemon 2>/dev/null || true -pkill -x vietc-uinputd 2>/dev/null || true pkill -x vietc 2>/dev/null || true -# 2. Install Binaries -echo "Installing binaries to /usr/bin/..." -cp "$BIN_DAEMON" /usr/bin/vietc-daemon -cp "$BIN_CLI" /usr/bin/ -cp "$BIN_UINPUTD" /usr/bin/ -cp "$BIN_TRAY" /usr/bin/ -cp "$BIN_XRECORD" /usr/bin/ -chmod 755 /usr/bin/vietc-daemon /usr/bin/vietc-cli /usr/bin/vietc-uinputd /usr/bin/vietc-tray /usr/bin/vietc-xrecord - -# Remove old local path binaries to prevent shadows -rm -f /usr/local/bin/vietc-tray /usr/local/bin/vietc /usr/local/bin/vietc-daemon \ - /usr/local/bin/vietc-cli /usr/local/bin/vietc-uinputd /usr/local/bin/vietc-xrecord 2>/dev/null || true - -# 3. Install Icons -echo "Installing icons..." -mkdir -p /usr/share/icons/hicolor/256x256/apps -cp "$DIR_ICONS/vietc.svg" /usr/share/icons/hicolor/256x256/apps/ -cp "$DIR_ICONS/vietc-vn.svg" /usr/share/icons/hicolor/256x256/apps/ -cp "$DIR_ICONS/vietc-en.svg" /usr/share/icons/hicolor/256x256/apps/ -if command -v gtk-update-icon-cache >/dev/null 2>&1; then - gtk-update-icon-cache -f /usr/share/icons/hicolor/ >/dev/null 2>&1 || true +# Build +echo "Building..." +cargo build --release +(cd ui && cargo build --release) +if command -v gcc &>/dev/null && [ -f packaging/deb/vietc-xrecord.c ]; then + gcc -O2 -o target/release/vietc-xrecord packaging/deb/vietc-xrecord.c -lX11 -lXtst 2>/dev/null || true fi -# 4. Install Desktop File -echo "Installing desktop launcher..." -mkdir -p /usr/share/applications -cp "$FILE_DESKTOP" /usr/share/applications/ +# Install binaries +echo "Installing to /usr/bin/..." +cp target/release/vietc /usr/bin/vietc-daemon +cp target/release/vietc-cli /usr/bin/ +cp target/release/vietc-uinputd /usr/bin/ +cp ui/target/release/vietc-tray /usr/bin/ +[ -f target/release/vietc-xrecord ] && cp target/release/vietc-xrecord /usr/bin/ +chmod 755 /usr/bin/vietc-daemon /usr/bin/vietc-cli /usr/bin/vietc-uinputd /usr/bin/vietc-tray 2>/dev/null || true -if command -v update-desktop-database >/dev/null 2>&1; then - update-desktop-database /usr/share/applications >/dev/null 2>&1 || true -fi +# Clean old /usr/local/bin/ binaries +rm -f /usr/local/bin/vietc /usr/local/bin/vietc-daemon /usr/local/bin/vietc-cli \ + /usr/local/bin/vietc-uinputd /usr/local/bin/vietc-tray /usr/local/bin/vietc-xrecord 2>/dev/null || true -# 5. Install Systemd User Service -echo "Installing systemd user service..." -mkdir -p /usr/lib/systemd/user -cat > /usr/lib/systemd/user/vietc.service << 'SERVICE' -[Unit] -Description=Viet+ Vietnamese IME Tray -PartOf=graphical-session.target +# Udev rules for uinput +echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' > /etc/udev/rules.d/99-vietc.rules +udevadm control --reload-rules 2>/dev/null || true +udevadm trigger 2>/dev/null || true -[Service] -Type=simple -ExecStart=/usr/bin/vietc-tray -Restart=on-failure -RestartSec=5 - -[Install] -WantedBy=default.target -SERVICE - -# 6. Install XDG Autostart -echo "Setting up autostart..." -mkdir -p /etc/xdg/autostart -cat > /etc/xdg/autostart/vietc-tray.desktop << 'AUTOSTART' -[Desktop Entry] -Type=Application -Name=Viet+ Tray -Comment=Vietnamese Input Method Tray -Exec=vietc-tray -Icon=vietc -Terminal=false -Categories=Utility; -StartupNotify=false -NoDisplay=true -AUTOSTART - -# 7. Install default config -echo "Installing default configuration..." -mkdir -p /etc/vietc -cp "$FILE_CONFIG" /etc/vietc/config.toml -chmod 644 /etc/vietc/config.toml - -# 8. Configure permissions (uinput) -echo "Installing udev rules for uinput access..." -mkdir -p /etc/udev/rules.d -cp "$FILE_RULES" /etc/udev/rules.d/99-vietc.rules -chmod 644 /etc/udev/rules.d/99-vietc.rules - -echo "Reloading udev rules..." -if command -v udevadm >/dev/null 2>&1; then - udevadm control --reload-rules >/dev/null 2>&1 || true - udevadm trigger --subsystem-match=misc >/dev/null 2>&1 || true -fi - -# Add active users to input group -INSTALLING_USER="${SUDO_USER:-${USER:-}}" +# User setup +INSTALLING_USER="${SUDO_USER:-$USER}" if [ -n "$INSTALLING_USER" ] && [ "$INSTALLING_USER" != "root" ]; then - echo "Adding user '$INSTALLING_USER' to group 'input'..." - if ! groups "$INSTALLING_USER" 2>/dev/null | grep -qw input; then - if command -v usermod >/dev/null 2>&1; then - usermod -aG input "$INSTALLING_USER" || true - elif command -v adduser >/dev/null 2>&1; then - adduser "$INSTALLING_USER" input || true - fi - fi - - # Remove any old conflicting configurations in user home - user_home="$(getent passwd "$INSTALLING_USER" 2>/dev/null | cut -d: -f6 || true)" - if [ -n "$user_home" ]; then - rm -f "$user_home/.config/vietc/config.toml" 2>/dev/null || true - rm -f "$user_home/.config/vietc/overrides.toml" 2>/dev/null || true - rm -f "$user_home/.config/vietc/.first-launch-done" 2>/dev/null || true - fi + adduser "$INSTALLING_USER" input 2>/dev/null || true + rm -f "$(getent passwd "$INSTALLING_USER" | cut -d: -f6)/.config/vietc/config.toml" 2>/dev/null || true fi -if command -v systemctl >/dev/null 2>&1; then - systemctl --global daemon-reload >/dev/null 2>&1 || true -fi +# Create default config +mkdir -p /etc/vietc +cat > /etc/vietc/config.toml << 'EOF' +input_method = "vni" +toggle_key = "space" +toggle_method_key = "shift" +start_enabled = true +grab = true -echo -e "\n${GREEN}=== Installation Completed Successfully! ===${NC}" -echo -e "Please ${YELLOW}LOG OUT and LOG BACK IN${NC} to activate group permissions." -echo -e "Once logged back in, you can start Viet+ from your application launcher menu." +[password_detection] +enabled = true +check_atspi2 = true +check_window_title = true +title_keywords = ["password", "passphrase", "secret", "mặt khẩu", "sudo"] +password_apps = ["pinentry", "pinentry-gtk-2", "pinentry-qt", "kwallet"] + +[app_state] +enabled = true +english_apps = ["code", "vim"] +vietnamese_apps = ["telegram", "discord", "firefox"] +bypass_apps = ["kitty", "alacritty", "steam"] +EOF + +echo -e "${GREEN}=== Done! ===${NC}" +echo -e "${YELLOW}Log out and log back in, then run: vietc-tray${NC}" diff --git a/uninstall.sh b/uninstall.sh index c4293f2..34b9c59 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -3,60 +3,22 @@ # Viet+ — Vietnamese Input Method Uninstaller set -euo pipefail -# Color codes for output -RED='\033[0;31m' -GREEN='\033[0;32m' -NC='\033[0m' # No Color +RED='\033[0;31m'; GREEN='\033[0;32m'; NC='\033[0m' -echo -e "${RED}=== Viet+ Uninstallation Script ===${NC}" +[ "$EUID" -ne 0 ] && echo -e "${RED}Please run with sudo.${NC}" && exit 1 -if [ "$EUID" -ne 0 ]; then - echo -e "${RED}Error: This script must be run as root (or with sudo).${NC}" - exit 1 -fi +echo -e "${RED}=== Viet+ Uninstaller ===${NC}" -echo "Stopping any running Viet+ processes..." pkill -x vietc-tray 2>/dev/null || true pkill -x vietc-daemon 2>/dev/null || true -pkill -x vietc-uinputd 2>/dev/null || true pkill -x vietc 2>/dev/null || true -echo "Removing binaries..." -rm -f /usr/bin/vietc-daemon /usr/bin/vietc-cli /usr/bin/vietc-uinputd /usr/bin/vietc-tray /usr/bin/vietc-xrecord -rm -f /usr/local/bin/vietc-daemon /usr/local/bin/vietc-cli /usr/local/bin/vietc-uinputd /usr/local/bin/vietc-tray /usr/local/bin/vietc-xrecord /usr/local/bin/vietc - -echo "Removing icons..." -rm -f /usr/share/icons/hicolor/256x256/apps/vietc.svg -rm -f /usr/share/icons/hicolor/256x256/apps/vietc-vn.svg -rm -f /usr/share/icons/hicolor/256x256/apps/vietc-en.svg - -if command -v gtk-update-icon-cache >/dev/null 2>&1; then - gtk-update-icon-cache -f /usr/share/icons/hicolor/ >/dev/null 2>&1 || true -fi - -echo "Removing desktop files and autostart..." -rm -f /usr/share/applications/vietc.desktop -rm -f /etc/xdg/autostart/vietc-tray.desktop - -if command -v update-desktop-database >/dev/null 2>&1; then - update-desktop-database /usr/share/applications >/dev/null 2>&1 || true -fi - -echo "Removing systemd service..." -rm -f /usr/lib/systemd/user/vietc.service - -echo "Removing udev rules..." +rm -f /usr/bin/vietc-daemon /usr/bin/vietc-cli /usr/bin/vietc-uinputd \ + /usr/bin/vietc-tray /usr/bin/vietc-xrecord +rm -f /usr/local/bin/vietc /usr/local/bin/vietc-daemon /usr/local/bin/vietc-cli \ + /usr/local/bin/vietc-uinputd /usr/local/bin/vietc-tray /usr/local/bin/vietc-xrecord rm -f /etc/udev/rules.d/99-vietc.rules -if command -v udevadm >/dev/null 2>&1; then - udevadm control --reload-rules >/dev/null 2>&1 || true - udevadm trigger --subsystem-match=misc >/dev/null 2>&1 || true -fi +rm -f /etc/vietc/config.toml +rmdir /etc/vietc 2>/dev/null || true -echo "Removing global configuration..." -rm -rf /etc/vietc - -if command -v systemctl >/dev/null 2>&1; then - systemctl --global daemon-reload >/dev/null 2>&1 || true -fi - -echo -e "\n${GREEN}=== Uninstallation Completed Successfully! ===${NC}" +echo -e "${GREEN}=== Done! ===${NC}"