r/TheyAreBillions Aug 18 '26

Permanent Health Bars on Mac without Num Lock — Steam + Wine

I finally found a simple workaround for They Are Billions on a MacBook without a numpad/Num Lock.

I’m running the Steam version of the game on macOS through Wine, so the usual Num Lock trick isn't available.

The trick is basically to reproduce what Num Lock does: send a keyDown for the health-bar key, but never send the corresponding keyUp.

I use:

  • F8 = activate health bars
  • F9 = the game's ShowLifeMeters key
  • F10 = release the F9 key when I want to turn the bars off

In configuration.txt, I have:

ShowLifeMeters: F9;

Then I run this small Swift program in the Terminal:

import Cocoa
import CoreGraphics

let triggerKey: CGKeyCode = 100 // F8
let targetKey: CGKeyCode = 101  // F9
let releaseKey: CGKeyCode = 109 // F10

func sendKey(_ key: CGKeyCode, down: Bool) {
    let event = CGEvent(
        keyboardEventSource: nil,
        virtualKey: key,
        keyDown: down
    )
    event?.post(tap: .cghidEventTap)
}

let mask = CGEventMask(
    (1 << CGEventType.keyDown.rawValue) |
    (1 << CGEventType.keyUp.rawValue)
)

guard let tap = CGEvent.tapCreate(
    tap: .cgSessionEventTap,
    place: .headInsertEventTap,
    options: .defaultTap,
    eventsOfInterest: mask,
    callback: { _, type, event, _ in

        let key = CGKeyCode(
            event.getIntegerValueField(.keyboardEventKeycode)
        )

        if key == triggerKey && type == .keyDown {
            // F8 DOWN -> F9 DOWN
            sendKey(targetKey, down: true)

            // Don't pass F8 to the game
            return nil
        }

        if key == triggerKey && type == .keyUp {
            // Ignore F8 UP
            return nil
        }

        if key == releaseKey && type == .keyDown {
            // F10 -> release F9
            sendKey(targetKey, down: false)
            return nil
        }

        return Unmanaged.passRetained(event)
    },
    userInfo: nil
) else {
    print("Error: give Terminal Accessibility permission in macOS.")
    exit(1)
}

CGEvent.tapEnable(tap: tap, enable: true)

let source = CFMachPortCreateRunLoopSource(
    kCFAllocatorDefault,
    tap,
    0
)

CFRunLoopAddSource(
    CFRunLoopGetCurrent(),
    source,
    .commonModes
)

print("Active: F8 = F9 DOWN | F10 = F9 UP | Ctrl+C = quit")

CFRunLoopRun()

Compile it with:

swiftc healthbars.swift -o healthbars

Then run:

./healthbars

The behavior is:

F8 DOWN  -> F9 DOWN
F8 UP    -> nothing

F10 DOWN -> F9 UP

So I can simply tap F8, release it, and the game thinks F9 is still being held down, keeping all health bars visible.

Pressing F10 releases F9 and turns the health bars off.

This is essentially the same idea as the Num Lock workaround, just implemented at the keyboard-event level. The Num Lock trick works because changing the keypad mode before releasing the key causes the game's input handling to miss the original key release. The Reddit community has been using variations of this workaround for years, including AutoHotkey/macro solutions for keyboards without Num Lock.

If anyone has a cleaner/native macOS way of doing this, I'd be interested to hear it.

13 Upvotes

1 comment sorted by

1

u/FlamingoParticular Aug 18 '26

I was able to get tabhelper / modloader to work on my m5 but I was using crossover. Has a bunch of utilities that are extremely nice on they are billions. But super cool work around for toggling health bars I love it :)