diff --git a/common/systemdunit/transientunit.go b/common/systemdunit/transientunit.go index 7dae7bed8..881b3cccd 100644 --- a/common/systemdunit/transientunit.go +++ b/common/systemdunit/transientunit.go @@ -81,12 +81,16 @@ func (t *TransientUnit) WaitforFinish(sigLoop *dbusutil.SignalLoop) bool { return false } t.unit.InitSignalExt(sigLoop, true) - var result = make(chan string) + var result = make(chan string, 1) // buffered channel to prevent blocking t.unit.ConnectPropertiesChanged(func(interfaceName string, changedProperties map[string]dbus.Variant, invalidatedProperties []string) { _, ok := changedProperties["ActiveState"] if ok { val := changedProperties["ActiveState"].String() - result <- val + select { + case result <- val: + default: + // channel is full or closed, skip this update + } } }) defer func() { diff --git a/inputdevices1/ifc.go b/inputdevices1/ifc.go index f0cf92748..50ce5476b 100644 --- a/inputdevices1/ifc.go +++ b/inputdevices1/ifc.go @@ -5,6 +5,8 @@ package inputdevices import ( + "fmt" + "github.com/godbus/dbus/v5" langselector "github.com/linuxdeepin/dde-daemon/langselector1" "github.com/linuxdeepin/go-lib/dbusutil" @@ -31,8 +33,12 @@ func (tpad *Touchpad) Reset() *dbus.Error { } func (tpad *Touchpad) Enable(enabled bool) *dbus.Error { - tpad.enable(enabled) - return nil + sysTP := tpad.sysTouchPad + if sysTP != nil { + return dbusutil.ToError(sysTP.SetTouchpadEnable(0, enabled)) + } else { + return dbusutil.ToError(fmt.Errorf("system touchpad is nul")) + } } func (w *Wacom) Reset() *dbus.Error { diff --git a/inputdevices1/inputdevices_dbusutil.go b/inputdevices1/inputdevices_dbusutil.go index d1ccc6aeb..dfc5b67c7 100644 --- a/inputdevices1/inputdevices_dbusutil.go +++ b/inputdevices1/inputdevices_dbusutil.go @@ -76,6 +76,19 @@ func (v *Touchpad) emitPropChangedDeviceList(value string) error { return v.service.EmitPropertyChanged(v, "DeviceList", value) } +func (v *Touchpad) setPropTPadEnable(value bool) (changed bool) { + if v.TPadEnable != value { + v.TPadEnable = value + v.emitPropChangedTPadEnable(value) + return true + } + return false +} + +func (v *Touchpad) emitPropChangedTPadEnable(value bool) error { + return v.service.EmitPropertyChanged(v, "TPadEnable", value) +} + func (v *TrackPoint) setPropDeviceList(value string) (changed bool) { if v.DeviceList != value { v.DeviceList = value diff --git a/inputdevices1/mouse.go b/inputdevices1/mouse.go index 0ff78b6e6..119ed1169 100644 --- a/inputdevices1/mouse.go +++ b/inputdevices1/mouse.go @@ -95,7 +95,7 @@ func (m *Mouse) init() { tpad := m.touchPad if !m.Exist { - if tpad.Exist && tpad.TPadEnable.Get() { + if tpad.Exist && tpad.TPadEnable { tpad.setDisableTemporary(false) } return @@ -107,7 +107,7 @@ func (m *Mouse) init() { m.enableAdaptiveAccelProfile() m.motionAcceleration() m.motionThreshold() - if m.DisableTpad.Get() && tpad.TPadEnable.Get() { + if m.DisableTpad.Get() && tpad.TPadEnable { m.disableTouchPad() } } diff --git a/inputdevices1/touchpad.go b/inputdevices1/touchpad.go index 8f2872de2..c2d8c388e 100644 --- a/inputdevices1/touchpad.go +++ b/inputdevices1/touchpad.go @@ -50,13 +50,14 @@ const ( ) type Touchpad struct { - service *dbusutil.Service - PropsMu sync.RWMutex - Exist bool - DeviceList string + service *dbusutil.Service + PropsMu sync.RWMutex + sysTouchPad inputdevices.Touchpad + Exist bool + DeviceList string // dbusutil-gen: ignore-below - TPadEnable dconfig.Bool `prop:"access:rw"` + TPadEnable bool `prop:"access:rw"` // 通过监听 system 端 Enable 属性动态更新,不使用 dconfig LeftHanded dconfig.Bool `prop:"access:rw"` DisableIfTyping dconfig.Bool `prop:"access:rw"` NaturalScroll dconfig.Bool `prop:"access:rw"` @@ -98,7 +99,6 @@ func newTouchpad(service *dbusutil.Service) *Touchpad { panic("Touchpad DConfig initialization failed - cannot continue without dconfig support") } - tpad.TPadEnable.Bind(tpad.dsgTouchpadConfig, dconfigKeyTouchpadEnabled) tpad.LeftHanded.Bind(tpad.dsgTouchpadConfig, dconfigKeyTouchpadLeftHanded) tpad.DisableIfTyping.Bind(tpad.dsgTouchpadConfig, dconfigKeyTouchpadDisableTyping) tpad.NaturalScroll.Bind(tpad.dsgTouchpadConfig, dconfigKeyTouchpadNaturalScroll) @@ -117,18 +117,47 @@ func newTouchpad(service *dbusutil.Service) *Touchpad { tpad.DoubleClick.Bind(tpad.dsgMouseConfig, dconfigKeyDoubleClick) tpad.DragThreshold.Bind(tpad.dsgMouseConfig, dconfigKeyDragThreshold) - // TODO: treeland环境暂不支持 - if hasTreeLand { - return tpad - } - tpad.updateDXTpads() - if conn, err := dbus.SystemBus(); err != nil { logger.Warning(err) } else { tpad.systemConn = conn tpad.systemSigLoop = dbusutil.NewSignalLoop(conn, 10) + tpad.sysTouchPad, err = inputdevices.NewTouchpad(tpad.systemConn, "/org/deepin/dde/InputDevices1/Touchpad") + if err != nil { + logger.Warning(err) + } else { + // 在这里注册信号监听,避免 init 中重复注册 + tpad.sysTouchPad.InitSignalExt(tpad.systemSigLoop, true) + tpad.sysTouchPad.Enable().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + logger.Infof("System touchpad Enable changed: %v", value) + tpad.enable(value) + }) + // 因为通过udev禁用触控板时, libinput感知不到触控板,通过系统touchpad查询是否存在触控板设备 + tpad.sysTouchPad.DeviceList().ConnectChanged(func(hasValue bool, value []string) { + if !hasValue { + return + } + logger.Infof("System touchpad DeviceList changed: %v", value) + if !tpad.TPadEnable { + if len(value) == 0 { + tpad.setPropExist(false) + } else { + tpad.setPropExist(true) + } + } + }) + tpad.systemSigLoop.Start() + tpad.TPadEnable, _ = tpad.sysTouchPad.Enable().Get(0) + } + } + // TODO: treeland环境暂不支持 + if hasTreeLand { + return tpad } + tpad.updateDXTpads() return tpad } @@ -180,28 +209,15 @@ func (tpad *Touchpad) init() { return } - if tpad.systemConn != nil { - sysTouchPad, err := inputdevices.NewTouchpad(tpad.systemConn, "/org/deepin/dde/InputDevices1/Touchpad") - if err != nil { + // 从 system 端获取初始状态 + if tpad.sysTouchPad != nil { + if enabled, err := tpad.sysTouchPad.Enable().Get(0); err != nil { logger.Warning(err) } else { - sysTouchPad.InitSignalExt(tpad.systemSigLoop, true) - sysTouchPad.Enable().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - tpad.enable(value) - }) - if enabled, err := sysTouchPad.Enable().Get(0); err != nil { - logger.Warning(err) - } else { - tpad.TPadEnable.Set(enabled) - } + tpad.setPropTPadEnable(enabled) } } - currentState := tpad.TPadEnable.Get() - tpad.forceEnable(currentState) tpad.enableLeftHanded() tpad.enableNaturalScroll() tpad.enableEdgeScroll() @@ -213,10 +229,6 @@ func (tpad *Touchpad) init() { tpad.disableWhileTyping() tpad.enablePalmDetect() tpad.setPalmDimensions() - - if tpad.systemSigLoop != nil { - tpad.systemSigLoop.Start() - } } func (tpad *Touchpad) handleDeviceChanged() { @@ -238,44 +250,46 @@ func (tpad *Touchpad) updateDXTpads() { tpad.PropsMu.Lock() var v string - if len(tpad.devInfos) == 0 { - tpad.setPropExist(false) + if tpad.TPadEnable { + if len(tpad.devInfos) == 0 { + tpad.setPropExist(false) + } else { + tpad.setPropExist(true) + v = tpad.devInfos.string() + } } else { - tpad.setPropExist(true) - v = tpad.devInfos.string() + if tpad.sysTouchPad != nil { + sysTpList, _ := tpad.sysTouchPad.DeviceList().Get(0) + tpad.setPropExist(len(sysTpList) > 0) + } } + tpad.setPropDeviceList(v) tpad.PropsMu.Unlock() } // 受鼠标禁用触控板影响,临时关闭触控板 func (tpad *Touchpad) setDisableTemporary(disable bool) { - if disable == tpad.disableTemporary { - return - } if len(tpad.devInfos) > 0 { for _, v := range tpad.devInfos { - err := v.Enable(!disable && tpad.TPadEnable.Get()) + err := v.Enable(!disable && tpad.TPadEnable) if err != nil { logger.Warningf("Enable '%v - %v' failed: %v", v.Id, v.Name, err) } } } - tpad.disableTemporary = disable } func (tpad *Touchpad) enable(enabled bool) { - if enabled == tpad.TPadEnable.Get() { + if enabled == tpad.TPadEnable { return } - tpad.forceEnable(enabled) -} - -func (tpad *Touchpad) forceEnable(enabled bool) { - if len(tpad.devInfos) > 0 { + // 禁用时有system 的touchpad设置 + // 重新开启时,需要考虑插入鼠标时禁用触控板 + if len(tpad.devInfos) > 0 && enabled { for _, v := range tpad.devInfos { - err := v.Enable(!tpad.disableTemporary && enabled) + err := v.Enable(!tpad.disableTemporary) if err != nil { logger.Warningf("Enable '%v - %v' failed: %v", v.Id, v.Name, err) @@ -284,13 +298,7 @@ func (tpad *Touchpad) forceEnable(enabled bool) { } enableGesture(enabled) - tpad.TPadEnable.Set(enabled) - sysTouchPad, err := inputdevices.NewTouchpad(tpad.systemConn, "/org/deepin/dde/InputDevices1/Touchpad") - if err == nil && sysTouchPad != nil { - if err = sysTouchPad.SetTouchpadEnable(0, enabled); err != nil { - logger.Warning(err) - } - } + tpad.setPropTPadEnable(enabled) } func (tpad *Touchpad) enableLeftHanded() { @@ -544,7 +552,7 @@ func enableGesture(enabled bool) { return } - dconfig.SetValue("dconfig", enabled) + dconfig.SetValue("touchpadEnabled", enabled) } func (tpad *Touchpad) initTouchpadDConfig() error { @@ -562,13 +570,6 @@ func (tpad *Touchpad) initTouchpadDConfig() error { tpad.dsgTouchpadConfig.ConnectValueChanged(func(key string) { logger.Debugf("Touchpad dconfig value changed: %s", key) switch key { - case dconfigKeyTouchpadEnabled: - enabled, err := tpad.dsgTouchpadConfig.GetValueBool(dconfigKeyTouchpadEnabled) - if err != nil { - logger.Warningf("Failed to get touchpad enabled value from dconfig: %v", err) - } else { - tpad.enable(enabled) - } case dconfigKeyTouchpadLeftHanded: tpad.enableLeftHanded() case dconfigKeyTouchpadDisableTyping: diff --git a/system/inputdevices1/libinput.go b/system/inputdevices1/libinput.go index ec468c9ae..3123e6f2e 100644 --- a/system/inputdevices1/libinput.go +++ b/system/inputdevices1/libinput.go @@ -25,7 +25,7 @@ func log_handler_go(priority C.enum_libinput_log_priority, cstr *C.char) { case C.LIBINPUT_LOG_PRIORITY_INFO: logger.Info(str) case C.LIBINPUT_LOG_PRIORITY_ERROR: - logger.Error(str) + logger.Warning(str) } } diff --git a/system/inputdevices1/touchpad.go b/system/inputdevices1/touchpad.go index 65d202321..5419ddf97 100644 --- a/system/inputdevices1/touchpad.go +++ b/system/inputdevices1/touchpad.go @@ -5,8 +5,9 @@ package inputdevices1 import ( - "errors" "os" + "os/exec" + "path/filepath" "strings" "github.com/godbus/dbus/v5" @@ -15,15 +16,24 @@ import ( ) const ( - // touchpad接口的导出不再依赖touchpadSwitchFile文件的存在,只有设置的时候才会读写该文件配置 - touchpadSwitchFile = "/proc/uos/touchpad_switch" touchpadDBusPath = "/org/deepin/dde/InputDevices1/Touchpad" touchpadDBusInterface = "org.deepin.dde.InputDevices1.Touchpad" + + // udev 规则文件路径 + udevRuleFile = "/etc/udev/rules.d/90-dde-touchpad.rules" + // udev 规则内容(禁用触控板) + // ENV{LIBINPUT_IGNORE_DEVICE}="1": 让 libinput 忽略设备 + // 注意:这只影响 libinput,evtest 仍能读取内核事件 + udevRuleContent = `# DDE - Disable touchpad via libinput +SUBSYSTEM=="input", KERNEL=="event*", ENV{ID_INPUT_TOUCHPAD}=="1", ENV{LIBINPUT_IGNORE_DEVICE}="1" +` ) type Touchpad struct { - service *dbusutil.Service - Enable bool + service *dbusutil.Service + Enable bool + DeviceList []string + udevMonitor *udevMonitor } func newTouchpad(service *dbusutil.Service) *Touchpad { @@ -31,43 +41,161 @@ func newTouchpad(service *dbusutil.Service) *Touchpad { service: service, Enable: getDsgConf(), } + + // 初始化 udev 监听器 + t.udevMonitor = newUdevMonitor(func(devices []string) { + t.handleDeviceChange(devices) + }) + + // 初始化设备列表 + if t.udevMonitor != nil { + devices := t.udevMonitor.enumerateDevices() + t.setPropDeviceList(devices) + logger.Infof("touchpad initialized with %d device(s)", len(devices)) + } + return t } +// handleDeviceChange 处理设备变化 +func (t *Touchpad) handleDeviceChange(devices []string) { + t.setPropDeviceList(devices) + logger.Infof("touchpad devices updated: %d device(s)", len(devices)) +} + func (t *Touchpad) SetTouchpadEnable(enabled bool) *dbus.Error { err := t.setTouchpadEnable(enabled) return dbusutil.ToError(err) } func (t *Touchpad) setTouchpadEnable(enabled bool) error { - t.setPropEnable(enabled) + logger.Debugf("setTouchpadEnable: %v", enabled) + if !t.setPropEnable(enabled) { + return nil + } + + // 1. 保存到 dconfig(持久化配置) err := setDsgConf(enabled) if err != nil { - logger.Warning(err) + logger.Warning("failed to save to dconfig:", err) return err } - if err = TouchpadExist(touchpadSwitchFile); err != nil { - return nil + // 2. 使用 udev 规则方案 + if err := t.setTouchpadEnableViaUdev(enabled); err != nil { + logger.Warning("udev rules method failed:", err) + return err } - current, err := TouchpadEnable(touchpadSwitchFile) - if err != nil { - logger.Warning(" TouchpadEnable err : ", err) + + return nil +} + +// setTouchpadEnableViaUdev 通过 udev 规则禁用/启用触控板 +func (t *Touchpad) setTouchpadEnableViaUdev(enabled bool) error { + if enabled { + // 启用:删除 udev 规则文件 + if err := os.Remove(udevRuleFile); err != nil && !os.IsNotExist(err) { + return err + } + logger.Info("removed udev rule file:", udevRuleFile) + } else { + // 禁用:检查文件是否已存在且内容相同 + existingContent, err := os.ReadFile(udevRuleFile) + if err == nil && string(existingContent) == udevRuleContent { + logger.Debug("udev rule file already exists with correct content, skip writing") + return nil + } + + // 创建或覆盖 udev 规则文件 + if err := os.WriteFile(udevRuleFile, []byte(udevRuleContent), 0644); err != nil { + return err + } + logger.Info("created udev rule file:", udevRuleFile) + } + + // 重新加载 udev 规则 + if err := reloadUdevRules(); err != nil { + logger.Warning("failed to reload udev rules:", err) + } + + // 只触发触控板设备,减少不必要的事件 + if err := t.triggerTouchpadDevices(); err != nil { + logger.Warning("failed to trigger touchpad devices:", err) + } + + return nil +} + +// reloadUdevRules 重新加载 udev 规则 +func reloadUdevRules() error { + cmd := exec.Command("udevadm", "control", "--reload-rules") + if err := cmd.Run(); err != nil { return err } - if current == enabled { - logger.Info("current touchPad state is same : ", enabled) + logger.Info("udev rules reloaded") + return nil +} + +// triggerTouchpadDevices 只触发触控板设备,减少不必要的事件 +func (t *Touchpad) triggerTouchpadDevices() error { + touchpadNames := t.DeviceList + if len(touchpadNames) == 0 { + logger.Warning("no touchpad devices to trigger") return nil } - arg := "enable" - if !enabled { - arg = "disable" - } - err = os.WriteFile(touchpadSwitchFile, []byte(arg), 0644) + + sysInputPath := "/sys/class/input" + files, err := os.ReadDir(sysInputPath) if err != nil { - logger.Warning(" os.WriteFile err : ", err) return err } + + count := 0 + for _, file := range files { + // 只处理 event 设备 + if !strings.HasPrefix(file.Name(), "event") { + continue + } + + // 读取设备名称 + namePath := filepath.Join(sysInputPath, file.Name(), "device/name") + nameBytes, err := os.ReadFile(namePath) + if err != nil { + continue + } + + name := strings.TrimSpace(string(nameBytes)) + + // 检查是否是触控板设备 + isTouchpad := false + for _, touchpadName := range touchpadNames { + if name == touchpadName { + isTouchpad = true + break + } + } + + if !isTouchpad { + continue + } + + // 只触发这个触控板设备 + cmd := exec.Command("udevadm", "trigger", "--action=change", "--sysname="+file.Name()) + if err := cmd.Run(); err != nil { + logger.Warningf("failed to trigger %s: %v", file.Name(), err) + } else { + count++ + logger.Debugf("triggered touchpad device: %s (%s)", file.Name(), name) + } + + } + + if count > 0 { + logger.Infof("triggered %d touchpad device(s)", count) + } else { + logger.Warning("no touchpad devices found to trigger") + } + return nil } @@ -113,30 +241,6 @@ func getDsgConf() bool { return data.Value().(bool) } -func TouchpadEnable(filePath string) (bool, error) { - err := TouchpadExist(filePath) - if err != nil { - return false, err - } - content, err := os.ReadFile(touchpadSwitchFile) - if err != nil { - return false, err - } - return strings.Contains(string(content), "enable"), nil -} - -func TouchpadExist(filePath string) error { - if filePath != touchpadSwitchFile { - return errors.New("filePath is inValid") - } - _, err := os.Stat(touchpadSwitchFile) - if err != nil { - logger.Warning(err) - return err - } - return nil -} - func (t *Touchpad) GetInterfaceName() string { return touchpadDBusInterface } @@ -145,6 +249,17 @@ func (t *Touchpad) export(path dbus.ObjectPath) error { return t.service.Export(path, t) } -func (t *Touchpad) stopExport() error { - return t.service.StopExport(t) +// setPropDeviceList 设置 DeviceList 属性并发送信号 +func (t *Touchpad) setPropDeviceList(devices []string) { + t.DeviceList = devices + // 发送属性变化信号 + _ = t.service.EmitPropertyChanged(t, "DeviceList", devices) +} + +// destroy 销毁触控板对象 +func (t *Touchpad) destroy() { + if t.udevMonitor != nil { + t.udevMonitor.destroy() + t.udevMonitor = nil + } } diff --git a/system/inputdevices1/udev_monitor.go b/system/inputdevices1/udev_monitor.go new file mode 100644 index 000000000..adb4ebbf7 --- /dev/null +++ b/system/inputdevices1/udev_monitor.go @@ -0,0 +1,247 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices1 + +// #cgo pkg-config: libudev +// #include +// #include +// #include +// #include +// +// // 永久阻塞等待 udev 事件(-1 表示永不超时) +// static struct udev_device* receive_device_blocking(struct udev_monitor *monitor) { +// struct pollfd pfd; +// pfd.fd = udev_monitor_get_fd(monitor); +// pfd.events = POLLIN; +// +// int ret = poll(&pfd, 1, -1); // -1 = 永不超时 +// if (ret > 0) { +// return udev_monitor_receive_device(monitor); +// } +// return NULL; // 只有出错才会到这里 +// } +import "C" +import ( + "strings" + "unsafe" +) + +// udevMonitor 使用 libudev 监听输入设备的插拔 +type udevMonitor struct { + udev *C.struct_udev + monitor *C.struct_udev_monitor + stopCh chan struct{} + callback func(devices []string) +} + +// newUdevMonitor 创建 udev 监听器 +func newUdevMonitor(callback func(devices []string)) *udevMonitor { + // 创建 udev 上下文 + udev := C.udev_new() + if udev == nil { + logger.Warning("failed to create udev context") + return nil + } + + // 创建 udev 监听器 + monitor := C.udev_monitor_new_from_netlink(udev, C.CString("udev")) + if monitor == nil { + logger.Warning("failed to create udev monitor") + C.udev_unref(udev) + return nil + } + + // 过滤:只监听 input 子系统 + subsystem := C.CString("input") + C.udev_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, nil) + C.free(unsafe.Pointer(subsystem)) + + // 启用监听器 + if C.udev_monitor_enable_receiving(monitor) < 0 { + logger.Warning("failed to enable udev monitor") + C.udev_monitor_unref(monitor) + C.udev_unref(udev) + return nil + } + + m := &udevMonitor{ + udev: udev, + monitor: monitor, + stopCh: make(chan struct{}), + callback: callback, + } + + // 启动监听 goroutine + go m.handleEvents() + + logger.Info("udev monitor started (using libudev)") + return m +} + +// handleEvents 处理 udev 事件(永久阻塞式) +func (m *udevMonitor) handleEvents() { + // 使用 channel 接收设备事件 + deviceCh := make(chan *C.struct_udev_device, 10) + + // 启动阻塞读取 goroutine + go func() { + for { + // 永久阻塞等待事件,不占用 CPU + device := C.receive_device_blocking(m.monitor) + if device != nil { + select { + case deviceCh <- device: + case <-m.stopCh: + C.udev_device_unref(device) + return + } + } + } + }() + + // 主循环处理事件或停止信号 + for { + select { + case <-m.stopCh: + return + case device := <-deviceCh: + m.handleDevice(device) + C.udev_device_unref(device) + } + } +} + +// handleDevice 处理单个设备事件 +func (m *udevMonitor) handleDevice(device *C.struct_udev_device) { + // 获取事件类型 + action := C.GoString(C.udev_device_get_action(device)) + + // 只关心 add 和 remove 事件 + if action != "add" && action != "remove" { + return + } + + // 获取设备节点 + devnode := C.GoString(C.udev_device_get_devnode(device)) + if devnode == "" || !strings.Contains(devnode, "/dev/input/event") { + return + } + + // 检查是否是触控板 + if !isTouchpadDeviceUdev(device) { + return + } + + logger.Debugf("udev: %s event for %s", action, devnode) + + // 重新扫描所有设备并回调 + if m.callback != nil { + devices := m.enumerateDevices() + m.callback(devices) + } +} + +// isTouchpadDeviceUdev 判断 udev 设备是否是触控板 +func isTouchpadDeviceUdev(device *C.struct_udev_device) bool { + // 方法1:检查 ID_INPUT_TOUCHPAD 属性(最准确) + propKey := C.CString("ID_INPUT_TOUCHPAD") + defer C.free(unsafe.Pointer(propKey)) + prop := C.udev_device_get_property_value(device, propKey) + if prop != nil && C.GoString(prop) == "1" { + return true + } + + // 方法2:通过设备名称判断(降级方案) + nameKey := C.CString("device/name") + defer C.free(unsafe.Pointer(nameKey)) + name := C.udev_device_get_sysattr_value(device, nameKey) + if name != nil { + devName := C.GoString(name) + nameLower := strings.ToLower(devName) + return strings.Contains(nameLower, "touchpad") || isTPadPS2Mouse(nameLower) + } + + return false +} + +// isTPadPS2Mouse 判断是否是 PS/2 触控板 +func isTPadPS2Mouse(name string) bool { + return strings.Contains(name, "ps/2") && strings.Contains(name, "mouse") && !strings.Contains(name, "usb") +} + +// enumerateDevices 枚举所有触控板设备 +func (m *udevMonitor) enumerateDevices() []string { + var devices []string + + // 创建枚举器 + enumerate := C.udev_enumerate_new(m.udev) + if enumerate == nil { + logger.Warning("failed to create udev enumerate") + return devices + } + defer C.udev_enumerate_unref(enumerate) + + // 过滤:只枚举 input 子系统 + subsystem := C.CString("input") + C.udev_enumerate_add_match_subsystem(enumerate, subsystem) + C.free(unsafe.Pointer(subsystem)) + + // 扫描设备 + C.udev_enumerate_scan_devices(enumerate) + + // 获取设备列表 + deviceMap := make(map[string]bool) + entry := C.udev_enumerate_get_list_entry(enumerate) + for entry != nil { + // 获取设备路径 + syspath := C.udev_list_entry_get_name(entry) + device := C.udev_device_new_from_syspath(m.udev, syspath) + + if device != nil { + // 只处理 event 设备 + devnode := C.GoString(C.udev_device_get_devnode(device)) + if devnode != "" && strings.Contains(devnode, "/dev/input/event") { + // 检查是否是触控板 + if isTouchpadDeviceUdev(device) { + // 获取设备名称 + nameKey := C.CString("device/name") + name := C.udev_device_get_sysattr_value(device, nameKey) + C.free(unsafe.Pointer(nameKey)) + if name != nil { + devName := strings.TrimSpace(C.GoString(name)) + if devName != "" && !deviceMap[devName] { + deviceMap[devName] = true + devices = append(devices, devName) + } + } + } + } + C.udev_device_unref(device) + } + + entry = C.udev_list_entry_get_next(entry) + } + + return devices +} + +// destroy 销毁监听器 +func (m *udevMonitor) destroy() { + if m.stopCh != nil { + close(m.stopCh) + } + + if m.monitor != nil { + C.udev_monitor_unref(m.monitor) + m.monitor = nil + } + + if m.udev != nil { + C.udev_unref(m.udev) + m.udev = nil + } + + logger.Info("udev monitor stopped") +} diff --git a/system/keyevent1/manager.go b/system/keyevent1/manager.go index 80b03550e..04d10876c 100644 --- a/system/keyevent1/manager.go +++ b/system/keyevent1/manager.go @@ -5,10 +5,6 @@ package keyevent1 import ( - "errors" - "os" - "strings" - "github.com/godbus/dbus/v5" inputdevices "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.inputdevices1" "github.com/linuxdeepin/go-lib/dbusutil" @@ -147,77 +143,23 @@ func (m *Manager) handleEvent(ev *KeyEvent) { if !pressed { return } - - //开关触控板逻辑 - _, err := os.Stat(touchpadSwitchFile) - if err != nil { - logger.Warning(err) + var TPadEnable bool + if m.touchPad != nil { + TPadEnable, _ = m.touchPad.Enable().Get(0) + } else { return } switch ev.Keycode { case KEY_TOUCHPAD_TOGGLE: - go func() { - content, err := os.ReadFile(touchpadSwitchFile) - if err != nil { - logger.Warning(err) - return - } - enable := strings.Contains(string(content), "enable") - - if m.touchPad == nil { - err = errors.New("m.TouchPad is nil") - } else { - err = m.touchPad.SetTouchpadEnable(0, !enable) - } - - if err != nil { - logger.Warning("Set TouchPad state err : ", err) - - // 接口调用异常时,需要保证开关触摸板正常 - arg := string(content) - if strings.Contains(arg, "enable") { - arg = "disable" - } else { - arg = "enable" - } - err = os.WriteFile(touchpadSwitchFile, []byte(arg), 0644) - if err != nil { - logger.Warning("write /proc/uos/touchpad_switch err : ", err) - } - } - }() + m.touchPad.SetTouchpadEnable(0, !TPadEnable) case KEY_TOUCHPAD_ON: - go func() { - if m.touchPad == nil { - err = errors.New("m.TouchPad is nil") - } else { - err = m.touchPad.SetTouchpadEnable(0, true) - } - - if err != nil { - logger.Warning("Set TouchPad state err : ", err) - err = os.WriteFile(touchpadSwitchFile, []byte("enable"), 0644) - if err != nil { - logger.Warning("write /proc/uos/touchpad_switch err : ", err) - } - } - }() + if !TPadEnable { + m.touchPad.SetTouchpadEnable(0, true) + } case KEY_TOUCHPAD_OFF: - go func() { - if m.touchPad == nil { - err = errors.New("m.TouchPad is nil") - } else { - err = m.touchPad.SetTouchpadEnable(0, false) - } - - if err != nil { - logger.Warning("Set TouchPad state err : ", err) - err = os.WriteFile(touchpadSwitchFile, []byte("disable"), 0644) - if err != nil { - logger.Warning("write /proc/uos/touchpad_switch err : ", err) - } - } - }() + if TPadEnable { + m.touchPad.SetTouchpadEnable(0, false) + } } } }