def read_timeout(milliseconds)
      raise DeviceNotOpen unless open?

      mutex.synchronize do
        if input_reports.count > 0
          data = input_reports.delete_at(0)
          HIDAPI.debug "read data from device #{path}: #{data.inspect}"
          return data
        end

        if shutdown_thread
          HIDAPI.debug "read thread for device #{path} is not running"
          return nil
        end
      end

      # no data to return, do not block.
      return '' if milliseconds == 0

      if milliseconds < 0
        # wait forever (as long as the read thread doesn't die)
        until shutdown_thread
          mutex.synchronize do
            if input_reports.count > 0
              data = input_reports.delete_at(0)
              HIDAPI.debug "read data from device #{path}: #{data.inspect}"
              return data
            end
          end
          sleep 0.001
        end

        # error, return nil
        HIDAPI.debug "read thread ended while waiting on device #{path}"
        nil
      else
        # wait up to so many milliseconds for input.
        stop_at = Time.now + (milliseconds * 0.001)
        while Time.now < stop_at
          mutex.synchronize do
            if input_reports.count > 0
              data = input_reports.delete_at(0)
              HIDAPI.debug "read data from device #{path}: #{data.inspect}"
              return data
            end
          end
          sleep 0.001
        end

        # no input, return empty.
        ''
      end
    end
def read_timeout(milliseconds)
      raise DeviceNotOpen unless open?

      mutex.synchronize do
        if input_reports.count > 0
          data = input_reports.delete_at(0)
          HIDAPI.debug "read data from device #{path}: #{data.inspect}"
          return data
        end

        if shutdown_thread
          HIDAPI.debug "read thread for device #{path} is not running"
          return nil
        end
      end

      # no data to return, do not block.
      return '' if milliseconds == 0

      if milliseconds < 0
        # wait forever (as long as the read thread doesn't die)
        until shutdown_thread
          mutex.synchronize do
            if input_reports.count > 0
              data = input_reports.delete_at(0)
              HIDAPI.debug "read data from device #{path}: #{data.inspect}"
              return data
            end
          end
          sleep 0.001
        end

        # error, return nil
        HIDAPI.debug "read thread ended while waiting on device #{path}"
        nil
      else
        # wait up to so many milliseconds for input.
        stop_at = Time.now + (milliseconds * 0.001)
        while Time.now < stop_at
          mutex.synchronize do
            if input_reports.count > 0
              data = input_reports.delete_at(0)
              HIDAPI.debug "read data from device #{path}: #{data.inspect}"
              return data
            end
          end
          sleep 0.001
        end

        # no input, return empty.
        ''
      end
    end
Attempts to read from the device, waiting up to +milliseconds+ before returning.

 If milliseconds is less than 1, it will wait forever.
 If milliseconds is 0, then it will return immediately.

 Returns the next report on success.  If no report is available and it is not waiting
 forever, it will return an empty string.

 Returns nil on error.