def on_change(pattern=".*", obj=nil, &block)
      pattern = (pattern.kind_of?(Regexp) ? pattern.source : pattern.to_s)

      @listeners[pattern] = [
        ::FFI::MemoryPointer.new(:pointer),
        Proc.new { |handle, obj_ptr, key, value, reason|
          yield object_for(obj_ptr), key, value, reason
        }
      ]
      Klass.set_OnKeyChange_Handler(@handle, @listeners[pattern][0], pattern, @listeners[pattern][1], pointer_for(obj))
      sleep @handler_sleep
    end
def on_change(pattern=".*", obj=nil, &block)
      pattern = (pattern.kind_of?(Regexp) ? pattern.source : pattern.to_s)

      @listeners[pattern] = [
        ::FFI::MemoryPointer.new(:pointer),
        Proc.new { |handle, obj_ptr, key, value, reason|
          yield object_for(obj_ptr), key, value, reason
        }
      ]
      Klass.set_OnKeyChange_Handler(@handle, @listeners[pattern][0], pattern, @listeners[pattern][1], pointer_for(obj))
      sleep @handler_sleep
    end
Adds a key listener to an opened dictionary. Note that this should only be called after the connection has been made - unlike all other events.

 @param [String] obj Object to pass to the callback function. This is optional.
 @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
 @example
     dict.on_change do |obj, key, val, reason|
       puts "Every key: #{key} => #{val}-- #{reason}"
     end
 As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
 @return [Boolean] returns true or raises an error