2017-08-05 79 views
1

我正在編寫媒體跨平臺分佈式媒體播放器,以便在我自己的網絡上使用。從Go程序中讀取媒體密鑰

當前版本有三/四部分:

  1. 一個NAS持有的音頻文件。
  2. 包含有關文件信息的元數據服務器。
  3. 一個HTML/JS客戶端,允許操作元數據服務器和隊列媒體:
  4. 玩家deamon。

我的問題在於第4部分。玩家沒有用戶界面,也不需要用戶界面。它將通過來自客戶端的網絡命令並通過監聽當前主機上的媒體密鑰來控制。

玩家守護進程需要在Windows和Linux上工作,但我似乎無法找出一種方法(任何方式)在任一操作系統上讀取這些密鑰。大部分我知道閱讀鍵盤的方式都不會讀取這些鍵。

+1

你可能想用鍵盤記錄程序開始你的搜索。這是一個可以和linux一起使用的軟件包。類似的邏輯可以用於mac https://github.com/gearmover/keylogger。 Windows不在我的領域是知識,但我相信一些谷歌搜索和堆棧搜索將產生結果。 https://play.golang.org/p/wHJ-8D2nKT – reticentroot

+1

謝謝你,我從來沒有想過檢查鍵盤記錄器......你鏈接的人有足夠的信息,我可以得到Linux的工作,現在我只需要一些Windows的東西.. (有趣的是,鏈接密鑰記錄器爲媒體密鑰產生未知的掃描碼錯誤,但這是因爲它的映射不完整)。 –

+1

是的,可能是映射問題。你可能碰到過這個窗口,但如果不是這裏的窗口。 https://github.com/SaturnsVoid/Windows-KeyLogger – reticentroot

回答

0

在幾位評論員的幫助下,我現在已經明白了。

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]) 
     } 
    } 
} 

和Windows版本:

package main 

import (
    「fmt」 
    「syscall」 
    「time」 
) 

var user32 = syscall.NewLazyDLL(「user32.dll」) 
var procGAKS = user32.NewProc(「GetAsyncKeyState」) 

// Key codes from MSDN 
var keys = [4]uint{ 
    0xb0, // VK_MEDIA_NEXT_TRACK 
    0xb1, // VK_MEDIA_PREV_TRACK 
    0xb2, // VK_MEDIA_STOP 
    0xb3, // VK_MEDIA_PLAY_PAUSE 
} 

var names = [4]string{ 
    「VK_MEDIA_NEXT_TRACK」, 
    「VK_MEDIA_PREV_TRACK」, 
    「VK_MEDIA_STOP」, 
    「VK_MEDIA_PLAY_PAUSE」, 
} 

func main() { 
    fmt.Println(「Running…」) 

    // Since I don’t want to trigger dozens of times for each key I need to track state. 
    // I could check the bits of GAKS’ return value, but that is not reliable. 
    down := [4]bool{false, false, false, false} 

    for { 
     time.Sleep(1 * time.Millisecond) 
     for i, key := range keys { 
      // val is not a simple boolean! 
      // 0 means 「not pressed」 (also certain errors) 
      // If LSB is set the key was just pressed (this may not be reliable) 
      // If MSB is set the key is currently down. 
      val, _, _ := procGAKS.Call(uintptr(key)) 

      // Turn a press into a transition and track key state. 
      goingdown := false 
      if int(val) != 0 && !down[i] { 
       goingdown = true 
       down[i] = true 
      } 
      if int(val) == 0 && down[i] { 
       down[i] = false 
      } 
      if goingdown { 
       // In a real application I would send a message here. 
       fmt.Println(names[i]) 
      } 
     } 
    } 
} 

唯一的 「問題」 是Linux版本必須以root身份運行。對我來說這不是問題。如果以root身份運行是一個問題,我認爲有一種方法涉及到X11 ...