; 这个库是同时只发射一个timer,用这个库触发的timer可以保证排队执行
#Persistent ; 确保脚本一直运行,直到我们的timmer被解雇

Hello(words) {
  Msgbox, % "Hello " words "!"
  ; 我们需要自己编写退出脚本,使用时 #Persistent
  ExitApp
}
emitter := new AEEmitter()
emitter.On("say", Func("Hello")) ; 注册事件
; 消息框将显示“Hello World!”
emitter.emit("say", "World")     ; 触发它


; #include <AEE>

/*
 *****************************************************
  Author: helsmy
  Website: https://github.com/helsmy/ahk_AEE
  Lisence: LGPLv2.1
  Plesase redistribute with above information
 ******************************************************

  A simple event driven framework

  for the most simple way:
    #Persistent ; Ensure script keeps running until our timmer is fired
    #include <AEE>
    Hello(words)
    {
      Msgbox, % "Hello " words "!"
      ; we need exit script by ourselves, 
      ; when use #Persistent
      ExitApp
    }
    emitter := new AEEmitter()
    emitter.On("say", Func("Hello")) ; register a event
    ; A msgbox will show with "Hello World!"
    emitter.emit("say", "World")   ; fire it

  Property:
    eventsCount(ReadOnly): number of events registered
    maxListener(ReadOnly): the maximum number of listeners that an event can have

  Special Event:
    newListener: fired every times when a new listener is added
           listener must accept 2 parameters: 
            type: event name of added listener
            listener: added listener
    removeListener: fired every times when a listener of a event is removed
           listener must accept 2 parameters: 
            type: event name of removed listener
            listener: removed listener. If more than one listener is removed at once, this parameter passes an array containing all reomved listeners.
*/


class AEEmitter {
  _events := {}
  _eventsCount := 0
  _maxListener := 10

  eventsCount[] {
    get {
      return this._eventsCount
    }

    set {
      throw Exception("Set to read only property", -1, "eventsCount")
    }
  }

  maxListener[] {
    get {
      return this._maxListener
    }

    set {
      throw Exception("Set to read only property", -1, "maxListener")
    }
  }

  /**
   *   Add a listener to wait for a event
   *   @params: type event name waited
   *   @params: callback listener
   *   @params: prepend If ture, add listener to the head of listener list(will be execute earlier)
   */
  On(type, callback, prepend := false) {
    return this._AddListener(type, callback, prepend)
  }

  /**
   *   Remove a listener waiting for a event
   *   @params: type event name waited
   *   @params: callback listener to be removed
   */
  Off(type, callback) {
    return this.RemoveListener(type, callback)
  }
  
  /**
   *   Add a listener to wait for a event
   *   This listener will be removed Once it has been executed
   *   @params: type event name waited
   *   @params: callback listener
   *   @params: prepend If ture, add listener to the head of listener list(will be execute earlier)
   */
  Once(type, listener, prepend := false) {
    return this._AddListener(type, listener, prepend, true)
  }

  /**
   *   Add a listener to wait for a event
   *   @params: type event name waited
   *   @params: listener listener
   *   @params: prepend If ture, add listener to the head of listener list(will be execute earlier)
   */
  AddListener(type, listener, prepend := false) {
    return this._AddListener(type, listener, prepend)
  }

  /**
   *   Add a listener in the head of listener list(will be execute earlier) to wait for a event
   *   @params: type event name waited
   *   @params: listener listener
   */
  PrependListener(type, listener)  {
    return this._AddListener(type, listener, true)   
  }

  /**
   *   Remove a listener waiting for a event
   *   @params: type event name waited
   *   @params: listener listener to be removed
   */
  RemoveListener(type, listener) {
    events := this._events, list := events[type]
    for p, l in list {
      if (l == listener) {
        list.RemoveAt(p)
        if (list.Length() == 0)
          this.RemoveEvent(type)
        if (events.HasKey("removeListener"))
          this.Emit("removeListener", type, listener)
        break
      }
    }
    return this
  }

  /**
   *   Remove all listener of a event
   *   @params: type event name waited
   */
  RemoveAllListener(type) {
    events := this._events
    
    if (events.HasKey(type))
      listeners := events[type], events[type] := []
    if (events.HasKey("removeListener"))
      this.Emit("removeListener", type, listeners)
    return this
  }

  /**
   *   Remove a event from monitor
   *   @params: type event name to be removed
   */
  RemoveEvent(type) {
    events := this._events
    if (events.HasKey(type))
      events.Delete(type), --this._eventsCount
    return this
  }

  /**
   *   Emit a specific event 
   *   @params: type event name waited
   *   @params: params* params to be passed to each listener
   */
  Emit(type, params*) {
    if (this._events.HasKey(type)) {
      for _, handler in this._events[type] {
        if (handler.Length())
          handler := ObjBindMethod(this, "_OnceWapper", type, handler)
        __AEE_EventDispatcher.Put(handler, params)
      }
    }
    return true
  }

  /**
   *   Emit a specific event and execute each listener as quick as possible
   *   @params: type event name waited
   *   @params: params* params to be passed to each listener
   */
  EmitImmediate(type, params*) {
    if (this._events.HasKey(type)) {
      for _, handler in this._events[type] {
        if (handler.Length())
          handler := ObjBindMethod(this, "_OnceWapper", type, handler)
        __AEE_EventDispatcher.Put(handler, params, true)
      }
    }
    return true
  }

  /**
   *  Set property maxListener
   */
  SetMaxListener(number) {
    n := number&-1
    if (number != n) 
      throw Exception("Value Error!", -1, "Need an integer.")
    this._maxListener := n
  }
  
  /**
   *  return number of listeners of a event
   */
  ListenerCount(type) {
    return this._events.HasKey(type) ? this._events[type].Length() : 0
  }

  /**
   *  return all listeners(in a array) of a event
   */
  Listeners(type) {
    if (!this._events.HasKey(type))
      return []
    all_l := []
    for _, l in this._events
      l := IsFunc(l) ? l : l[1]
      , all_l.Push(l)
    return all_l
  }

  /**
   *  return all events' name(in a array) registered
   */
  EventNames() {
    names := []
    for name in this._events
      names.Push(name)
    return names
  }

  /*
   * Inner wapper for `Once` method to remove listener after executed
   * DO NOT CALL IT
   */
  _OnceWapper(type, fn, params*) {
    events := this._events, list := events[type]
    ; Once marked listener is contained in a 1 length array
    fn[1].Call(params*)
    this.RemoveListener(type, fn)
  }
  
  /*
   * Inner method.
   * DO NOT CALL IT
   */
  _AddListener(type, callback, prepend := false, isOnce := false) {
    if (!_IsFuncEx(callback))  ; IsFunc does not work on method, sad
      throw Exception("Value Error", -2, "Listener(callback) must be a function or method")
    if (!this._events)
      this._events := {}
    events := this._events

    if (events.HasKey("newListener"))
      this.Emit("newListener", type, callback)
    if (!events.HasKey(type))
      events[type] := [], ++this._eventsCount
    if (events[type].Length() >= this._maxListener)
      throw Exception("The number of listeners has reached the maximum.", -2, "Use method SetMaxListener to increase it.")
    ; mark once by making a non-function callback   
    if (isOnce)
      callback := [callback]
    if (!prepend)
      events[type].Push(callback)
    else
      events[type].InsertAt(1, callback)
    return this
  }
}

; *************** INNER CLASS *******************
;       DO NOT DRICTLY CALL IT
;     UNLESS YOU KNOW WHAT YOU ARE DONING
; ***********************************************
class __AEE_EventDispatcher {
  /*
   *  Based on DBGp_DispatchTimer of Lexikos's dbgp.ahk
   */
  static eventQueue := []
  static immediateQueue := []

  Put(handler, data, immediate := false) {
    if !immediate
      this.eventQueue.Push([handler, data])
    else
      this.immediateQueue.Push([handler, data])
    ; Using a single timer ensures that each handler finishes before
    ; the next is called, and that each runs in its own thread.
    static DT := ObjBindMethod(__AEE_EventDispatcher, "DispatchTimer")
    SetTimer, % DT, -1
  }

  DispatchTimer() {
    static DT := ObjBindMethod(__AEE_EventDispatcher, "DispatchTimer")
    ; Clear immediateQueue array before fire handler of eventQueue
    if (next := this.immediateQueue.RemoveAt(1))
      fn := next[1], %fn%(next[2]*)
    ; Call exactly one handler per new thread.
    else if next := this.eventQueue.RemoveAt(1)
      fn := next[1], %fn%(next[2]*)
    ; If the queue is not empty, reset the timer.
    if (this.eventQueue.Length() || this.immediateQueue.Length())
      SetTimer, % DT, -1
  }
}

_IsFuncEx(obj) {
  static nBoundFunc := NumGet(&(f := Func("Func").Bind()))
  return IsFunc(obj) || (NumGet(&obj) == nBoundFunc)
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。