321 lines
11 KiB
Go
321 lines
11 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/progrium/darwinkit/macos/appkit"
|
|
"github.com/progrium/darwinkit/objc"
|
|
)
|
|
|
|
var Devs map[string]*RazerDevice = make(map[string]*RazerDevice)
|
|
|
|
var Temp = TempData{}
|
|
|
|
type TempData struct {
|
|
TempKey string
|
|
TempState State
|
|
}
|
|
|
|
var DeviceStateCache = make(map[string]State)
|
|
|
|
type State interface {
|
|
GetEffect() int
|
|
GetColorKey() string
|
|
GetMultiColorKey() string
|
|
GetModel() int
|
|
SetColor([]byte)
|
|
GetColor() []byte
|
|
GetColor1() []byte
|
|
GetColor2() []byte
|
|
GetSpeed() int
|
|
}
|
|
|
|
// StaticState 常亮模式
|
|
type StaticState struct {
|
|
Effect int
|
|
ColorKey string
|
|
Color []byte
|
|
}
|
|
|
|
func (s *StaticState) GetEffect() int {
|
|
return s.Effect
|
|
}
|
|
func (s *StaticState) GetModel() int {
|
|
return 0
|
|
}
|
|
func (s *StaticState) GetColorKey() string {
|
|
return s.ColorKey
|
|
}
|
|
func (s *StaticState) GetMultiColorKey() string {
|
|
return ""
|
|
}
|
|
func (s *StaticState) SetColor(color []byte) {
|
|
s.Color = color
|
|
}
|
|
func (s *StaticState) GetColor() []byte {
|
|
return s.Color
|
|
}
|
|
func (s *StaticState) GetColor1() []byte {
|
|
return []byte{}
|
|
|
|
}
|
|
func (s *StaticState) GetColor2() []byte {
|
|
return []byte{}
|
|
|
|
}
|
|
func (s *StaticState) GetSpeed() int {
|
|
return 0
|
|
}
|
|
|
|
// BreathingState 呼吸模式
|
|
type BreathingState struct {
|
|
Effect int
|
|
Model int // 单色呼吸 双色呼吸 随机颜色
|
|
Speed int // 快 中 慢
|
|
Color []byte
|
|
ColorKey string
|
|
Color1 []byte // 多色
|
|
Color2 []byte // 多色
|
|
MultiColorKey string // 多色
|
|
}
|
|
|
|
func (b *BreathingState) GetEffect() int {
|
|
return b.Effect
|
|
}
|
|
func (b *BreathingState) GetColorKey() string {
|
|
return b.ColorKey
|
|
}
|
|
func (b *BreathingState) GetModel() int {
|
|
return b.Model
|
|
}
|
|
func (b *BreathingState) GetMultiColorKey() string {
|
|
return b.MultiColorKey
|
|
}
|
|
func (b *BreathingState) SetColor(color []byte) {
|
|
b.Color = color
|
|
}
|
|
func (b *BreathingState) GetColor() []byte {
|
|
return b.Color
|
|
}
|
|
func (b *BreathingState) GetSpeed() int {
|
|
return b.Speed
|
|
}
|
|
func (b *BreathingState) GetColor1() []byte {
|
|
return b.Color1
|
|
}
|
|
func (b *BreathingState) GetColor2() []byte {
|
|
return b.Color2
|
|
}
|
|
func UpdateMenu(menu appkit.Menu, app appkit.Application, statusBarItem appkit.StatusItem) {
|
|
menu.RemoveAllItems()
|
|
|
|
// 1. 刷新按钮
|
|
refreshItem := appkit.NewMenuItemWithAction("🔄 刷新设备列表", "r", func(sender objc.Object) {
|
|
UpdateMenu(menu, app, statusBarItem)
|
|
})
|
|
menu.AddItem(refreshItem)
|
|
menu.AddItem(appkit.MenuItem_SeparatorItem())
|
|
|
|
devices := ScanDevices()
|
|
Devs = devices
|
|
// 更新 ToolTip 显示当前连接数
|
|
statusBarItem.Button().SetToolTip(fmt.Sprintf("雷蛇控制器 - 已连接设备: %d", len(devices)))
|
|
|
|
if len(devices) == 0 {
|
|
none := appkit.NewMenuItemWithAction("未发现雷蛇设备", "", func(sender objc.Object) {})
|
|
none.SetEnabled(false)
|
|
menu.AddItem(none)
|
|
} else {
|
|
for _, dev := range devices {
|
|
|
|
key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
|
stateVal := DeviceStateCache[key]
|
|
// 设备标题 (不可点击)
|
|
devTitle := appkit.NewMenuItemWithAction("⌨️ "+dev.Name, "", func(sender objc.Object) {})
|
|
devTitle.SetEnabled(false)
|
|
menu.AddItem(devTitle)
|
|
|
|
// 切换灯效模式 (二级菜单)
|
|
//modeMenuItem := appkit.NewMenuItemWithAction("⚙️ 切换灯效模式", "", func(sender objc.Object) {})
|
|
//modeSubMenu := appkit.NewMenuWithTitle("Select Mode")
|
|
|
|
// --- A. 常亮模式 ---
|
|
staticItem := appkit.NewMenuItemWithAction("☀️ 常亮模式", "", func(sender objc.Object) {})
|
|
if dev.CurrentEffect == KBD_EFFECT_STATIC {
|
|
staticItem.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
|
|
colorMenu := appkit.NewMenuWithTitle("Colors")
|
|
for _, c := range PRESET_COLORS {
|
|
colorItem := appkit.NewMenuItemWithAction(c.Name, "", func(sender objc.Object) {
|
|
if c.Name == "自定义" {
|
|
DeviceStateCache[key] = &StaticState{Effect: KBD_EFFECT_STATIC, ColorKey: c.Name}
|
|
Temp = TempData{TempKey: key, TempState: DeviceStateCache[key]} // [key] = StaticState{Effect: KBD_EFFECT_STATIC, ColorKey: c.Name}
|
|
openColorPicker()
|
|
} else {
|
|
//dev.ApplyEffect(KBD_EFFECT_STATIC, c.R, c.G, c.B)
|
|
dev.SetStaticColor([]byte{c.R, c.G, c.B})
|
|
// 更新状态与缓存
|
|
DeviceStateCache[key] = &StaticState{Effect: KBD_EFFECT_STATIC, ColorKey: c.Name, Color: []byte{c.R, c.G, c.B}}
|
|
}
|
|
|
|
UpdateMenu(menu, app, statusBarItem)
|
|
})
|
|
stateVal := DeviceStateCache[key]
|
|
if stateVal != nil && dev.CurrentEffect == KBD_EFFECT_STATIC && stateVal.GetColorKey() == c.Name {
|
|
colorItem.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
colorMenu.AddItem(colorItem)
|
|
}
|
|
staticItem.SetSubmenu(colorMenu)
|
|
menu.AddItem(staticItem)
|
|
|
|
// --- B. 呼吸模式 ---
|
|
breathItem := appkit.NewMenuItemWithAction("🌬️ 呼吸模式", "", func(sender objc.Object) {})
|
|
if dev.CurrentEffect == KBD_EFFECT_BREATHING {
|
|
breathItem.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
breathRootMenu := appkit.NewMenuWithTitle("BreathingRoot")
|
|
|
|
singleItem := appkit.NewMenuItemWithAction("单色模式", "", func(sender objc.Object) {})
|
|
singleSub := appkit.NewMenuWithTitle("Single")
|
|
for _, color := range PRESET_COLORS {
|
|
item := appkit.NewMenuItemWithAction(color.Name, "", func(sender objc.Object) {
|
|
if color.Name == "自定义" {
|
|
DeviceStateCache[key] = &StaticState{Effect: KBD_EFFECT_BREATHING, ColorKey: color.Name}
|
|
Temp = TempData{TempKey: key, TempState: DeviceStateCache[key]} // [key] = StaticState{Effect: KBD_EFFECT_STATIC, ColorKey: c.Name}
|
|
openColorPicker()
|
|
} else {
|
|
if stateVal != nil {
|
|
dev.SetBreathingColor(0x01, []byte{color.R, color.G, color.B}, []byte{}, byte(stateVal.GetSpeed()))
|
|
} else {
|
|
dev.SetBreathingColor(0x01, []byte{color.R, color.G, color.B}, []byte{}, byte(1))
|
|
}
|
|
}
|
|
|
|
//dev.SetBreathing(0x01, color.R, color.G, color.B, 0, 0, 0, curState.Speed)
|
|
// 0x01: 单色 (只看第一组 RGB)
|
|
// 0x02: 双色 (看两组 RGB)
|
|
// 0x03: 随机
|
|
DeviceStateCache[key] = &BreathingState{Effect: KBD_EFFECT_BREATHING, Model: 0x01, ColorKey: color.Name, Color: []byte{color.R, color.G, color.B}}
|
|
UpdateMenu(menu, app, statusBarItem)
|
|
})
|
|
stateVal := DeviceStateCache[key]
|
|
if dev.CurrentEffect == KBD_EFFECT_BREATHING && stateVal != nil && stateVal.GetModel() == 0x01 && stateVal.GetColorKey() == color.Name {
|
|
item.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
singleSub.AddItem(item)
|
|
}
|
|
stateVal = DeviceStateCache[key]
|
|
if dev.CurrentEffect == KBD_EFFECT_BREATHING && stateVal != nil && stateVal.GetModel() == 0x01 {
|
|
singleItem.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
singleItem.SetSubmenu(singleSub)
|
|
breathRootMenu.AddItem(singleItem)
|
|
|
|
// B2. 双色呼吸 (红 <-> 自选)
|
|
dualItem := appkit.NewMenuItemWithAction("双色模式", "", func(sender objc.Object) {})
|
|
dualSub := appkit.NewMenuWithTitle("Dual")
|
|
for _, multiColor := range PRESET_MULTI_COLORS {
|
|
item := appkit.NewMenuItemWithAction(multiColor.Name, "", func(sender objc.Object) {
|
|
if stateVal != nil {
|
|
dev.SetBreathingColor(0x02, multiColor.Color1, multiColor.Color2, byte(stateVal.GetSpeed()))
|
|
} else {
|
|
dev.SetBreathingColor(0x02, multiColor.Color1, multiColor.Color2, byte(1))
|
|
}
|
|
DeviceStateCache[key] = &BreathingState{Effect: KBD_EFFECT_BREATHING, Model: 0x02, MultiColorKey: multiColor.Name, Color1: multiColor.Color1, Color2: multiColor.Color2}
|
|
UpdateMenu(menu, app, statusBarItem)
|
|
})
|
|
if dev.CurrentEffect == KBD_EFFECT_BREATHING && stateVal != nil && stateVal.GetModel() == 0x02 && stateVal.GetMultiColorKey() == multiColor.Name {
|
|
item.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
dualSub.AddItem(item)
|
|
}
|
|
stateVal = DeviceStateCache[key]
|
|
if dev.CurrentEffect == KBD_EFFECT_BREATHING && stateVal != nil && stateVal.GetModel() == 0x02 {
|
|
dualItem.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
dualItem.SetSubmenu(dualSub)
|
|
breathRootMenu.AddItem(dualItem)
|
|
|
|
// B3. 随机
|
|
randItem := appkit.NewMenuItemWithAction("随机颜色", "", func(sender objc.Object) {
|
|
DeviceStateCache[key] = &BreathingState{Effect: KBD_EFFECT_BREATHING, Model: 0x03}
|
|
UpdateMenu(menu, app, statusBarItem)
|
|
})
|
|
stateVal = DeviceStateCache[key]
|
|
if dev.CurrentEffect == KBD_EFFECT_BREATHING && stateVal != nil && stateVal.GetModel() == 0x03 {
|
|
randItem.SetState(appkit.ControlStateValueOn)
|
|
}
|
|
breathRootMenu.AddItem(randItem)
|
|
breathRootMenu.AddItem(appkit.MenuItem_SeparatorItem())
|
|
|
|
breathItem.SetSubmenu(breathRootMenu)
|
|
menu.AddItem(breathItem)
|
|
|
|
//// --- C. 波浪模式 ---
|
|
//waveItem := appkit.NewMenuItemWithAction("🌊 波浪模式", "", func(sender objc.Object) {
|
|
// //dev.ApplyEffect(KBD_EFFECT_WAVE, 0x01, 0x00, 0x00)
|
|
// key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
|
// deviceStateCache[key] = State{Effect: KBD_EFFECT_WAVE, Color: ""}
|
|
// UpdateMenu(menu, app, statusBarItem)
|
|
//})
|
|
//if dev.CurrentEffect == KBD_EFFECT_WAVE {
|
|
// waveItem.SetState(appkit.ControlStateValueOn)
|
|
//}
|
|
//menu.AddItem(waveItem)
|
|
|
|
// --- D. 响应模式 ---
|
|
//reactiveItem := appkit.NewMenuItemWithAction("🌊 响应模式", "", func(sender objc.Object) {
|
|
// //dev.ApplyEffect(KBD_EFFECT_WAVE, 0x01, 0x00, 0x00)
|
|
// key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
|
// deviceStateCache[key] = State{Effect: KBD_EFFECT_REACTIVE, Color: ""}
|
|
// UpdateMenu(menu, app, statusBarItem)
|
|
//})
|
|
//if dev.CurrentEffect == KBD_EFFECT_REACTIVE {
|
|
// reactiveItem.SetState(appkit.ControlStateValueOn)
|
|
//}
|
|
//menu.AddItem(reactiveItem)
|
|
|
|
// --- E. 关灯模式 --- 关灯
|
|
//offLightsItem := appkit.NewMenuItemWithAction("关灯模式", "", func(sender objc.Object) {
|
|
// dev.SetOffLightsColor([]byte{0x00, 0x00, 0x00})
|
|
// //key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
|
// deviceStateCache[key] = State{Effect: KBD_EFFECT_OFFLIGHTS, Color: ""}
|
|
// UpdateMenu(menu, app, statusBarItem)
|
|
//})
|
|
//if dev.CurrentEffect == KBD_EFFECT_OFFLIGHTS {
|
|
// offLightsItem.SetState(appkit.ControlStateValueOn)
|
|
//}
|
|
//menu.AddItem(offLightsItem)
|
|
|
|
//modeMenuItem.SetSubmenu(modeSubMenu)
|
|
//menu.AddItem(modeMenuItem)
|
|
|
|
menu.AddItem(appkit.MenuItem_SeparatorItem())
|
|
}
|
|
}
|
|
|
|
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("antenna.radiowaves.left.and.right", "Razer Tool")
|
|
item.Button().SetImage(img)
|
|
|
|
// 设置描述
|
|
item.Button().SetToolTip("雷蛇设备控制器 (Razer Controller)")
|
|
|
|
// 创建初始菜单
|
|
menu := appkit.NewMenuWithTitle("Razer")
|
|
UpdateMenu(menu, app, item)
|
|
item.SetMenu(menu)
|
|
}
|