If you use dependency injection wisely, you will never need to use global variables of any sort.
For communication, for example, you can inject in each system by constructor a mediator that will let the systems communicate between each other.
Let's put it in another way, let's assume that your EventManager is not a static class/singleton, but an instance that you created in your application composition root, that you can pass by constructor in your systems (your systems should also be created in the composition root).
If you create just one instance of the EventManager, there isn't much difference with what you have done. The problem about global variables is the lack of scope, which leads to spaghetti code. This means that you should give a specific responsibility to each EventManager you want to create and inject them only in specific systems. A simple example, just to clarify what I am saying, is that you can have a GUIEventManager that you can inject only in your systems that deals with GUI.
All that said, there are different approaches to solve communication, although all of them rely on injection. For example in Svelto.ECS I use the concept of "sequencer", which is a way to declare that a list of systems is part of a specific communication flow and let each single system to communicate to the next one in the flow.
Communication can happens also through data change. ECS is very prone to this kind of communication, as it can happen through the entity components. Usually it happens through polling, but polling can be awkward. In Svelto.ECS I created a sort of data binding system to communicate through data pushing instead of polling.