refactored to support capture + dispatch on window