Deadlock occurs when you attempt to acquire the lock in the test, while the lock is already held by the game thread. What I meant with the "return channel" was literally passing the state back through the channel for assertions. It's very easy to do if you don't mind cloning the state for your tests.
And of course, you wouldn't send the state until after it has been updated by handling the key event. Going back to what I said earlier about dependency inversion introducing weird code, this is a great example of that. If you need to do end-to-end automated testing, some sacrifices will have to be made.