代码拉取完成,页面将自动刷新
同步操作将从 tupelo-shen/mysnapd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2020 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package triggerwatch
import (
"fmt"
"syscall"
"time"
"unsafe"
// TODO:UC20: not packaged, reimplement the minimal things we need?
evdev "github.com/gvalkov/golang-evdev"
"gitee.com/mysnapcore/mysnapd/logger"
)
type keyEvent struct {
Dev triggerDevice
Err error
}
type triggerEventFilter struct {
Key string
}
var (
strToKey = map[string]int{
"KEY_ESC": evdev.KEY_ESC,
"KEY_1": evdev.KEY_1,
"KEY_2": evdev.KEY_2,
"KEY_3": evdev.KEY_3,
"KEY_4": evdev.KEY_4,
"KEY_5": evdev.KEY_5,
"KEY_6": evdev.KEY_6,
"KEY_7": evdev.KEY_7,
"KEY_8": evdev.KEY_8,
"KEY_9": evdev.KEY_9,
"KEY_0": evdev.KEY_0,
}
evKeyCapability = evdev.CapabilityType{Type: evdev.EV_KEY, Name: "EV_KEY"}
// hold time needed to trigger the event
holdToTrigger = 2 * time.Second
)
func init() {
trigger = &evdevInput{}
}
type evdevKeyboardInputDevice struct {
keyCode uint16
dev *evdev.InputDevice
}
func (e *evdevKeyboardInputDevice) probeKeyState() (bool, error) {
// XXX: evdev defines EVIOCGKEY using MAX_NAME_SIZE which is larger than
// what is needed to store the key bitmap with KEY_MAX bits, but we need
// to play along since the value is already encoded
keyBitmap := new([evdev.MAX_NAME_SIZE]byte)
// obtain the large bitmap with all key states
// https://elixir.bootlin.com/linux/v5.5.5/source/drivers/input/evdev.c#L1163
_, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, e.dev.File.Fd(), uintptr(evdev.EVIOCGKEY), uintptr(unsafe.Pointer(keyBitmap)))
if err != 0 {
return false, err
}
byteIdx := e.keyCode / 8
keyMask := byte(1 << (e.keyCode % 8))
isDown := keyBitmap[byteIdx]&keyMask != 0
return isDown, nil
}
func (e *evdevKeyboardInputDevice) WaitForTrigger(ch chan keyEvent) {
logger.Noticef("%s: starting wait, hold %s to trigger", e, holdToTrigger)
// XXX: do not mess with setting the key repeat rate, as it's cumbersome
// and golang-evdev SetRepeatRate() parameter order is actually reversed
// wrt. what the kernel does. The evdev interprets EVIOCSREP arguments
// as (delay, repeat)
// https://elixir.bootlin.com/linux/latest/source/drivers/input/evdev.c#L1072
// but the wrapper is passing is passing (repeat, delay)
// https://github.com/gvalkov/golang-evdev/blob/287e62b94bcb850ab42e711bd74b2875da83af2c/device.go#L226-L230
keyDown, err := e.probeKeyState()
if err != nil {
ch <- keyEvent{Err: fmt.Errorf("cannot obtain initial key state: %v", err), Dev: e}
}
if keyDown {
// looks like the key is pressed initially, we don't know when
// that happened, but pretend it happened just now
logger.Noticef("%s: key is already down", e)
}
type evdevEvent struct {
kev *evdev.KeyEvent
err error
}
// buffer large enough to collect some events
evChan := make(chan evdevEvent, 10)
monitorKey := func() {
for {
ies, err := e.dev.Read()
if err != nil {
evChan <- evdevEvent{err: err}
break
}
for _, ie := range ies {
if ie.Type != evdev.EV_KEY || ie.Code != e.keyCode {
continue
}
kev := evdev.NewKeyEvent(&ie)
evChan <- evdevEvent{kev: kev}
}
}
close(evChan)
}
go monitorKey()
holdTimer := time.NewTimer(holdToTrigger)
// no sense to keep it running later either
defer holdTimer.Stop()
if !keyDown {
// key isn't held yet, stop the timer
holdTimer.Stop()
}
// invariant: tholdTimer is running iff keyDown is true, otherwise is stopped
Loop:
for {
select {
case ev := <-evChan:
if ev.err != nil {
holdTimer.Stop()
ch <- keyEvent{Err: ev.err, Dev: e}
break Loop
}
kev := ev.kev
switch kev.State {
case evdev.KeyDown:
if keyDown {
// unexpected, but possible if we missed
// a key up event right after checking
// the initial keyboard state when the
// key was still down
if !holdTimer.Stop() {
// drain the channel before the
// timer gets reset
<-holdTimer.C
}
}
keyDown = true
// timer is stopped at this point
holdTimer.Reset(holdToTrigger)
logger.Noticef("%s: trigger key down", e)
case evdev.KeyHold:
if !keyDown {
keyDown = true
// timer is not running yet at this point
holdTimer.Reset(holdToTrigger)
logger.Noticef("%s: unexpected hold without down", e)
}
case evdev.KeyUp:
// no need to drain the channel, if it expired,
// we'll handle it in next iteration
holdTimer.Stop()
keyDown = false
logger.Noticef("%s: trigger key up", e)
}
case <-holdTimer.C:
logger.Noticef("%s: hold complete", e)
ch <- keyEvent{Dev: e}
break Loop
}
}
}
func (e *evdevKeyboardInputDevice) String() string {
return fmt.Sprintf("%s: %s", e.dev.Phys, e.dev.Name)
}
func (e *evdevKeyboardInputDevice) Close() {
e.dev.File.Close()
}
type evdevInput struct{}
func getCapabilityCode(Key string) (evdev.CapabilityCode, error) {
keyCode, ok := strToKey[Key]
if !ok {
return evdev.CapabilityCode{}, fmt.Errorf("cannot find a key matching the filter %q", Key)
}
return evdev.CapabilityCode{Code: keyCode, Name: Key}, nil
}
func matchDevice(cap evdev.CapabilityCode, dev *evdev.InputDevice) triggerDevice {
for _, cc := range dev.Capabilities[evKeyCapability] {
if cc == cap {
return &evdevKeyboardInputDevice{
dev: dev,
keyCode: uint16(cap.Code),
}
}
}
return nil
}
func (e *evdevInput) Open(filter triggerEventFilter, node string) (triggerDevice, error) {
evdevDevice, err := evdev.Open(node)
if err != nil {
return nil, err
}
cap, err := getCapabilityCode(filter.Key)
if err != nil {
return nil, err
}
return matchDevice(cap, evdevDevice), nil
}
func (e *evdevInput) FindMatchingDevices(filter triggerEventFilter) ([]triggerDevice, error) {
devices, err := evdev.ListInputDevices()
if err != nil {
return nil, fmt.Errorf("cannot list input devices: %v", err)
}
// NOTE: this supports so far only key input devices
cap, err := getCapabilityCode(filter.Key)
if err != nil {
return nil, err
}
// collect all input devices that can emit the trigger key
var devs []triggerDevice
for _, dev := range devices {
idev := matchDevice(cap, dev)
if idev != nil {
devs = append(devs, idev)
} else {
defer dev.File.Close()
}
}
return devs, nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。