code: 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
docs: 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.