Skip to content
Open
68 changes: 68 additions & 0 deletions .github/workflows/manual.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Manual

on:
workflow_dispatch:
inputs:
platform:
description: 'Choose the platform'
required: true
default: 'windows'
options:
- windows
- macos

jobs:
build:
if: github.event.inputs.platform == 'windows'
runs-on: windows-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pyinstaller

- name: Build with PyInstaller
run: |
pyinstaller --onefile --noconsole --name Baafucha --add-data "assets/icon.png:assets" --icon=assets/icon.png main.py

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Baafucha
path: dist/Baafucha.exe

build-macos:
if: github.event.inputs.platform == 'macos'
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12.5'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pyinstaller

- name: Build with PyInstaller
run: |
pyinstaller --onefile --noconsole --name Baafucha --add-data "assets/icon.png:assets" --icon=assets/icon.png main.py --osx-bundle-identifier com.baafucha.app
zip -r dist/Baafucha.app.zip dist/Baafucha.app

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Baafucha
path: dist/Baafucha.app.zip
44 changes: 43 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,34 @@ jobs:
name: Baafucha
path: dist/Baafucha.exe

build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pyinstaller

- name: Build with PyInstaller
run: |
pyinstaller --onefile --noconsole --name Baafucha --add-data "assets/icon.png:assets" --icon=assets/icon.png main.py

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Baafucha
path: dist/Baafucha

release:
needs: build
needs: [build, build-macos]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -71,3 +97,19 @@ jobs:
asset_path: ./Baafucha.exe
asset_name: Baafucha.exe
asset_content_type: application/octet-stream

- name: Download MacOS artifact
uses: actions/download-artifact@v4
with:
name: Baafucha
path: dist/Baafucha

- name: Upload MacOS Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./Baafucha
asset_name: Baafucha
asset_content_type: application/octet-stream
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ dist/
*.spec
*.pyc
baafucha_config.json

venv/

.DS_Store
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Ba'afucha is a tiny program that provides an easy way to convert text between En

## Requirements

- Windows operating system
- Windows or MacOS operating system

## Installation

Expand All @@ -50,7 +50,7 @@ Download the latest release from the [Releases](https://github.com/matipojo/baaf

## Usage

1. If you downloaded the release version, simply run the `Baafucha.exe` file.
1. If you downloaded the release version, simply run the `Baafucha.exe` file on Windows or `Baafucha` file on MacOS.

2. If you're running from source, run the script:

Expand Down Expand Up @@ -86,6 +86,22 @@ To create a standalone executable for Windows:

3. Find the `Baafucha.exe` in the `dist` folder.

To create a standalone executable for MacOS:

1. Ensure you have PyInstaller installed:

```
pip install pyinstaller
```

2. Run PyInstaller:

```
pyinstaller --onefile --noconsole --name Baafucha baafucha.py
```

3. Find the `Baafucha` in the `dist` folder.

## Continuous Integration

This project uses GitHub Actions for continuous integration. Every merge to the main branch triggers a new build and release. You can find the latest release in the [Releases](https://github.com/matipojo/baafucha/releases) section of the repository.
Expand Down
100 changes: 47 additions & 53 deletions core/taskbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,58 @@
import ctypes
import multiprocessing
import time
import winreg
import threading
import platform
from core.tray import load_config

# Loading the library user32.dll
user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32

# Gets the handle of the taskbar
taskbar_handle = user32.FindWindowW("Shell_TrayWnd", None)

# Setting constants
WM_SETTINGCHANGE = 0x001A

import winreg

REGISTRY_PATH = r"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
VALUE_NAME = "ColorPrevalence"
if platform.system() == "Windows":
import winreg
user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32
taskbar_handle = user32.FindWindowW("Shell_TrayWnd", None)
WM_SETTINGCHANGE = 0x001A
REGISTRY_PATH = r"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
VALUE_NAME = "ColorPrevalence"
elif platform.system() == "Darwin":
from AppKit import NSApp, NSApplicationActivationPolicyRegular
from Foundation import NSUserDefaults

def get_set_color_prevalence(set_value=None):
"""
Gets or sets the ColorPrevalence value in the registry.
If set_value is None, it returns the current value.
If set_value is provided, it sets the new value and returns it.
"""

try:
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, REGISTRY_PATH, 0, winreg.KEY_READ | winreg.KEY_WRITE) as key:
if set_value is None:
value, _ = winreg.QueryValueEx(key, VALUE_NAME)
return value
else:
winreg.SetValueEx(key, VALUE_NAME, 0, winreg.REG_DWORD, set_value)
return set_value
except Exception as e:
print(f"An error occurred with ColorPrevalence: {e}")
return None
if platform.system() == "Windows":
try:
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, REGISTRY_PATH, 0, winreg.KEY_READ | winreg.KEY_WRITE) as key:
if set_value is None:
value, _ = winreg.QueryValueEx(key, VALUE_NAME)
return value
else:
winreg.SetValueEx(key, VALUE_NAME, 0, winreg.REG_DWORD, set_value)
return set_value
except Exception as e:
print(f"An error occurred with ColorPrevalence: {e}")
return None
elif platform.system() == "Darwin":
defaults = NSUserDefaults.standardUserDefaults()
if set_value is None:
return defaults.integerForKey("AppleInterfaceStyleSwitchesAutomatically")
else:
defaults.setInteger_forKey_(set_value, "AppleInterfaceStyleSwitchesAutomatically")
return set_value

def refresh_taskbar():
"""
Refreshes the taskbar by sending a settings change notification to the taskbar.
"""
user32.SendMessageW(taskbar_handle, WM_SETTINGCHANGE, 0, "ImmersiveColorSet")
if platform.system() == "Windows":
user32.SendMessageW(taskbar_handle, WM_SETTINGCHANGE, 0, "ImmersiveColorSet")
elif platform.system() == "Darwin":
app = NSApp()
app.setActivationPolicy_(NSApplicationActivationPolicyRegular)
app.activateIgnoringOtherApps_(True)

def set_color_prevalence(value):
"""
Expand All @@ -62,19 +71,15 @@ def set_color_prevalence(value):
refresh_taskbar()

def get_current_input_language():
# Get the foreground window
hwnd = user32.GetForegroundWindow()

# Get the thread of the foreground window
thread_id = user32.GetWindowThreadProcessId(hwnd, 0)

# Get the keyboard layout of the thread
layout_id = user32.GetKeyboardLayout(thread_id)

# Extract the language ID from the keyboard layout
language_id = layout_id & 0xFFFF

return language_id
if platform.system() == "Windows":
hwnd = user32.GetForegroundWindow()
thread_id = user32.GetWindowThreadProcessId(hwnd, 0)
layout_id = user32.GetKeyboardLayout(thread_id)
language_id = layout_id & 0xFFFF
return language_id
elif platform.system() == "Darwin":
languages = NSUserDefaults.standardUserDefaults().stringForKey_("AppleLanguages")
return languages[0] if languages else None

language_monitor_thread = None
language_monitor_stop_event = None
Expand Down Expand Up @@ -108,32 +113,21 @@ def on_config_change(new_config):
if not language_monitor_thread:
start_language_monitor()

# The main process of the program
def monitor_language(stop_event):
# Stores the last language ID
last_layout_id = get_current_input_language()

# Set the initial color value
new_value = 0 if last_layout_id == kernel32.GetUserDefaultUILanguage() else 1
set_color_prevalence( new_value )
set_color_prevalence(new_value)

# Main loop to check language changes
while not stop_event.is_set():
layout_id = get_current_input_language()

# If a language change is detected, changes the color value and refreshes the taskbar
if layout_id != last_layout_id:
last_layout_id = layout_id

if layout_id == kernel32.GetUserDefaultUILanguage():
set_color_prevalence(0)
else:
set_color_prevalence(1)
print("Language change detected to language ID:", layout_id)

# Waits 0.2 seconds before next test
time.sleep(0.2)

# Running the main program
if __name__ == "__main__":
main()
Loading