Using AutoHotkey to Emulate macOS Cmd + ` Window Switching on Windows OS

As a long-time Windows user, I experienced the convenience of Cmd+ after getting a MacBook Air M1. Especially when switching between different windows within the same application, this shortcut is incredibly smooth. For Windows users, this feature isn't as straightforward—typically, you need to use Alt+Tab to switch between all applications, without limiting it to just a single app. This guide will show you how to achieve a similar operation using AutoHotkey 1.0, allowing you to quickly switch between windows within the same program.

Download and Install AutoHotkey 1.0

  1. Visit the AutoHotkey Website: Open your browser and go to the AutoHotkey official website.
  2. Download AutoHotkey v1.0: The website provides download links for both v1.0 and v2.0. For this guide, we need v1.0, so download v1.0.
  3. Install AutoHotkey: Once the download is complete, run the installer and follow the prompts to complete the installation.

Create and Save Your Script

  1. Create a New AHK Script File: Anywhere on your computer, right-click and choose "New" > "AutoHotkey Script". Name the script "SwitchWindows.ahk".
    Alternatively, you can open a blank file using Windows Notepad.
  2. Copy and Paste the Script Content: Paste the following script code into the new .ahk file and save it:

    ; Define a hotkey, such as Alt + ` (similar to macOS Cmd + `)
    !`::
       ; Get the PID of the current active window
       WinGet, currentPID, PID, A
       ; Get the process name of the current active window
       WinGet, processName, ProcessName, A
       ; Initialize variables
       nextWindow := ""
       foundCurrent := false
       ; Iterate through all windows
       WinGet, id, list,,, Program Manager
       Loop, %id%
       {
           this_id := id%A_Index%
           ; Get the process name of the window
           WinGet, thisProcess, ProcessName, ahk_id %this_id%
           ; Check if the window belongs to the same process and is visible
           if (thisProcess = processName)
           {
               ; If the current window is found, the next matching window is the target
               if (foundCurrent)
               {
                   nextWindow := this_id
                   break
               }
               ; Check if this is the current active window
               if (this_id = WinExist("A"))
                   foundCurrent := true
               ; If the current window is not yet found, set the first matching window as the target
               if (nextWindow = "")
                   nextWindow := this_id
           }
       }
       ; Switch to the target window
       if (nextWindow != "")
           WinActivate, ahk_id %nextWindow%
    return

Place the AHK File in a Specific Location and Set It to Run on Startup

  1. Place the Script in a Specific Location: Place the newly created "SwitchWindows.ahk" script in the C:\Scripts\AHK1\ directory.
  2. Set It to Run on Startup:
    • Press Win + R, type shell:startup, and press Enter.
    • In the startup folder that opens, right-click and choose "Paste Shortcut" (Windows 11 may require expanding the menu first), and paste a shortcut to the "SwitchWindows.ahk" file.
    • This ensures that the script starts automatically every time you boot your computer, saving you from having to manually run it.

How to Temporarily Disable the AHK Script

If you need to temporarily disable the script, such as when you don't want the hotkeys to interfere, follow these steps:

  1. Find the AutoHotkey Icon in the System Tray: In the system tray at the bottom-right of the screen, you'll see a green "H" icon.
  2. Right-Click the Icon: Right-click the green "H" icon to open the menu, and choose "Suspend hotkeys" to pause the script. The icon will turn into an "S". Alternatively, choose "Exit" to completely close the script.

Conclusion

Using AutoHotkey 1.0, you can achieve the convenience of the macOS Cmd+ operation with just a few simple steps, allowing you to set it up and run it automatically.
I hope this guide helps you experience better multi-window switching in the Windows environment and boosts your productivity. Give this script a try and see how much convenience it can bring to your workflow!

Handling Line Breaks in Home Assistant’s YAML to Send LineMessenger Push Messages (Restful Request)

In this blog post, I won't guide you step-by-step on how to configure Home Assistant to send Gmail notifications to LINE, but focusing on how to correctly handle line breaks (\n). This seemingly simple requirement can become quite challenging due to the complexities between YAML, JSON, and various APIs.

This post will focus on ensuring that line breaks are correctly displayed in LINE messages.繼續閱讀...

Import data to PowertoysRunTOTP from Aegis Authenticator

This article will introduce how to export plain JSON data from Aegis Authenticator and convert it into the format required by PowertoysRunTOTP, helping you import two-factor authentication (2FA) accounts from Aegis into the PowerToys Run TOTP extension.

Warning: Do not keep plain JSON files on your computer for an extended period. It is recommended to store them in encrypted storage, such as pCloud Crypto, or use 7zip to compress and set a secure password to protect the files.

Step 1: Export Plain JSON from Aegis Authenticator

First, export your 2FA account data from Aegis Authenticator. Ensure the exported file is in plain JSON format and save it to a secure location, such as C:\path\to\aegis_export.json.

Step 2: Write a PowerShell Script

Write a PowerShell script to convert the exported Aegis JSON file into the format required by PowertoysRunTOTP. Below is the complete script, which you can copy and paste into Notepad and save as a .ps1 file, for example, convert_aegis_to_powertoysrun.ps1.

$inputFilePath = "P:\Crypto Folder\aegis.json"
$outputFilePath = "$env:LOCALAPPDATA\Microsoft\PowerToys\PowerToys Run\Settings\Plugins\Community.PowerToys.Run.Plugin.TOTP\OTPList.json_new"
try {
    # Read the Aegis JSON file and ensure it uses UTF-8 encoding
    $jsonContent = Get-Content -Raw -Path $inputFilePath -Encoding UTF8

    # Check if the JSON file is empty
    if ($jsonContent -eq $null -or $jsonContent.Trim() -eq "") {
        throw "The Aegis JSON file is empty or contains no content"
    }

    try {
        # Parse the JSON file
        $aegisData = $jsonContent | ConvertFrom-Json
    } catch {
        throw "JSON parsing error: $_"
    }

    # Prepare the JSON structure for PowerToysRunTOTP
    $powerToysRunTOTP = @{
        Version = 2
        Entries = @()
    }

    # Check the structure of the Aegis JSON file
    if ($aegisData.db.entries -ne $null) {
        # Iterate over Aegis entries and extract necessary data
        foreach ($entry in $aegisData.db.entries) {
            $newEntry = @{
                Name = "$($entry.issuer): $($entry.name)"
                Key = $entry.info.secret
                IsEncrypted = $false
            }
            $powerToysRunTOTP.Entries += $newEntry
        }
    } else {
        throw "Entries in the Aegis JSON file are empty or not found"
    }

    # Write the converted data to the PowerToysRunTOTP JSON file
    $powerToysRunTOTP | ConvertTo-Json -Depth 3 | Set-Content -Path $outputFilePath -Encoding UTF8

    Write-Host "Aegis JSON conversion successful and saved to $outputFilePath"
} catch {
    Write-Host "An error occurred during the conversion process: $_"
}

Step 3: Run the PowerShell Script

Method 1: Run via Right-Click on Windows 10 or Later

  1. Ensure PowerToys is closed. This prevents the PowertoysRun OTP extension from overwriting the user-edited file during the process.
  2. Open File Explorer and locate the PowerShell script file you saved, such as convert_aegis_to_powertoysrun.ps1.
  3. Right-click the file and select "Run with PowerShell."
  4. If you see a Windows security warning, select "More info" and then click "Run anyway."

Method 2: Run Using PowerShell Command

  1. Ensure PowerToys is closed. This prevents the PowertoysRun OTP extension from overwriting the user-edited file during the process.
  2. Press Win + X and select "Windows PowerShell (Admin)" or "Windows Terminal (Admin)."
  3. In the PowerShell window, type the following command, without pressing Enter yet (there is a space after -File):
    %%%
    PowerShell -ExecutionPolicy Bypass -File
    %%%
  4. Open File Explorer and locate the PowerShell script file you saved.
  5. Drag and drop the file into the PowerShell window. This will automatically fill in the complete path of the file.
  6. Ensure the command looks like this and then press Enter to execute:
    %%%
    PowerShell -ExecutionPolicy Bypass -File "C:\path\to\convert_aegis_to_powertoysrun.ps1"
    %%%

Step 4: Verify the Import Results

  1. Open PowerToys, which will automatically start the TOTP extension.
  2. Once the PowertoysRun TOTP extension starts, it will automatically encrypt the data in the OTPList.json file.
  3. Open PowerToys Run and check if your 2FA accounts were successfully imported. If everything is correct, you should see your imported accounts and be able to use them for authentication.

Summary

Through the above steps, we successfully converted the plain JSON file exported from Aegis Authenticator and imported it into PowertoysRunTOTP. This method helps you easily manage your 2FA accounts and migrate them between different devices.
If you found this article helpful, please leave a comment, give a thumbs up, or share it with others.

If you have any suggestions, feel free to leave a comment!

WordPress Docker Maintenance and Deployment Notes

Docker Compose

If you're worried that using latest will pull new versions that could break your setup, you can specify a suitable version number.

version: "4.5"

services:
  tsumugi-db:
    image: mariadb:latest
    volumes:
      - tsumugi-mariadb_data:/var/lib/mysql
    restart: always
    environment:
      MARIADB_ROOT_PASSWORD: your-mariadb-root-pwd
      MARIADB_DATABASE: your-wordpress-db
      MARIADB_USER: yourDbUserForWp
      MARIADB_PASSWORD: yourMariaDbPassword

  tsumugi-wordpress:
    depends_on:
      - tsumugi-db
    #links:
    #  - mariadb:mysql
    image: wordpress:latest
    volumes:
      - tsumugi-wordpress_data:/var/www/html
      - tsumugi-wordpress_php:/usr/local/etc/php

    restart: always
    environment:
      WORDPRESS_DB_HOST: tsumugi-db
      WORDPRESS_DB_USER: yourDbUserForWp
      WORDPRESS_DB_PASSWORD: yourMariaDbPassword
      WORDPRESS_DB_NAME: your-wordpress-db

  zunda-db:
    image: mariadb:latest
    volumes:
      - zundamon-mariadb_data:/var/lib/mysql
    restart: always
    environment:
      MARIADB_ROOT_PASSWORD: some-mariadb-root-pwd
      MARIADB_DATABASE: zundamon-wordpress
      MARIADB_USER: zundamochi114514
      MARIADB_PASSWORD: some-mariadb-password

  zundamon-wordpress:
    depends_on:
      - zunda-db
    image: wordpress:latest
    volumes:
      - zundamon-wordpress_data:/var/www/html
      - zundamon-wordpress_php:/usr/local/etc/php
    restart: always
    environment:
      WORDPRESS_DB_HOST: zunda-db
      WORDPRESS_DB_USER: zundamochi114514
      WORDPRESS_DB_PASSWORD: some-mariadb-password
      WORDPRESS_DB_NAME: zundamon-wordpress
      WORDPRESS_TABLE_PREFIX: wpzundamochi_

  https-portal:
    image: steveltn/https-portal:1
    ports:
      - "192.168.19.19:80:80"
      - "192.168.19.19:443:443"
    restart: always
    environment:
      DOMAINS: 'www.zundamon-kawaii.com -> http://tsumugi-wordpress:80, blog.zundamon.co.jp -> http://zundamon-wordpress:80, www.zundamon.co.jp -> http://zundamon-wordpress:80, zundamon.co.jp -> http://zundamon-wordpress:80'
      CLIENT_MAX_BODY_SIZE: 500M
      STAGE: 'production' # Don't use production until staging works
      # FORCE_RENEW: 'true'
    volumes: 
      - https-portal-data:/var/lib/https-portal

volumes:
  tsumugi-mariadb_data: {}
  tsumugi-wordpress_data: {}
  tsumugi-wordpress_php: {}
  zundamon-mariadb_data: {}
  zundamon-wordpress_data: {}
  zundamon-wordpress_php: {}
  https-portal-data: {}

Troubleshooting

  • Browser Developer Console shows 413 Request entity too large
    • The https-portal needs an environment variable adjustment:
CLIENT_MAX_BODY_SIZE: 500M

If you accidentally add a semicolon after 500M like CLIENT_MAX_BODY_SIZE: 500M;, the container will still run, but the website will not respond. Check the https-portal error.log, and you will see an error message similar to this (my volume configuration is located in the dd87****87b folder):

2024/07/19 13:52:01 [emerg] 59#59: unexpected ";" in /etc/nginx/nginx.conf:56
  • Unable to upload files larger than 2MB to WordPress
    • Since my Compose configuration directly maps PHP to a volume, you can create an uploads.ini file in /var/lib/docker/volumes/yourstack-zundamon-wordpress_php/_data/conf.d with the following content:
file_uploads = On
memory_limit = 500M
upload_max_filesize = 500M
post_max_size = 500M
max_execution_time = 600

Backup Script

#!/bin/bash

# Define variables
NFS_SERVER="192.168.x.x" # Destination Hostname
NFS_PATH="/volume1/Backup-NFS" # Destination directory
LOCAL_PATHS=(
    "/var/lib/docker/volumes/yourblog_mariadb_data/_data"
    "/var/lib/docker/volumes/yourblog_wordpress_data/_data"
#...add and adjust as needed, no comma at the end of the string
)
MOUNT_POINT="/mnt/backup_nfs"
DATE_NOW=$(date +'%Y%m%d%H%M%S')
BACKUP_FILE="$MOUNT_POINT/web/websiteBackup_$DATE_NOW.tar.gz"

# Create mount point
mkdir -p $MOUNT_POINT

# Check if NFS is already mounted
mountpoint -q $MOUNT_POINT
if [ $? -ne 0 ]; then
  echo "Mounting NFS shared directory..."
  mount -t nfs $NFS_SERVER:$NFS_PATH $MOUNT_POINT

  if [ $? -ne 0 ]; then
    echo "Failed to mount NFS shared directory"
    exit 1
  fi
fi

# Compress and backup data
tar -czf $BACKUP_FILE -C / ${LOCAL_PATHS[@]}

# Delete excess backups
find $MOUNT_POINT -name "websiteBackup_*.tar.gz" -type f -print | while read FILE; do
    FILE_DATE=$(basename $FILE | sed 's/websiteBackup_\(.*\)\.tar\.gz//')
    FILE_EPOCH=$(date -d "${FILE_DATE:0:8}" +%s)
    NOW_EPOCH=$(date +%s)
    AGE=$(( (NOW_EPOCH - FILE_EPOCH) / 86400 ))

    if [ $AGE -le 7 ]; then
        # Keep one backup per day for the last 7 days
        continue
    elif [ $AGE -le 30 ]; then
        # Keep one backup per week for the last month
        FILE_DAY=$(date -d "${FILE_DATE:0:8}" +%u)
        if [ $FILE_DAY -eq 1]; then
            continue
        fi
    elif [ $AGE -le 365]; then
        # Keep one backup per month for the last year
        FILE_DAY=$(date -d "${FILE_DATE:0:8}" +%d)
        if [ $FILE_DAY -eq 1]; then
            continue
        fi
    elif [ $AGE -gt 365]; then
        # Keep one backup per year
        FILE_MONTH_DAY=$(date -d "${FILE_DATE:0:8}" +%m%d)
        if [ $FILE_MONTH_DAY -eq "0101"]; then
            continue
        fi
    fi

    # Delete files that do not meet the retention rules
    rm -f $FILE
done

crontab -e with micro editor

How to Fix the Black Screen Issue When Switching to Desktop Mode on Steam Deck

When you encounter a black screen while attempting to switch to Desktop Mode on your Steam Deck, it can be frustrating. However, there is a simple solution to help resolve this issue. Here is a step-by-step guide to solve the problem:

Solution

  1. Switch Accounts:

    • First, log in to a new Steam account through the game interface.
    • Use this new account to switch to Desktop Mode.
    • If the switch is successful, delete all files (excluding folders) located at Home/.local/share/kscreen and Home/.local/share/kscreen/outputs.
    • For safety, you may choose to cut and back up these files to another location before deleting them from the original location.
    • After backing up, switch back to Game Mode, log in to the account that had the issue, and try switching to Desktop Mode again. The problem should now be resolved.
  2. For Users with Decky Loader Framework Installed:

    • Ensure you have the Decky Loader framework installed and have set a root password in advance.
    • Install the Decky Terminal plugin.
    • Execute sudo -i to log in as root, then run the following commands:
      cd /home/deck/.local/share/kscreen
      rm *
      cd /home/deck/.local/share/kscreen/outputs
      rm *
      exit
    • After executing these commands, close the Terminal and try switching to Desktop Mode again; the issue should be resolved.
    • It is recommended to create a script file named fix.sh containing the above commands and store it in /home/deck/. Remember to make the script executable by using the command sudo chmod +x /home/deck/fix.sh.

By following these steps, you should be able to overcome the black screen issue on your Steam Deck and enjoy a seamless gaming experience.