Native utility for configuring the Epomaker x Aula F75 Max keyboard on macOS, Linux, and Android.
The macOS app communicates directly with the keyboard and its 2.4G receiver through macOS HID APIs. The Linux app uses hidapi over hidraw and a native GTK4 interface. The Android app uses the USB Host API and a Compose UI. The three versions share the same portable protocol code where possible.
The promo and documentation site lives in docs/ and is ready for GitHub Pages.
- Local entry point:
docs/index.html - Static assets:
docs/assets/anddocs/screenshots/ - GitHub Pages deployment workflow:
.github/workflows/pages.yml - Build workflow:
.github/workflows/build.ymlvalidates macOS DMG packaging, Linux DEB installer builds, and Android tests/debug APK builds on pull requests and pushes. Tagged builds also produce the Android release APK. - Default site language: English
- Site languages: English, Russian, Spanish, Uzbek, Kazakh, Portuguese, Simplified Chinese
After pushing to main or master, GitHub Actions publishes the docs/ directory through Pages. The workflow can also be started manually from the Actions tab.
- Detects wired USB HID endpoints for the keyboard.
- Detects the 2.4G USB receiver.
- Reads keyboard battery percentage through the 2.4G receiver.
- Sends a local low-battery notification on macOS and Linux when the level drops below 20%.
- Controls RGB mode, brightness, speed, direction, colorful animation, and fixed color.
- Configures response level, sleep timeout, Game Mode, and Command key restore behavior.
- Syncs the keyboard display clock to local system time.
- Uploads PNG, JPEG, GIF, BMP, TIFF, and WebP images to the 128 x 128 keyboard display.
- Supports animated GIF uploads with frame delays.
- Supports display fit modes: fit, fill, and stretch.
- Provides a factory reset flow for display slots and keyboard configuration blocks used by this implementation.
- Provides a diagnostic endpoint view for HID transport troubleshooting.
- Supports app language selection with bundled localizations.
- Ships native macOS, Linux, and Android builds with platform-specific integrations.
- Supports Launch at Login on macOS.
Android provides the same wired display, clock, reset, receiver battery, RGB, performance, and Game Mode controls through the system USB Host API. Desktop-only integrations such as Launch at Login, Linux desktop entries, and low-battery notifications are not available in the Android app.
- macOS 14 or newer.
- Apple Silicon Mac.
- Xcode Command Line Tools or a full Xcode installation.
- Aula F75 Max keyboard.
- USB-C wired connection for display upload, clock sync, and factory reset.
- 2.4G USB receiver for battery, RGB, performance, and Game Mode controls.
Some HID operations may require macOS Input Monitoring permission. If commands fail even though the keyboard is connected, grant permission in:
System Settings -> Privacy & Security -> Input Monitoring
Then restart the app.
- Ubuntu or Fedora on x86_64.
- Swift 6 toolchain.
- GTK4 development libraries.
- hidapi development libraries.
- Aula F75 Max keyboard and/or 2.4G receiver.
- udev access to the supported hidraw devices.
Ubuntu dependencies:
sudo apt install libgtk-4-dev libhidapi-dev pkg-configFedora dependencies:
sudo dnf install gtk4-devel hidapi-devel pkgconf-pkg-configSource builds need the udev rule before running device commands:
sudo install -m 0644 packaging/linux/60-aula-f75-max.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm triggerThen replug the keyboard and receiver.
- Android 9 (API 28) or newer.
- JDK 17 and the Android SDK (Android Studio is optional).
- USB OTG support on the Android device.
- Aula F75 Max keyboard and/or 2.4G receiver.
The Android app uses the system USB permission prompt for HID access. Plug the keyboard or receiver into the device with an OTG adapter, open the app, tap Grant USB access, and approve the prompt. The project uses its checked-in Gradle 9.3 wrapper and keeps downloaded Gradle state under android/.gradle/.
Show available Make targets:
make helpBuild and package the app:
make macos-appOpen the packaged app:
open "build/Aula F75 Max Driver.app"Build and open in one step:
make macos-runCreate a DMG installer image:
make macos-dmgCompatibility aliases are kept for the original macOS workflow:
make all
make build
make app
make dmg
make runBuild the native Linux GTK app:
make linux-buildRun the native Linux GTK app:
make linux-runBuild a Debian/Ubuntu installer package:
make linux-deb
sudo apt install ./build/AulaF75MaxDriver-v*_*.debThe DEB installs the application launcher, desktop entry, icon, Swift runtime libraries needed by the release binary, and the udev rule. Replug the keyboard and receiver after installation.
Package a legacy tar.gz artifact for development workflows:
make linux-packageBuild the Android debug APK and run unit tests:
make android-build
make android-testThe debug APK is written to:
android/app/build/outputs/apk/debug/app-debug.apk
Install it on a connected Android device with USB debugging enabled:
adb install -r android/app/build/outputs/apk/debug/app-debug.apkTagged GitHub Actions builds sign the release APK with a persistent release key. Configure these repository secrets before creating a tag:
ANDROID_RELEASE_KEYSTORE_BASE64: the base64-encoded JKS or PKCS12 keystore.ANDROID_RELEASE_KEYSTORE_PASSWORD: the keystore password.ANDROID_RELEASE_KEY_ALIAS: the signing key alias.ANDROID_RELEASE_KEY_PASSWORD: the signing key password.
Keep an offline backup of the keystore and its passwords. Every update must use the same signing key as the installed app. The workflow stops before publishing if a signing secret is absent or if apksigner cannot verify the resulting APK.
Other commands:
make macos-buildbuilds the macOS SwiftUI app binary in release mode forarm64.make macos-appbuilds and packagesbuild/Aula F75 Max Driver.app.make macos-dmgbuilds a styled drag-to-installbuild/Aula F75 Max Driver.dmgwith the app and an Applications shortcut.make macos-runbuilds and opens the macOS app bundle.make linux-buildbuilds the native Linux GTK app on Linux.make linux-debbuilds the Debian/Ubuntu installer inbuild/.make linux-packagepackages the Linux binary and udev rule intobuild/AulaF75MaxDriverLinux.tar.gzas a legacy developer artifact.make linux-runruns the native Linux GTK app on Linux.make android-buildbuilds the Android debug APK through the Android Gradle project.make android-testruns the Android JVM unit tests.make cleanremoves.build/andbuild/.
The build output is local generated state and should not be committed.
The app starts a HID monitor when the main window appears. It automatically rescans when supported devices are connected or removed.
The overview cards show:
- Wired USB state.
- 2.4G receiver state.
- Battery state.
The endpoint diagnostics panel lists visible HID endpoints, usage pages, report sizes, product names, and transports. Use this panel first when a device command does not work.
Use a wired USB-C connection for:
- Keyboard clock sync.
- Keyboard display image upload.
- Factory reset.
Display upload supports still images and animated GIFs. Images are rendered to the keyboard screen size of 128 x 128, converted to RGB565, chunked into 4096-byte HID output reports, and sent to the selected display slot.
Slots must be in the range 1...255.
Fit modes:
Fitpreserves aspect ratio and letterboxes when needed.Fillpreserves aspect ratio and crops when needed.Stretchfills the full display without preserving aspect ratio.
Use the 2.4G receiver for:
- Battery query.
- RGB lighting profile.
- Response level.
- Sleep timeout.
- Game Mode.
- Command key restore.
The app polls battery periodically while the receiver is present. Manual battery query is also available from the main window.
Launch at Login is managed through the macOS ServiceManagement framework. It can be toggled from the app settings panel.
- The Android build is a separate Gradle project under
android/. - USB Host permission is required before the app can talk to the keyboard or receiver.
- Use a wired USB-C connection through OTG for display upload, clock sync, and factory reset.
- Connect the 2.4G receiver through OTG for battery, RGB, response, sleep, and Game Mode controls.
- The Compose interface supports English, Russian, and the Android system-language option; unsupported system locales fall back to English.
- Android-specific features like desktop entry integration and Launch at Login are not available on Android.
.
|-- Package.swift
|-- Info.plist
|-- Makefile
|-- android/
| |-- app/
| | `-- src/
| | |-- main/
| | `-- test/
| `-- gradle/
|-- Sources/
| `-- AulaF75MaxDriver/
| |-- AulaF75MaxDriverApp.swift
| |-- ContentView.swift
| |-- AppViewModel.swift
| |-- AulaDevice.swift
| |-- WirelessAulaDevice.swift
| |-- DisplayEncoder.swift
| |-- HIDDeviceMonitor.swift
| |-- BatteryNotificationService.swift
| |-- LaunchAtLogin.swift
| |-- Localization.swift
| |-- AulaTypes.swift
| `-- Resources/
| |-- en.lproj/
| |-- ru.lproj/
| |-- es.lproj/
| |-- uz.lproj/
| |-- kk.lproj/
| |-- pt.lproj/
| `-- zh-Hans.lproj/
`-- build/
Linux-specific code is split into separate targets under Sources/AulaCore/, Sources/AulaLinuxHID/, Sources/AulaLinuxApp/, and Sources/CAulaLinuxGTK/.
Important files:
AulaF75MaxDriverApp.swiftdefines the SwiftUI app, main window, and AppKit window appearance configuration.ContentView.swiftcontains the main SwiftUI interface.AppViewModel.swiftowns app state, task orchestration, device refreshes, battery polling, and log messages.AulaDevice.swifthandles wired keyboard HID communication.WirelessAulaDevice.swifthandles 2.4G receiver communication.DisplayEncoder.swiftconverts image files into the keyboard display payload format.HIDDeviceMonitor.swiftwatches for supported HID attach and removal events.AulaTypes.swiftcontains the current macOS app protocol constants, shared errors, endpoint metadata, and upload progress types.AulaCorecontains portable packet builders and shared types used by the Linux implementation.Localization.swiftresolves bundled localized strings and language override behavior.android/app/src/main/java/com/vitalyart/aulaf75maxdriver/AulaApp.ktcontains the Android Compose interface.android/app/src/main/java/com/vitalyart/aulaf75maxdriver/AulaBackend.ktperforms Android USB Host device commands.android/app/src/main/java/com/vitalyart/aulaf75maxdriver/UsbHidSession.ktmanages claimed USB HID interfaces and report transfers.
The macOS app is a Swift Package executable target using SwiftUI for UI and AppKit/IOKit for macOS integration. The Linux app is a separate native GTK4 executable using hidapi/hidraw. Android is a Kotlin/Compose application that accesses the same supported device identifiers through Android's USB Host API.
High-level flow:
AulaF75MaxDriverAppcreates a sharedAppViewModel.ContentViewrenders state and invokes view model actions.AppViewModelstarts HID monitoring, runs device commands, updates logs, and manages background battery polling.AulaDeviceandWirelessAulaDeviceperform low-level HID report operations.DisplayEncoderprepares display payloads before upload.
On Android, AulaViewModel coordinates the Compose UI, AndroidAulaBackend performs device commands, and UsbHidSession claims USB interfaces after the user grants USB Host permission.
Device commands run off the main actor where appropriate, then publish UI state back on the main actor.
Known device identifiers:
- Wired keyboard: vendor
0x0c45, product0x800a. - 2.4G receiver: vendor
0x05ac, product0x024f.
Known usage pages:
- Wired command:
0xff13. - Wired raw display:
0xff68. - 2.4G command:
0xff59. - 2.4G raw:
0xff60.
The app also uses report size heuristics as fallbacks where needed.
Bundled localizations currently include:
- English
- Russian
- Spanish
- Uzbek
- Kazakh
- Portuguese
- Simplified Chinese
The macOS and Linux apps bundle all seven localizations. Their selected language is stored in UserDefaults under app.language.code, and the system option uses the default bundle resolution. Android currently bundles English and Russian and stores its language choice in Android shared preferences.
There is currently no automated test target in Package.swift. The shared AulaCore target is compiled as part of the package build.
Recommended validation before a release:
make clean
make macos-appLinux validation should be run on Ubuntu or Fedora after installing the documented GTK4, hidapi, and udev dependencies:
make linux-build
make linux-runValidate the Android Kotlin models and debug APK with JDK 17 and an installed Android SDK:
make android-test
make android-buildManual validation:
- Launch the packaged app.
- Connect the keyboard over USB-C and verify wired endpoints appear.
- Connect the 2.4G receiver and verify receiver endpoints appear.
- Query battery.
- Apply a harmless RGB profile.
- Sync keyboard clock.
- Upload a small test image to a non-critical display slot.
- Switch app language and verify the UI updates correctly.
- Toggle Launch at Login if that behavior changed.
- On Android, connect through OTG, grant the USB permission prompt, and verify wired or receiver actions work from the Compose UI.
If tests are added later, place them under Tests/ and run them with:
swift test- Check the diagnostic endpoint panel.
- Try reconnecting the keyboard or receiver.
- Try a direct USB port instead of a hub.
- On macOS, grant Input Monitoring permission and restart the app.
- On Android, confirm the phone or tablet supports USB OTG, then tap Grant USB access and approve the system prompt.
- Run
make clean && make macos-appif testing a fresh local macOS build.
Battery query requires the 2.4G receiver. Wired USB endpoints alone are not enough for the current battery implementation.
- Use wired USB-C mode.
- Confirm that the wired display endpoint is visible.
- Try a smaller still image first.
- Confirm that the selected slot is between
1and255. - Grant Input Monitoring permission if acknowledgements are not received.
- Use the 2.4G receiver.
- Confirm that the
2.4G rawendpoint is visible. - Reconnect the receiver and rescan.
Launch at Login depends on macOS ServiceManagement behavior and app bundle identity. Test it from the packaged .app, not from a raw SwiftPM executable.
- The app is currently packaged from SwiftPM with a Makefile, not from a full Xcode app project.
- There is no WidgetKit extension. The standard macOS Batteries widget cannot be extended from this package layout.
- Automated tests are not configured yet.
- Hardware-dependent behavior requires a real Aula F75 Max keyboard and receiver.
- The protocol implementation is based on observed/public packet flows and may need updates for firmware variants.
- Do not commit generated build output.
- Do not commit pairing data, device secrets, or private diagnostic captures.
- This app communicates with HID devices from user space and does not install kernel extensions.
See LICENSE.

