#!/usr/bin/env ruby
# encoding: UTF-8

require 'json'

def run(cmd)
  if cmd.is_a?(Array)
    warn cmd.map{|s| s =~ /\s/ ? s.inspect : s}.join(' ')
    system(*cmd) || raise
  else
    warn cmd
    system(cmd) || raise
  end
end

run('kldunload uhid') if system('kldstat -q -n uhid')

run('kldload hgame ')    if !system('kldstat -q -n hgame')
run('kldload hidraw')    if !system('kldstat -q -n hidraw')
run('kldload ps4dshock') if !system('kldstat -q -n ps4dshock')
run('kldload xb360gp')   if !system('kldstat -q -n xb360gp')

run('sysctl hw.usb.usbhid.enable=1')

hidraw_devices = {}
for line in `sysctl dev.hidraw`.lines
  if line =~ /^dev.hidraw.(\d+).(%desc|%driver|%location|%parent|%pnpinfo): (.*)$/
    idx = $1; key = $2; val = $3
    hidraw_devices[idx] ||= {}
    if key == '%pnpinfo'
      hidraw_devices[idx][key] = val.strip.split(' ').map{|kv| kv.split('=')}.to_h
    else
      hidraw_devices[idx][key] = val
    end
  end
end

event_devices = {}
for line in `sysctl kern.evdev.input`.lines
  if line =~ /^kern.evdev.input.(\d+).(id|name|phys|uniq): (.*)$/
    idx = $1; key = $2; val = $3
    event_devices[idx] ||= {}
    if key == 'id'
      event_devices[idx][key] = val.delete_prefix('{ ').delete_suffix(' }').split(', ').map{|kv| kv.split(' = ')}.to_h
    else
      event_devices[idx][key] = val
    end
  end
end

weird_hid_devs = []
for idx, props in hidraw_devices
  weird_hid_devs << idx if !(props['%desc'] =~ /keyboard|mouse|led controller/i)
end

evdev_gamepads = []
for idx, props in event_devices
  evdev_gamepads << idx if props['phys'] =~ /^(hgame|ps4dshock|xb360gp)\d+$/
end

weird_hid_devs.sort!
evdev_gamepads.sort!

mountpoints = JSON.parse(`mount --libxo json`)['mount']['mounted']
for m in mountpoints
  if m['fstype'] == 'devfs'
    for idx in weird_hid_devs
      path = File.join(m['node'], "hidraw#{idx}")
      run(['chgrp', 'operator', path])
      run(['chmod', 'g+rw',     path])
    end
    for idx in evdev_gamepads
      path = File.join(m['node'], "input/event#{idx}")
      run(['chgrp', 'operator', path])
      run(['chmod', 'g+rw',     path])
    end
  end
end
