hidapi 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +12 -0
 - data/Gemfile +4 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +103 -0
 - data/Rakefile +11 -0
 - data/bin/console +17 -0
 - data/bin/setup +8 -0
 - data/hidapi.gemspec +27 -0
 - data/lib/hidapi.rb +92 -0
 - data/lib/hidapi/device.rb +634 -0
 - data/lib/hidapi/engine.rb +151 -0
 - data/lib/hidapi/errors.rb +18 -0
 - data/lib/hidapi/language.rb +221 -0
 - data/lib/hidapi/numeric_extensions.rb +10 -0
 - data/lib/hidapi/setup_task_helper.rb +240 -0
 - data/lib/hidapi/version.rb +3 -0
 - data/tmp/.keep +0 -0
 - metadata +117 -0
 
| 
         @@ -0,0 +1,151 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            module HIDAPI
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              ##
         
     | 
| 
      
 5 
     | 
    
         
            +
              # A wrapper around the USB context that makes it easy to locate HID devices.
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Engine
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                ##
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Contains the class code for HID devices from LIBUSB.
         
     | 
| 
      
 10 
     | 
    
         
            +
                HID_CLASS = LIBUSB::CLASS_HID
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                ##
         
     | 
| 
      
 13 
     | 
    
         
            +
                # Creates a new engine.
         
     | 
| 
      
 14 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @context = LIBUSB::Context.new
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                ##
         
     | 
| 
      
 20 
     | 
    
         
            +
                # Enumerates the HID devices matching the vendor and product IDs.
         
     | 
| 
      
 21 
     | 
    
         
            +
                #
         
     | 
| 
      
 22 
     | 
    
         
            +
                # Both vendor_id and product_id are optional.  They will act as a wild card if set to 0 (the default).
         
     | 
| 
      
 23 
     | 
    
         
            +
                def enumerate(vendor_id = 0, product_id = 0, options = {})
         
     | 
| 
      
 24 
     | 
    
         
            +
                  raise HIDAPI::HidApiError, 'not initialized' unless @context
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  if options.is_a?(String) || options.is_a?(Symbol)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    options = { as: options }
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  unless options.nil? || options.is_a?(Hash)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    raise ArgumentError, 'options hash is invalid'
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  klass = (options || {}).delete(:as) || 'HIDAPI::Device'
         
     | 
| 
      
 35 
     | 
    
         
            +
                  klass = Object.const_get(klass) unless klass == :no_mapping
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  filters = { bClass: HID_CLASS }
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  unless vendor_id.nil? || vendor_id.to_i == 0
         
     | 
| 
      
 40 
     | 
    
         
            +
                    filters[:idVendor] = vendor_id.to_i
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  unless product_id.nil? || product_id.to_i == 0
         
     | 
| 
      
 43 
     | 
    
         
            +
                    filters[:idProduct] = product_id.to_i
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  list = @context.devices(filters)
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  if klass != :no_mapping
         
     | 
| 
      
 49 
     | 
    
         
            +
                    list.to_a.map{ |dev| klass.new(dev) }
         
     | 
| 
      
 50 
     | 
    
         
            +
                  else
         
     | 
| 
      
 51 
     | 
    
         
            +
                    list.to_a
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                ##
         
     | 
| 
      
 56 
     | 
    
         
            +
                # Gets the first device with the specified vendor_id, product_id, and optionally serial_number.
         
     | 
| 
      
 57 
     | 
    
         
            +
                def get_device(vendor_id, product_id, serial_number = nil, options = {})
         
     | 
| 
      
 58 
     | 
    
         
            +
                  raise ArgumentError, 'vendor_id must be provided' if vendor_id.to_i == 0
         
     | 
| 
      
 59 
     | 
    
         
            +
                  raise ArgumentError, 'product_id must be provided' if product_id.to_i == 0
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  klass = (options || {}).delete(:as) || 'HIDAPI::Device'
         
     | 
| 
      
 62 
     | 
    
         
            +
                  klass = Object.const_get(klass) unless klass == :no_mapping
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  list = enumerate(vendor_id, product_id, as: :no_mapping)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  return nil unless list && list.count > 0
         
     | 
| 
      
 66 
     | 
    
         
            +
                  if serial_number.to_s == ''
         
     | 
| 
      
 67 
     | 
    
         
            +
                    if klass != :no_mapping
         
     | 
| 
      
 68 
     | 
    
         
            +
                      return klass.new(list.first)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    else
         
     | 
| 
      
 70 
     | 
    
         
            +
                      return list.first
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  list.each do |dev|
         
     | 
| 
      
 74 
     | 
    
         
            +
                    if dev.serial_number == serial_number
         
     | 
| 
      
 75 
     | 
    
         
            +
                      if klass != :no_mapping
         
     | 
| 
      
 76 
     | 
    
         
            +
                        return klass.new(dev)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      else
         
     | 
| 
      
 78 
     | 
    
         
            +
                        return dev
         
     | 
| 
      
 79 
     | 
    
         
            +
                      end
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                ##
         
     | 
| 
      
 86 
     | 
    
         
            +
                # Opens the first device with the specified vendor_id, product_id, and optionally serial_number.
         
     | 
| 
      
 87 
     | 
    
         
            +
                def open(vendor_id, product_id, serial_number = nil)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  dev = get_device(vendor_id, product_id, serial_number)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  dev.open if dev
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                ##
         
     | 
| 
      
 93 
     | 
    
         
            +
                # Gets the device with the specified path.
         
     | 
| 
      
 94 
     | 
    
         
            +
                def get_device_by_path(path, options = {})
         
     | 
| 
      
 95 
     | 
    
         
            +
                  klass = (options || {}).delete(:as) || 'HIDAPI::Device'
         
     | 
| 
      
 96 
     | 
    
         
            +
                  klass = Object.const_get(klass) unless klass == :no_mapping
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  enumerate(as: :no_mapping).each do |usb_dev|
         
     | 
| 
      
 99 
     | 
    
         
            +
                    usb_dev.settings.each do |intf_desc|
         
     | 
| 
      
 100 
     | 
    
         
            +
                      if intf_desc.bInterfaceClass == HID_CLASS
         
     | 
| 
      
 101 
     | 
    
         
            +
                        dev_path = HIDAPI::make_path(usb_dev, intf_desc.bInterfaceNumber)
         
     | 
| 
      
 102 
     | 
    
         
            +
                        if dev_path == path
         
     | 
| 
      
 103 
     | 
    
         
            +
                          if klass != :no_mapping
         
     | 
| 
      
 104 
     | 
    
         
            +
                            return klass.new(usb_dev, intf_desc.bInterfaceNumber)
         
     | 
| 
      
 105 
     | 
    
         
            +
                          else
         
     | 
| 
      
 106 
     | 
    
         
            +
                            return usb_dev
         
     | 
| 
      
 107 
     | 
    
         
            +
                          end
         
     | 
| 
      
 108 
     | 
    
         
            +
                        end
         
     | 
| 
      
 109 
     | 
    
         
            +
                      end
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                ##
         
     | 
| 
      
 115 
     | 
    
         
            +
                # Opens the device with the specified path.
         
     | 
| 
      
 116 
     | 
    
         
            +
                def open_path(path)
         
     | 
| 
      
 117 
     | 
    
         
            +
                  dev = get_device_by_path(path)
         
     | 
| 
      
 118 
     | 
    
         
            +
                  dev.open if dev
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                ##
         
     | 
| 
      
 122 
     | 
    
         
            +
                # Gets the USB code for the current locale.
         
     | 
| 
      
 123 
     | 
    
         
            +
                def usb_code_for_current_locale
         
     | 
| 
      
 124 
     | 
    
         
            +
                  @usb_code_for_current_locale ||=
         
     | 
| 
      
 125 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 126 
     | 
    
         
            +
                        locale = I18n.locale
         
     | 
| 
      
 127 
     | 
    
         
            +
                        if locale
         
     | 
| 
      
 128 
     | 
    
         
            +
                          locale = locale.to_s.partition('.')[0]  # remove encoding
         
     | 
| 
      
 129 
     | 
    
         
            +
                          result = HIDAPI::Language.get_by_code(locale)
         
     | 
| 
      
 130 
     | 
    
         
            +
                          unless result
         
     | 
| 
      
 131 
     | 
    
         
            +
                            locale = locale.partition('_')[0]     # chop off extra specification
         
     | 
| 
      
 132 
     | 
    
         
            +
                            result = HIDAPI::Language.get_by_code(locale)
         
     | 
| 
      
 133 
     | 
    
         
            +
                          end
         
     | 
| 
      
 134 
     | 
    
         
            +
                          result ? result[:usb_code] : 0
         
     | 
| 
      
 135 
     | 
    
         
            +
                        else
         
     | 
| 
      
 136 
     | 
    
         
            +
                          0
         
     | 
| 
      
 137 
     | 
    
         
            +
                        end
         
     | 
| 
      
 138 
     | 
    
         
            +
                      end
         
     | 
| 
      
 139 
     | 
    
         
            +
                end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                def inspect   # :nodoc:
         
     | 
| 
      
 143 
     | 
    
         
            +
                  "#<#{self.class.name}:#{self.object_id.to_hex(16)} context=0x#{@context.object_id.to_hex(16)}>"
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                def to_s      # :nodoc:
         
     | 
| 
      
 147 
     | 
    
         
            +
                  inspect
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
              end
         
     | 
| 
      
 151 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module HIDAPI
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              ##
         
     | 
| 
      
 4 
     | 
    
         
            +
              # A general error from the HIDAPI library.
         
     | 
| 
      
 5 
     | 
    
         
            +
              HidApiError = Class.new(StandardError)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              ##
         
     | 
| 
      
 8 
     | 
    
         
            +
              # The device supplied was invalid for the HIDAPI::Device class.
         
     | 
| 
      
 9 
     | 
    
         
            +
              InvalidDevice = Class.new(HidApiError)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              ##
         
     | 
| 
      
 12 
     | 
    
         
            +
              # Failed to open a device.
         
     | 
| 
      
 13 
     | 
    
         
            +
              DeviceOpenFailed = Class.new(HidApiError)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              ##
         
     | 
| 
      
 16 
     | 
    
         
            +
              # An open device is required for the method called.
         
     | 
| 
      
 17 
     | 
    
         
            +
              DeviceNotOpen = Class.new(HidApiError)
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,221 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module HIDAPI
         
     | 
| 
      
 2 
     | 
    
         
            +
              ##
         
     | 
| 
      
 3 
     | 
    
         
            +
              # List of all known USB languages.
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Language
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                KNOWN = {
         
     | 
| 
      
 7 
     | 
    
         
            +
                    AFRIKAANS:                      {name: "Afrikaans", code: "af", usb_code: 0x0436},
         
     | 
| 
      
 8 
     | 
    
         
            +
                    ALBANIAN:                       {name: "Albanian", code: "sq", usb_code: 0x041c},
         
     | 
| 
      
 9 
     | 
    
         
            +
                    ARABIC___UNITED_ARAB_EMIRATES:  {name: "Arabic - United Arab Emirates", code: "ar_ae", usb_code: 0x3801},
         
     | 
| 
      
 10 
     | 
    
         
            +
                    ARABIC___BAHRAIN:               {name: "Arabic - Bahrain", code: "ar_bh", usb_code: 0x3c01},
         
     | 
| 
      
 11 
     | 
    
         
            +
                    ARABIC___ALGERIA:               {name: "Arabic - Algeria", code: "ar_dz", usb_code: 0x1401},
         
     | 
| 
      
 12 
     | 
    
         
            +
                    ARABIC___EGYPT:                 {name: "Arabic - Egypt", code: "ar_eg", usb_code: 0x0c01},
         
     | 
| 
      
 13 
     | 
    
         
            +
                    ARABIC___IRAQ:                  {name: "Arabic - Iraq", code: "ar_iq", usb_code: 0x0801},
         
     | 
| 
      
 14 
     | 
    
         
            +
                    ARABIC___JORDAN:                {name: "Arabic - Jordan", code: "ar_jo", usb_code: 0x2c01},
         
     | 
| 
      
 15 
     | 
    
         
            +
                    ARABIC___KUWAIT:                {name: "Arabic - Kuwait", code: "ar_kw", usb_code: 0x3401},
         
     | 
| 
      
 16 
     | 
    
         
            +
                    ARABIC___LEBANON:               {name: "Arabic - Lebanon", code: "ar_lb", usb_code: 0x3001},
         
     | 
| 
      
 17 
     | 
    
         
            +
                    ARABIC___LIBYA:                 {name: "Arabic - Libya", code: "ar_ly", usb_code: 0x1001},
         
     | 
| 
      
 18 
     | 
    
         
            +
                    ARABIC___MOROCCO:               {name: "Arabic - Morocco", code: "ar_ma", usb_code: 0x1801},
         
     | 
| 
      
 19 
     | 
    
         
            +
                    ARABIC___OMAN:                  {name: "Arabic - Oman", code: "ar_om", usb_code: 0x2001},
         
     | 
| 
      
 20 
     | 
    
         
            +
                    ARABIC___QATAR:                 {name: "Arabic - Qatar", code: "ar_qa", usb_code: 0x4001},
         
     | 
| 
      
 21 
     | 
    
         
            +
                    ARABIC___SAUDI_ARABIA:          {name: "Arabic - Saudi Arabia", code: "ar_sa", usb_code: 0x0401},
         
     | 
| 
      
 22 
     | 
    
         
            +
                    ARABIC___SYRIA:                 {name: "Arabic - Syria", code: "ar_sy", usb_code: 0x2801},
         
     | 
| 
      
 23 
     | 
    
         
            +
                    ARABIC___TUNISIA:               {name: "Arabic - Tunisia", code: "ar_tn", usb_code: 0x1c01},
         
     | 
| 
      
 24 
     | 
    
         
            +
                    ARABIC___YEMEN:                 {name: "Arabic - Yemen", code: "ar_ye", usb_code: 0x2401},
         
     | 
| 
      
 25 
     | 
    
         
            +
                    ARMENIAN:                       {name: "Armenian", code: "hy", usb_code: 0x042b},
         
     | 
| 
      
 26 
     | 
    
         
            +
                    AZERI___LATIN:                  {name: "Azeri - Latin", code: "az_az", usb_code: 0x042c},
         
     | 
| 
      
 27 
     | 
    
         
            +
                    AZERI___CYRILLIC:               {name: "Azeri - Cyrillic", code: "az_az", usb_code: 0x082c},
         
     | 
| 
      
 28 
     | 
    
         
            +
                    BASQUE:                         {name: "Basque", code: "eu", usb_code: 0x042d},
         
     | 
| 
      
 29 
     | 
    
         
            +
                    BELARUSIAN:                     {name: "Belarusian", code: "be", usb_code: 0x0423},
         
     | 
| 
      
 30 
     | 
    
         
            +
                    BULGARIAN:                      {name: "Bulgarian", code: "bg", usb_code: 0x0402},
         
     | 
| 
      
 31 
     | 
    
         
            +
                    CATALAN:                        {name: "Catalan", code: "ca", usb_code: 0x0403},
         
     | 
| 
      
 32 
     | 
    
         
            +
                    CHINESE___CHINA:                {name: "Chinese - China", code: "zh_cn", usb_code: 0x0804},
         
     | 
| 
      
 33 
     | 
    
         
            +
                    CHINESE___HONG_KONG_SAR:        {name: "Chinese - Hong Kong SAR", code: "zh_hk", usb_code: 0x0c04},
         
     | 
| 
      
 34 
     | 
    
         
            +
                    CHINESE___MACAU_SAR:            {name: "Chinese - Macau SAR", code: "zh_mo", usb_code: 0x1404},
         
     | 
| 
      
 35 
     | 
    
         
            +
                    CHINESE___SINGAPORE:            {name: "Chinese - Singapore", code: "zh_sg", usb_code: 0x1004},
         
     | 
| 
      
 36 
     | 
    
         
            +
                    CHINESE___TAIWAN:               {name: "Chinese - Taiwan", code: "zh_tw", usb_code: 0x0404},
         
     | 
| 
      
 37 
     | 
    
         
            +
                    CROATIAN:                       {name: "Croatian", code: "hr", usb_code: 0x041a},
         
     | 
| 
      
 38 
     | 
    
         
            +
                    CZECH:                          {name: "Czech", code: "cs", usb_code: 0x0405},
         
     | 
| 
      
 39 
     | 
    
         
            +
                    DANISH:                         {name: "Danish", code: "da", usb_code: 0x0406},
         
     | 
| 
      
 40 
     | 
    
         
            +
                    DUTCH___NETHERLANDS:            {name: "Dutch - Netherlands", code: "nl_nl", usb_code: 0x0413},
         
     | 
| 
      
 41 
     | 
    
         
            +
                    DUTCH___BELGIUM:                {name: "Dutch - Belgium", code: "nl_be", usb_code: 0x0813},
         
     | 
| 
      
 42 
     | 
    
         
            +
                    ENGLISH___AUSTRALIA:            {name: "English - Australia", code: "en_au", usb_code: 0x0c09},
         
     | 
| 
      
 43 
     | 
    
         
            +
                    ENGLISH___BELIZE:               {name: "English - Belize", code: "en_bz", usb_code: 0x2809},
         
     | 
| 
      
 44 
     | 
    
         
            +
                    ENGLISH___CANADA:               {name: "English - Canada", code: "en_ca", usb_code: 0x1009},
         
     | 
| 
      
 45 
     | 
    
         
            +
                    ENGLISH___CARIBBEAN:            {name: "English - Caribbean", code: "en_cb", usb_code: 0x2409},
         
     | 
| 
      
 46 
     | 
    
         
            +
                    ENGLISH___IRELAND:              {name: "English - Ireland", code: "en_ie", usb_code: 0x1809},
         
     | 
| 
      
 47 
     | 
    
         
            +
                    ENGLISH___JAMAICA:              {name: "English - Jamaica", code: "en_jm", usb_code: 0x2009},
         
     | 
| 
      
 48 
     | 
    
         
            +
                    ENGLISH___NEW_ZEALAND:          {name: "English - New Zealand", code: "en_nz", usb_code: 0x1409},
         
     | 
| 
      
 49 
     | 
    
         
            +
                    ENGLISH___PHILLIPPINES:         {name: "English - Phillippines", code: "en_ph", usb_code: 0x3409},
         
     | 
| 
      
 50 
     | 
    
         
            +
                    ENGLISH___SOUTHERN_AFRICA:      {name: "English - Southern Africa", code: "en_za", usb_code: 0x1c09},
         
     | 
| 
      
 51 
     | 
    
         
            +
                    ENGLISH___TRINIDAD:             {name: "English - Trinidad", code: "en_tt", usb_code: 0x2c09},
         
     | 
| 
      
 52 
     | 
    
         
            +
                    ENGLISH___GREAT_BRITAIN:        {name: "English - Great Britain", code: "en_gb", usb_code: 0x0809},
         
     | 
| 
      
 53 
     | 
    
         
            +
                    ENGLISH___UNITED_STATES:        {name: "English - United States", code: "en_us", usb_code: 0x0409},
         
     | 
| 
      
 54 
     | 
    
         
            +
                    ESTONIAN:                       {name: "Estonian", code: "et", usb_code: 0x0425},
         
     | 
| 
      
 55 
     | 
    
         
            +
                    FARSI:                          {name: "Farsi", code: "fa", usb_code: 0x0429},
         
     | 
| 
      
 56 
     | 
    
         
            +
                    FINNISH:                        {name: "Finnish", code: "fi", usb_code: 0x040b},
         
     | 
| 
      
 57 
     | 
    
         
            +
                    FAROESE:                        {name: "Faroese", code: "fo", usb_code: 0x0438},
         
     | 
| 
      
 58 
     | 
    
         
            +
                    FRENCH___FRANCE:                {name: "French - France", code: "fr_fr", usb_code: 0x040c},
         
     | 
| 
      
 59 
     | 
    
         
            +
                    FRENCH___BELGIUM:               {name: "French - Belgium", code: "fr_be", usb_code: 0x080c},
         
     | 
| 
      
 60 
     | 
    
         
            +
                    FRENCH___CANADA:                {name: "French - Canada", code: "fr_ca", usb_code: 0x0c0c},
         
     | 
| 
      
 61 
     | 
    
         
            +
                    FRENCH___LUXEMBOURG:            {name: "French - Luxembourg", code: "fr_lu", usb_code: 0x140c},
         
     | 
| 
      
 62 
     | 
    
         
            +
                    FRENCH___SWITZERLAND:           {name: "French - Switzerland", code: "fr_ch", usb_code: 0x100c},
         
     | 
| 
      
 63 
     | 
    
         
            +
                    GAELIC___IRELAND:               {name: "Gaelic - Ireland", code: "gd_ie", usb_code: 0x083c},
         
     | 
| 
      
 64 
     | 
    
         
            +
                    GAELIC___SCOTLAND:              {name: "Gaelic - Scotland", code: "gd", usb_code: 0x043c},
         
     | 
| 
      
 65 
     | 
    
         
            +
                    GERMAN___GERMANY:               {name: "German - Germany", code: "de_de", usb_code: 0x0407},
         
     | 
| 
      
 66 
     | 
    
         
            +
                    GERMAN___AUSTRIA:               {name: "German - Austria", code: "de_at", usb_code: 0x0c07},
         
     | 
| 
      
 67 
     | 
    
         
            +
                    GERMAN___LIECHTENSTEIN:         {name: "German - Liechtenstein", code: "de_li", usb_code: 0x1407},
         
     | 
| 
      
 68 
     | 
    
         
            +
                    GERMAN___LUXEMBOURG:            {name: "German - Luxembourg", code: "de_lu", usb_code: 0x1007},
         
     | 
| 
      
 69 
     | 
    
         
            +
                    GERMAN___SWITZERLAND:           {name: "German - Switzerland", code: "de_ch", usb_code: 0x0807},
         
     | 
| 
      
 70 
     | 
    
         
            +
                    GREEK:                          {name: "Greek", code: "el", usb_code: 0x0408},
         
     | 
| 
      
 71 
     | 
    
         
            +
                    HEBREW:                         {name: "Hebrew", code: "he", usb_code: 0x040d},
         
     | 
| 
      
 72 
     | 
    
         
            +
                    HINDI:                          {name: "Hindi", code: "hi", usb_code: 0x0439},
         
     | 
| 
      
 73 
     | 
    
         
            +
                    HUNGARIAN:                      {name: "Hungarian", code: "hu", usb_code: 0x040e},
         
     | 
| 
      
 74 
     | 
    
         
            +
                    ICELANDIC:                      {name: "Icelandic", code: "is", usb_code: 0x040f},
         
     | 
| 
      
 75 
     | 
    
         
            +
                    INDONESIAN:                     {name: "Indonesian", code: "id", usb_code: 0x0421},
         
     | 
| 
      
 76 
     | 
    
         
            +
                    ITALIAN___ITALY:                {name: "Italian - Italy", code: "it_it", usb_code: 0x0410},
         
     | 
| 
      
 77 
     | 
    
         
            +
                    ITALIAN___SWITZERLAND:          {name: "Italian - Switzerland", code: "it_ch", usb_code: 0x0810},
         
     | 
| 
      
 78 
     | 
    
         
            +
                    JAPANESE:                       {name: "Japanese", code: "ja", usb_code: 0x0411},
         
     | 
| 
      
 79 
     | 
    
         
            +
                    KOREAN:                         {name: "Korean", code: "ko", usb_code: 0x0412},
         
     | 
| 
      
 80 
     | 
    
         
            +
                    LATVIAN:                        {name: "Latvian", code: "lv", usb_code: 0x0426},
         
     | 
| 
      
 81 
     | 
    
         
            +
                    LITHUANIAN:                     {name: "Lithuanian", code: "lt", usb_code: 0x0427},
         
     | 
| 
      
 82 
     | 
    
         
            +
                    F_Y_R_O__MACEDONIA:             {name: "F.Y.R.O. Macedonia", code: "mk", usb_code: 0x042f},
         
     | 
| 
      
 83 
     | 
    
         
            +
                    MALAY___MALAYSIA:               {name: "Malay - Malaysia", code: "ms_my", usb_code: 0x043e},
         
     | 
| 
      
 84 
     | 
    
         
            +
                    MALAY___BRUNEI:                 {name: "Malay – Brunei", code: "ms_bn", usb_code: 0x083e},
         
     | 
| 
      
 85 
     | 
    
         
            +
                    MALTESE:                        {name: "Maltese", code: "mt", usb_code: 0x043a},
         
     | 
| 
      
 86 
     | 
    
         
            +
                    MARATHI:                        {name: "Marathi", code: "mr", usb_code: 0x044e},
         
     | 
| 
      
 87 
     | 
    
         
            +
                    NORWEGIAN___BOKML:              {name: "Norwegian - Bokml", code: "no_no", usb_code: 0x0414},
         
     | 
| 
      
 88 
     | 
    
         
            +
                    NORWEGIAN___NYNORSK:            {name: "Norwegian - Nynorsk", code: "no_no", usb_code: 0x0814},
         
     | 
| 
      
 89 
     | 
    
         
            +
                    POLISH:                         {name: "Polish", code: "pl", usb_code: 0x0415},
         
     | 
| 
      
 90 
     | 
    
         
            +
                    PORTUGUESE___PORTUGAL:          {name: "Portuguese - Portugal", code: "pt_pt", usb_code: 0x0816},
         
     | 
| 
      
 91 
     | 
    
         
            +
                    PORTUGUESE___BRAZIL:            {name: "Portuguese - Brazil", code: "pt_br", usb_code: 0x0416},
         
     | 
| 
      
 92 
     | 
    
         
            +
                    RAETO_ROMANCE:                  {name: "Raeto-Romance", code: "rm", usb_code: 0x0417},
         
     | 
| 
      
 93 
     | 
    
         
            +
                    ROMANIAN___ROMANIA:             {name: "Romanian - Romania", code: "ro", usb_code: 0x0418},
         
     | 
| 
      
 94 
     | 
    
         
            +
                    ROMANIAN___REPUBLIC_OF_MOLDOVA: {name: "Romanian - Republic of Moldova", code: "ro_mo", usb_code: 0x0818},
         
     | 
| 
      
 95 
     | 
    
         
            +
                    RUSSIAN:                        {name: "Russian", code: "ru", usb_code: 0x0419},
         
     | 
| 
      
 96 
     | 
    
         
            +
                    RUSSIAN___REPUBLIC_OF_MOLDOVA:  {name: "Russian - Republic of Moldova", code: "ru_mo", usb_code: 0x0819},
         
     | 
| 
      
 97 
     | 
    
         
            +
                    SANSKRIT:                       {name: "Sanskrit", code: "sa", usb_code: 0x044f},
         
     | 
| 
      
 98 
     | 
    
         
            +
                    SERBIAN___CYRILLIC:             {name: "Serbian - Cyrillic", code: "sr_sp", usb_code: 0x0c1a},
         
     | 
| 
      
 99 
     | 
    
         
            +
                    SERBIAN___LATIN:                {name: "Serbian - Latin", code: "sr_sp", usb_code: 0x081a},
         
     | 
| 
      
 100 
     | 
    
         
            +
                    SETSUANA:                       {name: "Setsuana", code: "tn", usb_code: 0x0432},
         
     | 
| 
      
 101 
     | 
    
         
            +
                    SLOVENIAN:                      {name: "Slovenian", code: "sl", usb_code: 0x0424},
         
     | 
| 
      
 102 
     | 
    
         
            +
                    SLOVAK:                         {name: "Slovak", code: "sk", usb_code: 0x041b},
         
     | 
| 
      
 103 
     | 
    
         
            +
                    SORBIAN:                        {name: "Sorbian", code: "sb", usb_code: 0x042e},
         
     | 
| 
      
 104 
     | 
    
         
            +
                    SPANISH___SPAIN__TRADITIONAL_:  {name: "Spanish - Spain (Traditional)", code: "es_es", usb_code: 0x040a},
         
     | 
| 
      
 105 
     | 
    
         
            +
                    SPANISH___ARGENTINA:            {name: "Spanish - Argentina", code: "es_ar", usb_code: 0x2c0a},
         
     | 
| 
      
 106 
     | 
    
         
            +
                    SPANISH___BOLIVIA:              {name: "Spanish - Bolivia", code: "es_bo", usb_code: 0x400a},
         
     | 
| 
      
 107 
     | 
    
         
            +
                    SPANISH___CHILE:                {name: "Spanish - Chile", code: "es_cl", usb_code: 0x340a},
         
     | 
| 
      
 108 
     | 
    
         
            +
                    SPANISH___COLOMBIA:             {name: "Spanish - Colombia", code: "es_co", usb_code: 0x240a},
         
     | 
| 
      
 109 
     | 
    
         
            +
                    SPANISH___COSTA_RICA:           {name: "Spanish - Costa Rica", code: "es_cr", usb_code: 0x140a},
         
     | 
| 
      
 110 
     | 
    
         
            +
                    SPANISH___DOMINICAN_REPUBLIC:   {name: "Spanish - Dominican Republic", code: "es_do", usb_code: 0x1c0a},
         
     | 
| 
      
 111 
     | 
    
         
            +
                    SPANISH___ECUADOR:              {name: "Spanish - Ecuador", code: "es_ec", usb_code: 0x300a},
         
     | 
| 
      
 112 
     | 
    
         
            +
                    SPANISH___GUATEMALA:            {name: "Spanish - Guatemala", code: "es_gt", usb_code: 0x100a},
         
     | 
| 
      
 113 
     | 
    
         
            +
                    SPANISH___HONDURAS:             {name: "Spanish - Honduras", code: "es_hn", usb_code: 0x480a},
         
     | 
| 
      
 114 
     | 
    
         
            +
                    SPANISH___MEXICO:               {name: "Spanish - Mexico", code: "es_mx", usb_code: 0x080a},
         
     | 
| 
      
 115 
     | 
    
         
            +
                    SPANISH___NICARAGUA:            {name: "Spanish - Nicaragua", code: "es_ni", usb_code: 0x4c0a},
         
     | 
| 
      
 116 
     | 
    
         
            +
                    SPANISH___PANAMA:               {name: "Spanish - Panama", code: "es_pa", usb_code: 0x180a},
         
     | 
| 
      
 117 
     | 
    
         
            +
                    SPANISH___PERU:                 {name: "Spanish - Peru", code: "es_pe", usb_code: 0x280a},
         
     | 
| 
      
 118 
     | 
    
         
            +
                    SPANISH___PUERTO_RICO:          {name: "Spanish - Puerto Rico", code: "es_pr", usb_code: 0x500a},
         
     | 
| 
      
 119 
     | 
    
         
            +
                    SPANISH___PARAGUAY:             {name: "Spanish - Paraguay", code: "es_py", usb_code: 0x3c0a},
         
     | 
| 
      
 120 
     | 
    
         
            +
                    SPANISH___EL_SALVADOR:          {name: "Spanish - El Salvador", code: "es_sv", usb_code: 0x440a},
         
     | 
| 
      
 121 
     | 
    
         
            +
                    SPANISH___URUGUAY:              {name: "Spanish - Uruguay", code: "es_uy", usb_code: 0x380a},
         
     | 
| 
      
 122 
     | 
    
         
            +
                    SPANISH___VENEZUELA:            {name: "Spanish - Venezuela", code: "es_ve", usb_code: 0x200a},
         
     | 
| 
      
 123 
     | 
    
         
            +
                    SOUTHERN_SOTHO:                 {name: "Southern Sotho", code: "st", usb_code: 0x0430},
         
     | 
| 
      
 124 
     | 
    
         
            +
                    SWAHILI:                        {name: "Swahili", code: "sw", usb_code: 0x0441},
         
     | 
| 
      
 125 
     | 
    
         
            +
                    SWEDISH___SWEDEN:               {name: "Swedish - Sweden", code: "sv_se", usb_code: 0x041d},
         
     | 
| 
      
 126 
     | 
    
         
            +
                    SWEDISH___FINLAND:              {name: "Swedish - Finland", code: "sv_fi", usb_code: 0x081d},
         
     | 
| 
      
 127 
     | 
    
         
            +
                    TAMIL:                          {name: "Tamil", code: "ta", usb_code: 0x0449},
         
     | 
| 
      
 128 
     | 
    
         
            +
                    TATAR:                          {name: "Tatar", code: "tt", usb_code: 0x0444},
         
     | 
| 
      
 129 
     | 
    
         
            +
                    THAI:                           {name: "Thai", code: "th", usb_code: 0x041e},
         
     | 
| 
      
 130 
     | 
    
         
            +
                    TURKISH:                        {name: "Turkish", code: "tr", usb_code: 0x041f},
         
     | 
| 
      
 131 
     | 
    
         
            +
                    TSONGA:                         {name: "Tsonga", code: "ts", usb_code: 0x0431},
         
     | 
| 
      
 132 
     | 
    
         
            +
                    UKRAINIAN:                      {name: "Ukrainian", code: "uk", usb_code: 0x0422},
         
     | 
| 
      
 133 
     | 
    
         
            +
                    URDU:                           {name: "Urdu", code: "ur", usb_code: 0x0420},
         
     | 
| 
      
 134 
     | 
    
         
            +
                    UZBEK___CYRILLIC:               {name: "Uzbek - Cyrillic", code: "uz_uz", usb_code: 0x0843},
         
     | 
| 
      
 135 
     | 
    
         
            +
                    UZBEK___LATIN:                  {name: "Uzbek – Latin", code: "uz_uz", usb_code: 0x0443},
         
     | 
| 
      
 136 
     | 
    
         
            +
                    VIETNAMESE:                     {name: "Vietnamese", code: "vi", usb_code: 0x042a},
         
     | 
| 
      
 137 
     | 
    
         
            +
                    XHOSA:                          {name: "Xhosa", code: "xh", usb_code: 0x0434},
         
     | 
| 
      
 138 
     | 
    
         
            +
                    YIDDISH:                        {name: "Yiddish", code: "yi", usb_code: 0x043d},
         
     | 
| 
      
 139 
     | 
    
         
            +
                    ZULU:                           {name: "Zulu", code: "zu", usb_code: 0x0435},
         
     | 
| 
      
 140 
     | 
    
         
            +
                }.freeze.each{|_,data| data.each{|_,val| val.freeze}; data.freeze}    # make the constant contents constant
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                private_constant :KNOWN
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                ##
         
     | 
| 
      
 145 
     | 
    
         
            +
                # Gets a language by key or name.
         
     | 
| 
      
 146 
     | 
    
         
            +
                def self.[](name)
         
     | 
| 
      
 147 
     | 
    
         
            +
                  get_by_name(name)
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                # :nodoc:
         
     | 
| 
      
 151 
     | 
    
         
            +
                def self.[]=(*args)
         
     | 
| 
      
 152 
     | 
    
         
            +
                  raise 'can\'t modify constants'
         
     | 
| 
      
 153 
     | 
    
         
            +
                end
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                ##
         
     | 
| 
      
 157 
     | 
    
         
            +
                # Gets a language by name.
         
     | 
| 
      
 158 
     | 
    
         
            +
                def self.get_by_name(name)
         
     | 
| 
      
 159 
     | 
    
         
            +
                  name_sym = name.to_s.upcase.to_sym
         
     | 
| 
      
 160 
     | 
    
         
            +
                  name = name.to_s.downcase
         
     | 
| 
      
 161 
     | 
    
         
            +
                  if KNOWN.keys.include?(name_sym)
         
     | 
| 
      
 162 
     | 
    
         
            +
                    return KNOWN[name_sym]
         
     | 
| 
      
 163 
     | 
    
         
            +
                  else
         
     | 
| 
      
 164 
     | 
    
         
            +
                    res = KNOWN.find{|k,v| v[:name].downcase == name}
         
     | 
| 
      
 165 
     | 
    
         
            +
                    return res[1] if res && res.length == 2
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 168 
     | 
    
         
            +
                end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                ##
         
     | 
| 
      
 171 
     | 
    
         
            +
                # Gets a language by code.
         
     | 
| 
      
 172 
     | 
    
         
            +
                def self.get_by_code(code)
         
     | 
| 
      
 173 
     | 
    
         
            +
                  code = code.to_s.downcase
         
     | 
| 
      
 174 
     | 
    
         
            +
                  res = KNOWN.find{|k,v| v[:code] == code}
         
     | 
| 
      
 175 
     | 
    
         
            +
                  return res[1] if res && res.length == 2
         
     | 
| 
      
 176 
     | 
    
         
            +
                end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                ##
         
     | 
| 
      
 179 
     | 
    
         
            +
                # Gets a language by USB code.
         
     | 
| 
      
 180 
     | 
    
         
            +
                def self.get_by_usb_code(code)
         
     | 
| 
      
 181 
     | 
    
         
            +
                  code = code.to_i
         
     | 
| 
      
 182 
     | 
    
         
            +
                  res = KNOWN.find{|k,v| v[:usb_code] == code}
         
     | 
| 
      
 183 
     | 
    
         
            +
                  return res[1] if res && res.length == 2
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                ##
         
     | 
| 
      
 187 
     | 
    
         
            +
                # Gets a language.
         
     | 
| 
      
 188 
     | 
    
         
            +
                #
         
     | 
| 
      
 189 
     | 
    
         
            +
                # The input value can be the name, code, or USB code.
         
     | 
| 
      
 190 
     | 
    
         
            +
                def self.get(language)
         
     | 
| 
      
 191 
     | 
    
         
            +
                  if language.is_a?(Numeric)
         
     | 
| 
      
 192 
     | 
    
         
            +
                    get_by_usb_code(language)
         
     | 
| 
      
 193 
     | 
    
         
            +
                  elsif language.is_a?(Symbol) || language.is_a?(String)
         
     | 
| 
      
 194 
     | 
    
         
            +
                    get_by_name(language) || get_by_code(language)
         
     | 
| 
      
 195 
     | 
    
         
            +
                  elsif language.is_a?(Hash)
         
     | 
| 
      
 196 
     | 
    
         
            +
                    if language[:usb_code]
         
     | 
| 
      
 197 
     | 
    
         
            +
                      get_by_usb_code(language[:usb_code])
         
     | 
| 
      
 198 
     | 
    
         
            +
                    elsif language[:code]
         
     | 
| 
      
 199 
     | 
    
         
            +
                      get_by_code(language[:code])
         
     | 
| 
      
 200 
     | 
    
         
            +
                    elsif language[:name]
         
     | 
| 
      
 201 
     | 
    
         
            +
                      get_by_name(language[:name])
         
     | 
| 
      
 202 
     | 
    
         
            +
                    else
         
     | 
| 
      
 203 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 204 
     | 
    
         
            +
                    end
         
     | 
| 
      
 205 
     | 
    
         
            +
                  else
         
     | 
| 
      
 206 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 207 
     | 
    
         
            +
                  end
         
     | 
| 
      
 208 
     | 
    
         
            +
                end
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                # :nodoc:
         
     | 
| 
      
 211 
     | 
    
         
            +
                def self.method_missing(m,*a,&b)
         
     | 
| 
      
 212 
     | 
    
         
            +
                  if KNOWN.respond_to?(m)
         
     | 
| 
      
 213 
     | 
    
         
            +
                    KNOWN.send m, *a, &b
         
     | 
| 
      
 214 
     | 
    
         
            +
                  else
         
     | 
| 
      
 215 
     | 
    
         
            +
                    super m, *a, &b
         
     | 
| 
      
 216 
     | 
    
         
            +
                  end
         
     | 
| 
      
 217 
     | 
    
         
            +
                end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
              end
         
     | 
| 
      
 221 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,240 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'tmpdir'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module HIDAPI
         
     | 
| 
      
 6 
     | 
    
         
            +
              class SetupTaskHelper
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                attr_reader :vendor_id, :product_id, :simple_name, :interface
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(vendor_id, product_id, simple_name, interface)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @vendor_id = vendor_id.to_s.strip.to_i(16)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @product_id = product_id.to_s.strip.to_i(16)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @simple_name = simple_name.to_s.strip.gsub(' ', '_').gsub(/[^A-Za-z0-9_\-]/, '')
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @interface = interface.to_s.strip.to_i
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @temp_dir = Dir.mktmpdir('hidapi_setup')
         
     | 
| 
      
 16 
     | 
    
         
            +
                  ObjectSpace.define_finalizer(self, ->{ FileUtils.rm_rf(@temp_dir) })
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def run
         
     | 
| 
      
 20 
     | 
    
         
            +
                  if valid_options?
         
     | 
| 
      
 21 
     | 
    
         
            +
                    if operating_system == :osx
         
     | 
| 
      
 22 
     | 
    
         
            +
                      run_osx
         
     | 
| 
      
 23 
     | 
    
         
            +
                    elsif operating_system == :linux
         
     | 
| 
      
 24 
     | 
    
         
            +
                      run_linux
         
     | 
| 
      
 25 
     | 
    
         
            +
                    elsif operating_system == :windows
         
     | 
| 
      
 26 
     | 
    
         
            +
                      run_windows
         
     | 
| 
      
 27 
     | 
    
         
            +
                    else
         
     | 
| 
      
 28 
     | 
    
         
            +
                      puts "Your operating system was detected as '#{operating_system}', but I don't have a setup routine for that."
         
     | 
| 
      
 29 
     | 
    
         
            +
                      false
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  else
         
     | 
| 
      
 32 
     | 
    
         
            +
                    usage
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def valid_options?
         
     | 
| 
      
 37 
     | 
    
         
            +
                  vendor_id != 0 && product_id != 0 && simple_name != ''
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def usage()
         
     | 
| 
      
 41 
     | 
    
         
            +
                  puts <<-USAGE
         
     | 
| 
      
 42 
     | 
    
         
            +
            Usage:  bundle exec rake setup_hid_device[vendor_id,product_id,simple_name,interface]
         
     | 
| 
      
 43 
     | 
    
         
            +
            -OR-    #{File.basename(__FILE__)} vendor_id product_id simple_name interface
         
     | 
| 
      
 44 
     | 
    
         
            +
              vendor_id should be the 16-bit identifier assigned to the device vendor in hex format.
         
     | 
| 
      
 45 
     | 
    
         
            +
              product_id should be the 16-bit identifier assigned by the manufacturer in hex format.
         
     | 
| 
      
 46 
     | 
    
         
            +
              simple_name should be a fairly short name for the device.
         
     | 
| 
      
 47 
     | 
    
         
            +
              interface is optional and defaults to 0.
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              ie - bundle exec rake setup_hid_device[04d8,c002,pico-lcd-graphic]
         
     | 
| 
      
 50 
     | 
    
         
            +
              ie - #{File.basename(__FILE__)} 04d8 c002 pico-lcd-graphic
         
     | 
| 
      
 51 
     | 
    
         
            +
            USAGE
         
     | 
| 
      
 52 
     | 
    
         
            +
                  false
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                private
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def operating_system
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @operating_system ||=
         
     | 
| 
      
 59 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                        # unix uses uname, windows uses ver.  failing both, use the OS environment variable (which can be specified by the user).
         
     | 
| 
      
 62 
     | 
    
         
            +
                        kernel_name = `uname -s`.strip.downcase rescue nil
         
     | 
| 
      
 63 
     | 
    
         
            +
                        kernel_name = `ver`.strip.downcase rescue nil unless kernel_name
         
     | 
| 
      
 64 
     | 
    
         
            +
                        kernel_name = ENV['OS'].to_s.strip.downcase rescue '' unless kernel_name
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                        if /darwin/ =~ kernel_name
         
     | 
| 
      
 67 
     | 
    
         
            +
                          :osx
         
     | 
| 
      
 68 
     | 
    
         
            +
                        elsif /win/ =~ kernel_name
         
     | 
| 
      
 69 
     | 
    
         
            +
                          :windows
         
     | 
| 
      
 70 
     | 
    
         
            +
                        elsif /linux/ =~ kernel_name
         
     | 
| 
      
 71 
     | 
    
         
            +
                          :linux
         
     | 
| 
      
 72 
     | 
    
         
            +
                        else
         
     | 
| 
      
 73 
     | 
    
         
            +
                          :unix
         
     | 
| 
      
 74 
     | 
    
         
            +
                        end
         
     | 
| 
      
 75 
     | 
    
         
            +
                      rescue
         
     | 
| 
      
 76 
     | 
    
         
            +
                        :unknown
         
     | 
| 
      
 77 
     | 
    
         
            +
                      end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def run_windows
         
     | 
| 
      
 81 
     | 
    
         
            +
                  puts "Please use the Zadig tool from http://zadig.akeo.ie/ to install a driver for your device.\nThis script unfortunately does not do this for you automatically at this point in time."
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def run_osx
         
     | 
| 
      
 85 
     | 
    
         
            +
                  # OS X needs a codeless kext setup in the /System/Library/Extensions directory.
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  path = @temp_dir
         
     | 
| 
      
 88 
     | 
    
         
            +
                  path += '/' unless path[-1] == '/'
         
     | 
| 
      
 89 
     | 
    
         
            +
                  path += simple_name
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  target = "/System/Library/Extensions/#{simple_name}.kext"
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  if Dir.exist?(target)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    puts 'A kext with the specified name already exists.'
         
     | 
| 
      
 95 
     | 
    
         
            +
                    return false
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  puts 'Building kext...'
         
     | 
| 
      
 99 
     | 
    
         
            +
                  Dir.mkdir path
         
     | 
| 
      
 100 
     | 
    
         
            +
                  Dir.mkdir path + '/Contents'
         
     | 
| 
      
 101 
     | 
    
         
            +
                  Dir.mkdir path + '/Contents/Resources'
         
     | 
| 
      
 102 
     | 
    
         
            +
                  Dir.mkdir path + '/Contents/Resources/English.lproj'
         
     | 
| 
      
 103 
     | 
    
         
            +
                  File.write path + '/Contents/Resources/English.lproj/InfoPlist.strings', "\nCFBundleName = \"VendorSpecificDriver\";\n"
         
     | 
| 
      
 104 
     | 
    
         
            +
                  File.write path + '/Contents/Info.plist', <<-FILE
         
     | 
| 
      
 105 
     | 
    
         
            +
            <?xml version="1.0" encoding="UTF-8"?>
         
     | 
| 
      
 106 
     | 
    
         
            +
            <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
         
     | 
| 
      
 107 
     | 
    
         
            +
            <plist version="1.0">
         
     | 
| 
      
 108 
     | 
    
         
            +
            <dict>
         
     | 
| 
      
 109 
     | 
    
         
            +
            	<key>BuildMachineOSBuild</key>
         
     | 
| 
      
 110 
     | 
    
         
            +
            	<string>11C74</string>
         
     | 
| 
      
 111 
     | 
    
         
            +
            	<key>CFBundleDevelopmentRegion</key>
         
     | 
| 
      
 112 
     | 
    
         
            +
            	<string>English</string>
         
     | 
| 
      
 113 
     | 
    
         
            +
            	<key>CFBundleIdentifier</key>
         
     | 
| 
      
 114 
     | 
    
         
            +
            	<string>idv.barkerest.#{simple_name}</string>
         
     | 
| 
      
 115 
     | 
    
         
            +
            	<key>CFBundleInfoDictionaryVersion</key>
         
     | 
| 
      
 116 
     | 
    
         
            +
            	<string>6.0</string>
         
     | 
| 
      
 117 
     | 
    
         
            +
            	<key>CFBundlePackageType</key>
         
     | 
| 
      
 118 
     | 
    
         
            +
            	<string>KEXT</string>
         
     | 
| 
      
 119 
     | 
    
         
            +
            	<key>CFBundleSignature</key>
         
     | 
| 
      
 120 
     | 
    
         
            +
            	<string>????</string>
         
     | 
| 
      
 121 
     | 
    
         
            +
            	<key>CFBundleVersion</key>
         
     | 
| 
      
 122 
     | 
    
         
            +
            	<string>1.0</string>
         
     | 
| 
      
 123 
     | 
    
         
            +
            	<key>DTCompiler</key>
         
     | 
| 
      
 124 
     | 
    
         
            +
            	<string></string>
         
     | 
| 
      
 125 
     | 
    
         
            +
            	<key>DTPlatformBuild</key>
         
     | 
| 
      
 126 
     | 
    
         
            +
            	<string>4D502</string>
         
     | 
| 
      
 127 
     | 
    
         
            +
            	<key>DTPlatformVersion</key>
         
     | 
| 
      
 128 
     | 
    
         
            +
            	<string>GM</string>
         
     | 
| 
      
 129 
     | 
    
         
            +
            	<key>DTSDKBuild</key>
         
     | 
| 
      
 130 
     | 
    
         
            +
            	<string>11C63</string>
         
     | 
| 
      
 131 
     | 
    
         
            +
            	<key>DTSDKName</key>
         
     | 
| 
      
 132 
     | 
    
         
            +
            	<string>macosx10.7</string>
         
     | 
| 
      
 133 
     | 
    
         
            +
            	<key>DTXcode</key>
         
     | 
| 
      
 134 
     | 
    
         
            +
            	<string>0421</string>
         
     | 
| 
      
 135 
     | 
    
         
            +
            	<key>DTXcodeBuild</key>
         
     | 
| 
      
 136 
     | 
    
         
            +
            	<string>4D502</string>
         
     | 
| 
      
 137 
     | 
    
         
            +
            	<key>OSBundleRequired</key>
         
     | 
| 
      
 138 
     | 
    
         
            +
            	<string>Console</string>
         
     | 
| 
      
 139 
     | 
    
         
            +
            	<key>IOKitPersonalities</key>
         
     | 
| 
      
 140 
     | 
    
         
            +
            	<dict>
         
     | 
| 
      
 141 
     | 
    
         
            +
                <key>#{simple_name}</key>
         
     | 
| 
      
 142 
     | 
    
         
            +
            		<dict>
         
     | 
| 
      
 143 
     | 
    
         
            +
            			<key>CFBundleIdentifier</key>
         
     | 
| 
      
 144 
     | 
    
         
            +
            			<string>com.apple.kpi.iokit</string>
         
     | 
| 
      
 145 
     | 
    
         
            +
            			<key>IOClass</key>
         
     | 
| 
      
 146 
     | 
    
         
            +
            			<string>IOService</string>
         
     | 
| 
      
 147 
     | 
    
         
            +
            			<key>IOProbeScore</key>
         
     | 
| 
      
 148 
     | 
    
         
            +
            			<integer>11000</integer>
         
     | 
| 
      
 149 
     | 
    
         
            +
            			<key>IOProviderClass</key>
         
     | 
| 
      
 150 
     | 
    
         
            +
            			<string>IOUSBInterface</string>
         
     | 
| 
      
 151 
     | 
    
         
            +
            			<key>bConfigurationValue</key>
         
     | 
| 
      
 152 
     | 
    
         
            +
            			<integer>1</integer>
         
     | 
| 
      
 153 
     | 
    
         
            +
            			<key>bInterfaceNumber</key>
         
     | 
| 
      
 154 
     | 
    
         
            +
            			<integer>#{interface}</integer>
         
     | 
| 
      
 155 
     | 
    
         
            +
            			<key>idProduct</key>
         
     | 
| 
      
 156 
     | 
    
         
            +
            			<integer>#{product_id}</integer>
         
     | 
| 
      
 157 
     | 
    
         
            +
            			<key>idVendor</key>
         
     | 
| 
      
 158 
     | 
    
         
            +
            			<integer>#{vendor_id}</integer>
         
     | 
| 
      
 159 
     | 
    
         
            +
            		</dict>
         
     | 
| 
      
 160 
     | 
    
         
            +
            	</dict>
         
     | 
| 
      
 161 
     | 
    
         
            +
            	<key>OSBundleLibraries</key>
         
     | 
| 
      
 162 
     | 
    
         
            +
            	<dict>
         
     | 
| 
      
 163 
     | 
    
         
            +
            		<key>com.apple.iokit.IOUSBFamily</key>
         
     | 
| 
      
 164 
     | 
    
         
            +
            		<string>1.8</string>
         
     | 
| 
      
 165 
     | 
    
         
            +
            		<key>com.apple.kernel.libkern</key>
         
     | 
| 
      
 166 
     | 
    
         
            +
            		<string>6.0</string>
         
     | 
| 
      
 167 
     | 
    
         
            +
            	</dict>
         
     | 
| 
      
 168 
     | 
    
         
            +
            </dict>
         
     | 
| 
      
 169 
     | 
    
         
            +
            </plist>
         
     | 
| 
      
 170 
     | 
    
         
            +
                  FILE
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                  puts 'Installing kext...'
         
     | 
| 
      
 173 
     | 
    
         
            +
                  `sudo cp -r #{path} #{target}`
         
     | 
| 
      
 174 
     | 
    
         
            +
                  `sudo touch /System/Library/Extensions`
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                  FileUtils.rm_rf path
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  puts "The kext has been installed.\nYou may have to unplug/plug the device or restart your computer."
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                  true
         
     | 
| 
      
 181 
     | 
    
         
            +
                end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                def run_linux
         
     | 
| 
      
 184 
     | 
    
         
            +
                  # Linux needs a udev rule file added under /etc/udev/rules.d
         
     | 
| 
      
 185 
     | 
    
         
            +
                  # We'll use '60-hidapi.rules' for our purposes.
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                  target = '/etc/udev/rules.d/60-hidapi.rules'
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                  contents = File.exist?(target) ? File.read(target) : nil
         
     | 
| 
      
 190 
     | 
    
         
            +
                  contents ||= <<-DEF
         
     | 
| 
      
 191 
     | 
    
         
            +
            # udev rules for libusb access created by Ruby 'hidapi' gem.
         
     | 
| 
      
 192 
     | 
    
         
            +
            SUBSYSTEM!="usb", GOTO="hidapi_rules_end"
         
     | 
| 
      
 193 
     | 
    
         
            +
            ACTION!="add", GOTO="hidapi_rules_end"
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
            LABEL="hidapi_rules_end"
         
     | 
| 
      
 196 
     | 
    
         
            +
                  DEF
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                  contents = contents.split("\n").map(&:strip)
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                  # get the position we will be inserting at.
         
     | 
| 
      
 201 
     | 
    
         
            +
                  last_line = contents.index { |item| item == 'LABEL="hidapi_rules_end"' }
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                  contents.each do |line|
         
     | 
| 
      
 204 
     | 
    
         
            +
                    if /^#\s+device:\s+#{simple_name}$/i =~ line
         
     | 
| 
      
 205 
     | 
    
         
            +
                      puts 'A udev rule for the specified device already exists.'
         
     | 
| 
      
 206 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 207 
     | 
    
         
            +
                    end
         
     | 
| 
      
 208 
     | 
    
         
            +
                  end
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                  line = "# device: #{simple_name}\nATTR{idVendor}==\"#{vendor_id.to_s(16).rjust(4,'0')}\", ATTR{idProduct}==\"#{product_id.to_s(16).rjust(4,'0')}\", MODE=\"0666\", SYMLINK+=\"hidapi/#{simple_name}@%k\"\n"
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                  if last_line
         
     | 
| 
      
 213 
     | 
    
         
            +
                    contents.insert last_line, line
         
     | 
| 
      
 214 
     | 
    
         
            +
                  else
         
     | 
| 
      
 215 
     | 
    
         
            +
                    contents << line
         
     | 
| 
      
 216 
     | 
    
         
            +
                  end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                  path = @temp_dir
         
     | 
| 
      
 219 
     | 
    
         
            +
                  path += '/' unless path[-1] == '/'
         
     | 
| 
      
 220 
     | 
    
         
            +
                  path += 'rules'
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                  File.write path, contents.join("\n")
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                  `sudo cp -f #{path} #{target}`
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                  File.delete path
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                  puts "A udev rule for the device has been created.\nYou may have to unplug/plug the device or restart your computer."
         
     | 
| 
      
 229 
     | 
    
         
            +
                  true
         
     | 
| 
      
 230 
     | 
    
         
            +
                end
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
              end
         
     | 
| 
      
 233 
     | 
    
         
            +
            end
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
            if $0 == __FILE__
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
              HIDAPI::SetupTaskHelper(ARGV[0], ARGV[1], ARGV[2], ARGV[3]).run
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
            end
         
     |