We need two kinds of modifiers (shortcuts) for our tools system:
The biggest problem we have there is that two levels of the modifiers implementations must know the state of the underlying implementation. That is, you cannot start a canvas panning while a freehand tool is painting on the canvas. That is why some complex system is needed.
The entire system will be based on the current implementation of KoInteractionTool/KoInteractionStrategy. So, ideally, all the tools will have to ported to KoInteractionStrategy. But for not doing this huge amount of (quite inefficient) work at once, the system provides special wrappers for KoToolBase those encapsule it into a strategy.
The main class here is KoInteractionStrategyFactory. It associates a particular strategy with the key stroke. It recieves notifications from KoModifiersManager when the keys are pressed/released so it can store any key as a modifier. When the manager calls tryCreateStrategy() it checks whether all the preconditions are satisfied and creates the strategy if needed.
The purpose of the manager is to filter all the mouse/key events that come to the KoManagedInteractionTool and pass them to the factories in a special order. When a key event comes it first notifies all the factories about this event. Then it starts iterating through the factories, checks whether current strategy (if there is one) can be superseded by any of the created ones and if so calls tryCreateStrategy(). You can see this process on a sequence diagram below.
This approach solves two great problems:
Implementation of two levels of shortcuts is shown on a diagram below. The wrappers (KoInteractionToolStrategyWrapper and KoToolBaseStrategyWrapper) create a common interface for the KoModifiersManager, so it can send the event further to the tools.