处理动画
This commit is contained in:
72
main.go
72
main.go
@@ -1,8 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"razer/utils"
|
"razer/utils"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/karalabe/hid"
|
"github.com/karalabe/hid"
|
||||||
"github.com/progrium/darwinkit/macos/appkit"
|
"github.com/progrium/darwinkit/macos/appkit"
|
||||||
@@ -19,6 +21,76 @@ func main() {
|
|||||||
app.SetActivationPolicy(appkit.ApplicationActivationPolicyAccessory)
|
app.SetActivationPolicy(appkit.ApplicationActivationPolicyAccessory)
|
||||||
|
|
||||||
utils.SetupStatusBar(app)
|
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.ActivateIgnoringOtherApps(true)
|
||||||
app.Run()
|
app.Run()
|
||||||
|
|||||||
@@ -14,10 +14,55 @@ var PRESET_COLORS = []struct {
|
|||||||
{"黄色", 0xFF, 0xFF, 0x00},
|
{"黄色", 0xFF, 0xFF, 0x00},
|
||||||
{"橙色", 0xFF, 0xA5, 0x00},
|
{"橙色", 0xFF, 0xA5, 0x00},
|
||||||
{"紫色", 0x80, 0x00, 0x80},
|
{"紫色", 0x80, 0x00, 0x80},
|
||||||
|
{"自定义", 0x00, 0x00, 0x00},
|
||||||
|
|
||||||
//{"熄灭", 0x00, 0x00, 0x00},
|
//{"熄灭", 0x00, 0x00, 0x00},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PRESET_MULTI_COLORS 预设颜色
|
||||||
|
var PRESET_MULTI_COLORS = []struct {
|
||||||
|
Name string
|
||||||
|
Color1 []byte
|
||||||
|
Color2 []byte
|
||||||
|
}{
|
||||||
|
// 霓虹紫蓝 (非常电竞范)
|
||||||
|
{"霓虹紫蓝",
|
||||||
|
[]byte{0xFF, 0x00, 0xFF}, // 紫色 (Magenta)
|
||||||
|
[]byte{0x00, 0xFF, 0xFF}, // 青蓝色 (Cyan)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 冰火 (经典红蓝对比)
|
||||||
|
{"冰火",
|
||||||
|
[]byte{0xFF, 0x00, 0x00}, // 纯红
|
||||||
|
[]byte{0x00, 0x00, 0xFF}, // 纯蓝
|
||||||
|
},
|
||||||
|
|
||||||
|
// 赛博朋克 (经典配色)
|
||||||
|
{"赛博粉黄",
|
||||||
|
[]byte{0xFF, 0x00, 0x7F}, // 玫粉色
|
||||||
|
[]byte{0xFF, 0xD7, 0x00}, // 金黄色
|
||||||
|
},
|
||||||
|
|
||||||
|
// 森林气息 (柔和过渡)
|
||||||
|
{"森翠",
|
||||||
|
[]byte{0x00, 0xFF, 0x00}, // 绿色
|
||||||
|
[]byte{0x00, 0xFF, 0x7F}, // 春绿
|
||||||
|
},
|
||||||
|
|
||||||
|
// 晚霞 (暖色调)
|
||||||
|
{"晚霞",
|
||||||
|
[]byte{0xFF, 0x45, 0x00}, // 橙红
|
||||||
|
[]byte{0xFF, 0x14, 0x93}, // 深粉
|
||||||
|
},
|
||||||
|
|
||||||
|
// 黑客帝国 (极简)
|
||||||
|
{"矩阵",
|
||||||
|
[]byte{0x00, 0xFF, 0x00}, // 翠绿
|
||||||
|
[]byte{0x00, 0x33, 0x00}, // 暗绿 (深邃感)
|
||||||
|
},
|
||||||
|
//{"熄灭", 0x00, 0x00, 0x00},
|
||||||
|
}
|
||||||
|
|
||||||
// 雷蛇绿 (标志性的 Razer Green)
|
// 雷蛇绿 (标志性的 Razer Green)
|
||||||
//razerGreen := []byte{0x00, 0xFF, 0x00} // 或者稍微深一点的 0x44, 0xFF, 0x00
|
//razerGreen := []byte{0x00, 0xFF, 0x00} // 或者稍微深一点的 0x44, 0xFF, 0x00
|
||||||
|
|
||||||
@@ -85,16 +130,18 @@ func (rd *RazerDevice) SetOffLightsColor(color []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetBreathingColor 设置双色呼吸
|
// SetBreathingColor 设置双色呼吸
|
||||||
func (rd *RazerDevice) SetBreathingColor() {
|
func (rd *RazerDevice) SetBreathingColor(subMode byte, rgb1 []byte, rgb2 []byte, speed byte) {
|
||||||
// 1. 定义呼吸子模式
|
// 1. 定义呼吸子模式
|
||||||
subMode := byte(0x02) // 0x02 为双色切换呼吸
|
//subMode := byte(0x02) // 0x02 为双色切换呼吸
|
||||||
rgb1 := []byte{0xFF, 0x00, 0x00} // 颜色1: 红色
|
//rgb1 := []byte{0xFF, 0x00, 0x00} // 颜色1: 红色
|
||||||
rgb2 := []byte{0x00, 0x00, 0xFF} // 颜色2: 蓝色
|
//rgb2 := []byte{0x00, 0x00, 0xFF} // 颜色2: 蓝色
|
||||||
speed := byte(0x01) // 速度: 1(快) - 3(慢), 200可能过大,建议先用1测试
|
//speed := byte(0x01) // 速度: 1(快) - 3(慢), 200可能过大,建议先用1测试
|
||||||
|
//fmt.Println(subMode)
|
||||||
|
|
||||||
// 2. 构造参数包 (总长 8 字节)
|
// 2. 构造参数包 (总长 8 字节)
|
||||||
// 结构: [SubMode, R1, G1, B1, R2, G2, B2, Speed]
|
// 结构: [SubMode, R1, G1, B1, R2, G2, B2, Speed]
|
||||||
breathingParams := append([]byte{subMode}, append(rgb1, append(rgb2, speed)...)...)
|
breathingParams := append([]byte{subMode}, append(rgb1, append(rgb2, speed)...)...)
|
||||||
|
fmt.Println(breathingParams)
|
||||||
|
|
||||||
// 3. 调用新版 buildArguments (内部不再强制加 0x01)
|
// 3. 调用新版 buildArguments (内部不再强制加 0x01)
|
||||||
args := buildArguments(KBD_EFFECT_BREATHING, KBD_BACKLIGHT_LED, breathingParams)
|
args := buildArguments(KBD_EFFECT_BREATHING, KBD_BACKLIGHT_LED, breathingParams)
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/progrium/darwinkit/macos/appkit"
|
||||||
|
)
|
||||||
|
|
||||||
// --- 硬件识别常量 ---
|
// --- 硬件识别常量 ---
|
||||||
|
|
||||||
// RAZER_VID (Vendor ID) 是雷蛇在 USB 协会注册的厂商唯一识别码
|
// RAZER_VID (Vendor ID) 是雷蛇在 USB 协会注册的厂商唯一识别码
|
||||||
@@ -60,3 +66,32 @@ const KBD_BACKLIGHT_LED = 0x05 // 键盘背光灯光控制索引
|
|||||||
const KBD_CMD_CLASS = 0x0F // 键盘指令分类 (Command Class)
|
const KBD_CMD_CLASS = 0x0F // 键盘指令分类 (Command Class)
|
||||||
const KBD_CMD_ID = 0x02 // 键盘指令标识 (Command ID)
|
const KBD_CMD_ID = 0x02 // 键盘指令标识 (Command ID)
|
||||||
const KBD_DATA_SIZE = 9 // 键盘数据包的有效负载长度
|
const KBD_DATA_SIZE = 9 // 键盘数据包的有效负载长度
|
||||||
|
|
||||||
|
// 全局变量,追踪当前色盘控制的设备
|
||||||
|
var (
|
||||||
|
activeDeviceKey string
|
||||||
|
colorPanel appkit.ColorPanel
|
||||||
|
)
|
||||||
|
|
||||||
|
func initColorPanel() {
|
||||||
|
// 修复:unsafe.Pointer 与 nil 比较
|
||||||
|
if colorPanel.Ptr() == nil {
|
||||||
|
colorPanel = appkit.ColorPanel_SharedColorPanel()
|
||||||
|
colorPanel.SetContinuous(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func openColorPicker() {
|
||||||
|
// 1. 获取共享的色盘实例(推荐做法)
|
||||||
|
colorPanel := appkit.ColorPanel_SharedColorPanel()
|
||||||
|
|
||||||
|
// 2. 配置 Target/Action (可选)
|
||||||
|
// 注意:在 Go 中处理 Selector 回调比较复杂,通常需要注册一个特定的 Class
|
||||||
|
|
||||||
|
// 3. 激活应用并显示色盘
|
||||||
|
// 如果你的程序不是 GUI 模式,色盘可能会隐藏在其他窗口后面
|
||||||
|
appkit.Application_SharedApplication().ActivateIgnoringOtherApps(true)
|
||||||
|
colorPanel.MakeKeyAndOrderFront(nil)
|
||||||
|
|
||||||
|
fmt.Println("Color Picker 已经尝试打开")
|
||||||
|
}
|
||||||
|
|||||||
269
utils/menu.go
269
utils/menu.go
@@ -7,13 +7,105 @@ import (
|
|||||||
"github.com/progrium/darwinkit/objc"
|
"github.com/progrium/darwinkit/objc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var deviceStateCache = make(map[string]State)
|
var Devs map[string]*RazerDevice = make(map[string]*RazerDevice)
|
||||||
|
|
||||||
type State struct {
|
var Temp = TempData{}
|
||||||
Effect int
|
|
||||||
Color string
|
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) {
|
func UpdateMenu(menu appkit.Menu, app appkit.Application, statusBarItem appkit.StatusItem) {
|
||||||
menu.RemoveAllItems()
|
menu.RemoveAllItems()
|
||||||
|
|
||||||
@@ -25,7 +117,7 @@ func UpdateMenu(menu appkit.Menu, app appkit.Application, statusBarItem appkit.S
|
|||||||
menu.AddItem(appkit.MenuItem_SeparatorItem())
|
menu.AddItem(appkit.MenuItem_SeparatorItem())
|
||||||
|
|
||||||
devices := ScanDevices()
|
devices := ScanDevices()
|
||||||
|
Devs = devices
|
||||||
// 更新 ToolTip 显示当前连接数
|
// 更新 ToolTip 显示当前连接数
|
||||||
statusBarItem.Button().SetToolTip(fmt.Sprintf("雷蛇控制器 - 已连接设备: %d", len(devices)))
|
statusBarItem.Button().SetToolTip(fmt.Sprintf("雷蛇控制器 - 已连接设备: %d", len(devices)))
|
||||||
|
|
||||||
@@ -35,6 +127,9 @@ func UpdateMenu(menu appkit.Menu, app appkit.Application, statusBarItem appkit.S
|
|||||||
menu.AddItem(none)
|
menu.AddItem(none)
|
||||||
} else {
|
} else {
|
||||||
for _, dev := range devices {
|
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 := appkit.NewMenuItemWithAction("⌨️ "+dev.Name, "", func(sender objc.Object) {})
|
||||||
devTitle.SetEnabled(false)
|
devTitle.SetEnabled(false)
|
||||||
@@ -53,14 +148,21 @@ func UpdateMenu(menu appkit.Menu, app appkit.Application, statusBarItem appkit.S
|
|||||||
colorMenu := appkit.NewMenuWithTitle("Colors")
|
colorMenu := appkit.NewMenuWithTitle("Colors")
|
||||||
for _, c := range PRESET_COLORS {
|
for _, c := range PRESET_COLORS {
|
||||||
colorItem := appkit.NewMenuItemWithAction(c.Name, "", func(sender objc.Object) {
|
colorItem := appkit.NewMenuItemWithAction(c.Name, "", func(sender objc.Object) {
|
||||||
//dev.ApplyEffect(KBD_EFFECT_STATIC, c.R, c.G, c.B)
|
if c.Name == "自定义" {
|
||||||
dev.SetStaticColor([]byte{c.R, c.G, c.B})
|
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}
|
||||||
key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
openColorPicker()
|
||||||
deviceStateCache[key] = State{Effect: KBD_EFFECT_STATIC, Color: c.Name}
|
} 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)
|
UpdateMenu(menu, app, statusBarItem)
|
||||||
})
|
})
|
||||||
if dev.CurrentEffect == KBD_EFFECT_STATIC && dev.CurrentColor == c.Name {
|
stateVal := DeviceStateCache[key]
|
||||||
|
if stateVal != nil && dev.CurrentEffect == KBD_EFFECT_STATIC && stateVal.GetColorKey() == c.Name {
|
||||||
colorItem.SetState(appkit.ControlStateValueOn)
|
colorItem.SetState(appkit.ControlStateValueOn)
|
||||||
}
|
}
|
||||||
colorMenu.AddItem(colorItem)
|
colorMenu.AddItem(colorItem)
|
||||||
@@ -69,52 +171,123 @@ func UpdateMenu(menu appkit.Menu, app appkit.Application, statusBarItem appkit.S
|
|||||||
menu.AddItem(staticItem)
|
menu.AddItem(staticItem)
|
||||||
|
|
||||||
// --- B. 呼吸模式 ---
|
// --- B. 呼吸模式 ---
|
||||||
breathItem := appkit.NewMenuItemWithAction("🌬️ 呼吸模式", "", func(sender objc.Object) {
|
breathItem := appkit.NewMenuItemWithAction("🌬️ 呼吸模式", "", func(sender objc.Object) {})
|
||||||
dev.SetBreathingColor() // 默认绿色
|
|
||||||
key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
|
||||||
deviceStateCache[key] = State{Effect: KBD_EFFECT_BREATHING, Color: ""}
|
|
||||||
UpdateMenu(menu, app, statusBarItem)
|
|
||||||
})
|
|
||||||
if dev.CurrentEffect == KBD_EFFECT_BREATHING {
|
if dev.CurrentEffect == KBD_EFFECT_BREATHING {
|
||||||
breathItem.SetState(appkit.ControlStateValueOn)
|
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)
|
menu.AddItem(breathItem)
|
||||||
|
|
||||||
// --- C. 波浪模式 ---
|
//// --- C. 波浪模式 ---
|
||||||
waveItem := appkit.NewMenuItemWithAction("🌊 波浪模式", "", func(sender objc.Object) {
|
//waveItem := appkit.NewMenuItemWithAction("🌊 波浪模式", "", func(sender objc.Object) {
|
||||||
//dev.ApplyEffect(KBD_EFFECT_WAVE, 0x01, 0x00, 0x00)
|
// //dev.ApplyEffect(KBD_EFFECT_WAVE, 0x01, 0x00, 0x00)
|
||||||
key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
// key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
||||||
deviceStateCache[key] = State{Effect: KBD_EFFECT_WAVE, Color: ""}
|
// deviceStateCache[key] = State{Effect: KBD_EFFECT_WAVE, Color: ""}
|
||||||
UpdateMenu(menu, app, statusBarItem)
|
// UpdateMenu(menu, app, statusBarItem)
|
||||||
})
|
//})
|
||||||
if dev.CurrentEffect == KBD_EFFECT_WAVE {
|
//if dev.CurrentEffect == KBD_EFFECT_WAVE {
|
||||||
waveItem.SetState(appkit.ControlStateValueOn)
|
// waveItem.SetState(appkit.ControlStateValueOn)
|
||||||
}
|
//}
|
||||||
menu.AddItem(waveItem)
|
//menu.AddItem(waveItem)
|
||||||
|
|
||||||
// --- D. 响应模式 ---
|
// --- D. 响应模式 ---
|
||||||
reactiveItem := appkit.NewMenuItemWithAction("🌊 响应模式", "", func(sender objc.Object) {
|
//reactiveItem := appkit.NewMenuItemWithAction("🌊 响应模式", "", func(sender objc.Object) {
|
||||||
//dev.ApplyEffect(KBD_EFFECT_WAVE, 0x01, 0x00, 0x00)
|
// //dev.ApplyEffect(KBD_EFFECT_WAVE, 0x01, 0x00, 0x00)
|
||||||
key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
// key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
||||||
deviceStateCache[key] = State{Effect: KBD_EFFECT_REACTIVE, Color: ""}
|
// deviceStateCache[key] = State{Effect: KBD_EFFECT_REACTIVE, Color: ""}
|
||||||
UpdateMenu(menu, app, statusBarItem)
|
// UpdateMenu(menu, app, statusBarItem)
|
||||||
})
|
//})
|
||||||
if dev.CurrentEffect == KBD_EFFECT_REACTIVE {
|
//if dev.CurrentEffect == KBD_EFFECT_REACTIVE {
|
||||||
reactiveItem.SetState(appkit.ControlStateValueOn)
|
// reactiveItem.SetState(appkit.ControlStateValueOn)
|
||||||
}
|
//}
|
||||||
menu.AddItem(reactiveItem)
|
//menu.AddItem(reactiveItem)
|
||||||
|
|
||||||
// --- E. 关灯模式 --- 关灯
|
// --- E. 关灯模式 --- 关灯
|
||||||
offLightsItem := appkit.NewMenuItemWithAction("关灯模式", "", func(sender objc.Object) {
|
//offLightsItem := appkit.NewMenuItemWithAction("关灯模式", "", func(sender objc.Object) {
|
||||||
dev.SetOffLightsColor([]byte{0x00, 0x00, 0x00})
|
// dev.SetOffLightsColor([]byte{0x00, 0x00, 0x00})
|
||||||
key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
// //key := fmt.Sprintf("%s|%s|%d", dev.Serial, dev.Product, dev.ProductID)
|
||||||
deviceStateCache[key] = State{Effect: KBD_EFFECT_OFFLIGHTS, Color: ""}
|
// deviceStateCache[key] = State{Effect: KBD_EFFECT_OFFLIGHTS, Color: ""}
|
||||||
UpdateMenu(menu, app, statusBarItem)
|
// UpdateMenu(menu, app, statusBarItem)
|
||||||
})
|
//})
|
||||||
if dev.CurrentEffect == KBD_EFFECT_OFFLIGHTS {
|
//if dev.CurrentEffect == KBD_EFFECT_OFFLIGHTS {
|
||||||
offLightsItem.SetState(appkit.ControlStateValueOn)
|
// offLightsItem.SetState(appkit.ControlStateValueOn)
|
||||||
}
|
//}
|
||||||
menu.AddItem(offLightsItem)
|
//menu.AddItem(offLightsItem)
|
||||||
|
|
||||||
//modeMenuItem.SetSubmenu(modeSubMenu)
|
//modeMenuItem.SetSubmenu(modeSubMenu)
|
||||||
//menu.AddItem(modeMenuItem)
|
//menu.AddItem(modeMenuItem)
|
||||||
|
|||||||
@@ -168,9 +168,9 @@ func ScanDevices() map[string]*RazerDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 从缓存恢复状态
|
// 从缓存恢复状态
|
||||||
if s, found := deviceStateCache[key]; found {
|
if s, found := DeviceStateCache[key]; found {
|
||||||
grouped[key].CurrentEffect = s.Effect
|
grouped[key].CurrentEffect = s.GetEffect()
|
||||||
grouped[key].CurrentColor = s.Color
|
//grouped[key].CurrentColor = s.Color
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user