Linux 从Go程序读取媒体密钥

Linux 从Go程序读取媒体密钥,linux,windows,go,Linux,Windows,Go,我正在编写一个媒体跨平台分布式媒体播放器,用于我自己的网络 当前版本有三/四个部分: 保存音频文件的NAS 保存有关文件信息的元数据服务器 一个HTML/JS客户端,允许对元数据服务器进行操作,并为以下内容排队介质: 一个演奏者执事 我的问题在于第四部分。玩家没有UI,也不需要UI。它将通过来自客户端的网络命令并通过监听其当前主机上的媒体密钥来控制 播放器守护进程需要在Windows和Linux上工作,但我似乎无法找到在这两个操作系统上读取这些键的方法(任何方法)。我所知道的大多数阅读键盘的方法

我正在编写一个媒体跨平台分布式媒体播放器,用于我自己的网络

当前版本有三/四个部分:

  • 保存音频文件的NAS
  • 保存有关文件信息的元数据服务器
  • 一个HTML/JS客户端,允许对元数据服务器进行操作,并为以下内容排队介质:
  • 一个演奏者执事
  • 我的问题在于第四部分。玩家没有UI,也不需要UI。它将通过来自客户端的网络命令并通过监听其当前主机上的媒体密钥来控制


    播放器守护进程需要在Windows和Linux上工作,但我似乎无法找到在这两个操作系统上读取这些键的方法(任何方法)。我所知道的大多数阅读键盘的方法根本不会阅读这些键。

    在几位评论者的帮助下,我现在已经把它们都弄明白了

    Linux版本如下:

    package main
    
    import (
        “bytes”
        “encoding/binary”
        “fmt”
        “os”
        “os/exec”
        “syscall”
    )
    
    // parses through the /proc/bus/input/devices file for keyboard devices.
    // Copied from `github.com/gearmover/keylogger` with trivial modification.
    func dumpDevices() ([]string, error) {
        cmd := exec.Command(“/bin/sh”, “-c”, “/bin/grep -E ‘Handlers|EV=’ /proc/bus/input/devices | /bin/grep -B1 ‘EV=120013’ | /bin/grep -Eo ‘event[0-9]+’”)
    
        output, err := cmd.Output()
        if err != nil {
            return nil, err
        }
    
        buf := bytes.NewBuffer(output)
    
        var devices []string
    
        for line, err := buf.ReadString(‘\n’); err == nil; {
            devices = append(devices, “/dev/input/”+line[:len(line)-1])
    
            line, err = buf.ReadString(‘\n’)
        }
    
        return devices, nil
    }
    
    // Using MS names, just because I don’t feel like looking up the Linux versions.
    var keys = map[uint16]string{
        0xa3: “VK_MEDIA_NEXT_TRACK”,
        0xa5: “VK_MEDIA_PREV_TRACK”,
        0xa6: “VK_MEDIA_STOP”,
        0xa4: “VK_MEDIA_PLAY_PAUSE”,
    }
    
    // Most of the code here comes from `github.com/gearmover/keylogger`.
    func main() {
        // drop privileges when executing other programs
        syscall.Setgid(65534)
        syscall.Setuid(65534)
    
        // dump our keyboard devices from /proc/bus/input/devices
        devices, err := dumpDevices()
        if err != nil {
            fmt.Println(err)
        }
        if len(devices) == 0 {
            fmt.Println(“No input devices found”)
            return
        }
    
        // bring back our root privs
        syscall.Setgid(0)
        syscall.Setuid(0)
    
        // Open the first keyboard device.
        input, err := os.OpenFile(devices[0], os.O_RDONLY, 0600)
        if err != nil {
            fmt.Println(err)
            return
        }
        defer input.Close()
    
        // Log media keys
        var buffer = make([]byte, 24)
        for {
            // read the input events as they come in
            n, err := input.Read(buffer)
            if err != nil {
                return
            }
    
            if n != 24 {
                fmt.Println(“Weird Input Event Size: “, n)
                continue
            }
    
            // parse the input event according to the <linux/input.h> header struct
            binary.LittleEndian.Uint64(buffer[0:8]) // Time stamp stuff I could care less about
            binary.LittleEndian.Uint64(buffer[8:16])
            etype := binary.LittleEndian.Uint16(buffer[16:18])        // Event Type. Always 1 for keyboard events
            code := binary.LittleEndian.Uint16(buffer[18:20])         // Key scan code
            value := int32(binary.LittleEndian.Uint32(buffer[20:24])) // press(1), release(0), or repeat(2)
    
            if etype == 1 && value == 1 && keys[code] != “” {
                // In a real application I would send a message here.
                fmt.Println(keys[code])
            }
        }
    }
    

    唯一的“问题”是Linux版本必须以root用户身份运行。对我来说这不是问题。如果以root身份运行是一个问题,我认为有一种方法涉及到X11…

    在几个评论者的帮助下,我现在已经解决了所有问题

    Linux版本如下:

    package main
    
    import (
        “bytes”
        “encoding/binary”
        “fmt”
        “os”
        “os/exec”
        “syscall”
    )
    
    // parses through the /proc/bus/input/devices file for keyboard devices.
    // Copied from `github.com/gearmover/keylogger` with trivial modification.
    func dumpDevices() ([]string, error) {
        cmd := exec.Command(“/bin/sh”, “-c”, “/bin/grep -E ‘Handlers|EV=’ /proc/bus/input/devices | /bin/grep -B1 ‘EV=120013’ | /bin/grep -Eo ‘event[0-9]+’”)
    
        output, err := cmd.Output()
        if err != nil {
            return nil, err
        }
    
        buf := bytes.NewBuffer(output)
    
        var devices []string
    
        for line, err := buf.ReadString(‘\n’); err == nil; {
            devices = append(devices, “/dev/input/”+line[:len(line)-1])
    
            line, err = buf.ReadString(‘\n’)
        }
    
        return devices, nil
    }
    
    // Using MS names, just because I don’t feel like looking up the Linux versions.
    var keys = map[uint16]string{
        0xa3: “VK_MEDIA_NEXT_TRACK”,
        0xa5: “VK_MEDIA_PREV_TRACK”,
        0xa6: “VK_MEDIA_STOP”,
        0xa4: “VK_MEDIA_PLAY_PAUSE”,
    }
    
    // Most of the code here comes from `github.com/gearmover/keylogger`.
    func main() {
        // drop privileges when executing other programs
        syscall.Setgid(65534)
        syscall.Setuid(65534)
    
        // dump our keyboard devices from /proc/bus/input/devices
        devices, err := dumpDevices()
        if err != nil {
            fmt.Println(err)
        }
        if len(devices) == 0 {
            fmt.Println(“No input devices found”)
            return
        }
    
        // bring back our root privs
        syscall.Setgid(0)
        syscall.Setuid(0)
    
        // Open the first keyboard device.
        input, err := os.OpenFile(devices[0], os.O_RDONLY, 0600)
        if err != nil {
            fmt.Println(err)
            return
        }
        defer input.Close()
    
        // Log media keys
        var buffer = make([]byte, 24)
        for {
            // read the input events as they come in
            n, err := input.Read(buffer)
            if err != nil {
                return
            }
    
            if n != 24 {
                fmt.Println(“Weird Input Event Size: “, n)
                continue
            }
    
            // parse the input event according to the <linux/input.h> header struct
            binary.LittleEndian.Uint64(buffer[0:8]) // Time stamp stuff I could care less about
            binary.LittleEndian.Uint64(buffer[8:16])
            etype := binary.LittleEndian.Uint16(buffer[16:18])        // Event Type. Always 1 for keyboard events
            code := binary.LittleEndian.Uint16(buffer[18:20])         // Key scan code
            value := int32(binary.LittleEndian.Uint32(buffer[20:24])) // press(1), release(0), or repeat(2)
    
            if etype == 1 && value == 1 && keys[code] != “” {
                // In a real application I would send a message here.
                fmt.Println(keys[code])
            }
        }
    }
    

    唯一的“问题”是Linux版本必须以root用户身份运行。对我来说这不是问题。如果以root身份运行是一个问题,我认为有一种方法涉及到X11…

    您可能希望从键盘记录器之类的东西开始搜索。这里有一个与linux一起工作的软件包。类似的逻辑可以用于Mac。Windows超出了我的知识范围,但我相信在堆栈上进行一些谷歌搜索将产生结果。谢谢你,我从没想过要检查键盘记录器。。。你链接的那个有足够的信息,我可以让Linux工作,现在我只需要一些Windows的东西。。。(有趣的是,链接的键盘记录器为媒体键生成未知的扫描代码错误,但这只是因为它的映射不完整。)是的,可能是映射问题。你可能已经在windows上看到过这个,但如果不是的话,这里有一个windows。我现在觉得自己像个白痴。我真正了解的一个Windows键盘轮询功能将实现我想要的功能。。。出于某种原因,我认为它更有限。。。哦,好吧。无论如何,如果在我开始工作的时候没有人回答,我会写一个自我回答,感谢一些有用的评论:)你可能想从键盘记录者开始搜索。这里有一个与linux一起工作的软件包。类似的逻辑可以用于Mac。Windows超出了我的知识范围,但我相信在堆栈上进行一些谷歌搜索将产生结果。谢谢你,我从没想过要检查键盘记录器。。。你链接的那个有足够的信息,我可以让Linux工作,现在我只需要一些Windows的东西。。。(有趣的是,链接的键盘记录器为媒体键生成未知的扫描代码错误,但这只是因为它的映射不完整。)是的,可能是映射问题。你可能已经在windows上看到过这个,但如果不是的话,这里有一个windows。我现在觉得自己像个白痴。我真正了解的一个Windows键盘轮询功能将实现我想要的功能。。。出于某种原因,我认为它更有限。。。哦,好吧。无论如何,如果在我完成这项工作时没有人回答,我会写一个自我回答,赞扬一些有帮助的评论者:)