Files
Razer-led-mac/main.go
2026-02-09 04:07:32 +08:00

157 lines
5.0 KiB
Go

package main
import (
"fmt"
"log"
"razer/utils"
"time"
"github.com/karalabe/hid"
"github.com/progrium/darwinkit/macos/appkit"
"github.com/progrium/darwinkit/objc"
)
func main() {
if !hid.Supported() {
log.Fatal("HID 不支持")
}
objc.WithAutoreleasePool(func() {
app := appkit.Application_SharedApplication()
app.SetActivationPolicy(appkit.ApplicationActivationPolicyAccessory)
utils.SetupStatusBar(app)
// 【新增】在主线程提前初始化色盘单例
// 这样后面协程调用它时,它已经存在了,不会触发线程检查崩溃
_ = appkit.ColorPanel_SharedColorPanel()
// 2. 启动颜色监听协程
go func() {
var lastColor string
for {
time.Sleep(100 * time.Millisecond)
// 关键:切换回主线程来获取色盘和颜色
// 在 DarwinKit 中,通常我们可以直接在菜单点击时先初始化它,
// 或者使用 dispatch 保证安全。
var r, g, b int
var isVisible bool
var colorFound bool
// 使用 WithAutoreleasePool 并在主线程执行
objc.WithAutoreleasePool(func() {
// 注意:有些 DarwinKit 版本需要 dispatch 包
// 如果没有 dispatch 包,最简单的办法是在 main 启动前
// 先在主线程调用一次 ColorPanel_SharedColorPanel()
cp := appkit.ColorPanel_SharedColorPanel()
if cp.IsVisible() {
isVisible = true
c := cp.Color().ColorUsingColorSpace(appkit.ColorSpace_DeviceRGBColorSpace())
if !c.IsNil() {
r = int(c.RedComponent() * 255)
g = int(c.GreenComponent() * 255)
b = int(c.BlueComponent() * 255)
colorFound = true
}
}
})
if isVisible && colorFound {
curr := fmt.Sprintf("%d-%d-%d", r, g, b)
if curr != lastColor {
lastColor = curr
//fmt.Printf("颜色更新: R:%d G:%d B:%d\n", r, g, b)
//fmt.Printf("内容: R:%#v ", utils.Temp)
// 这里写 HID 设备,这里已经是 Go 协程了,不会阻塞 UI
// 1. 转换并更新你的缓存
// 这里的 BreathingState 结构体可能需要增加 R, G, B 字段
// 设置颜色
utils.Temp.TempState.SetColor([]byte{byte(r), byte(g), byte(b)})
for _, dev := range utils.Devs {
key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
if utils.Temp.TempKey != key {
continue
}
switch utils.Temp.TempState.GetEffect() {
// 处理静态
case utils.KBD_EFFECT_STATIC:
dev.SetStaticColor(utils.Temp.TempState.GetColor())
// 处理呼吸
case utils.KBD_EFFECT_BREATHING:
dev.SetBreathingColor(byte(utils.Temp.TempState.GetModel()), utils.Temp.TempState.GetColor(), []byte{}, byte(utils.Temp.TempState.GetSpeed()))
}
}
utils.DeviceStateCache[utils.Temp.TempKey] = utils.Temp.TempState
//fmt.Printf("内容: R:%#v ", utils.DeviceStateCache[utils.Temp.TempKey])
// 2. 立即发送到硬件
// 这里的具体的转换逻辑需要匹配你的 HID 库
//payload := []byte{byte(r), byte(g), byte(b)}
//fmt.Printf("发送字节流到硬件: %v\n", payload)
}
}
}
}()
app.ActivateIgnoringOtherApps(true)
app.Run()
})
}
//// --- UI 逻辑:支持动态刷新 ---
//func updateMenu(menu appkit.Menu, app appkit.Application) {
// // 1. 清空旧菜单
// menu.RemoveAllItems()
//
// // 2. 重新扫描设备
// devices := utils.ScanDevices()
//
// // 3. 添加刷新按钮 (放在最上面)
// refreshItem := appkit.NewMenuItemWithAction("🔄 刷新设备列表", "r", func(sender objc.Object) {
// updateMenu(menu, app) // 递归调用刷新自身
// })
// menu.AddItem(refreshItem)
// menu.AddItem(appkit.MenuItem_SeparatorItem())
//
// // 4. 构建设备列表
// if len(devices) == 0 {
// none := appkit.NewMenuItemWithAction("未发现雷蛇设备", "", func(sender objc.Object) {})
// none.SetEnabled(false)
// menu.AddItem(none)
// } else {
// for _, dev := range devices {
// devTitle := appkit.NewMenuItemWithAction("设备: "+dev.Name, "", func(sender objc.Object) {})
// devTitle.SetEnabled(false)
// menu.AddItem(devTitle)
//
// menu.AddItem(appkit.NewMenuItemWithAction(" 🔴 设为红色", "", func(sender objc.Object) {
// //dev.ApplyStaticColor(0xFF, 0x00, 0x00)
// }))
//
// menu.AddItem(appkit.NewMenuItemWithAction(" 🟢 设为绿色", "", func(sender objc.Object) {
// //dev.ApplyStaticColor(0x00, 0xFF, 0x00)
// }))
//
// menu.AddItem(appkit.MenuItem_SeparatorItem())
// }
// }
//
// // 5. 退出按钮
// menu.AddItem(appkit.NewMenuItemWithAction("退出", "q", func(sender objc.Object) {
// app.Terminate(nil)
// }))
//}
//func setupStatusBar(app appkit.Application) {
// // 创建状态栏项
// item := appkit.StatusBar_SystemStatusBar().StatusItemWithLength(appkit.VariableStatusItemLength)
// objc.Retain(&item)
//
// img := appkit.Image_ImageWithSystemSymbolNameAccessibilityDescription("keyboard", "Razer Tool")
// item.Button().SetImage(img)
//
// // 创建初始菜单
// menu := appkit.NewMenuWithTitle("Razer")
// updateMenu(menu, app) // 初始填充菜单项
// item.SetMenu(menu)
//}