Your problem with the focusCycleRoots can be solved by writing a new LayoutFocusTraversalPolicy. Just to review:
The KeyboardFocusManager.getCurrentKeyboardFocusManager() handles focus. It uses a focus traversal policy to decide what to do with your key events.
Which keys to use are defined by setting the focus traversal keys. Here�s an idiom from the
Java Tutorial:
I have this working using two traversal policies, one for traversing the roots ( panels) and a standard anonymous one for traversing the components (buttons) but it should be possible to write it using a single more complex policy if you wanted to. I just did it this way because the default policy works fine for the buttons.
One thing strangely missing from the traversal policy is any methods that handle up cycle (or down cycle) events. The way I solved this was to add an implementation of KeyEventPostProcessor to the traversal policy and handle the up cycle keys in its postProcess(KeyEvent e) method. The up and down cycles are already handled by the KeyFocusManager but you need somewhere to traverse forward and backward on your up cycle. Here's a working policy that you can slot into your code subject to adding the code above and assigning the policy to your root panels. Don't forget to set a LayoutTraversalPolicy for the buttons:
It's not any simpler than your solution but using policies and the KeyboardFocusManager is probably closer to the intended use of the APIs. This version also solves your problem with getting to the first button.
If you wanted to continue doing things the way you are you could experiment with LayoutFocusTraversalPolicy.setImplicitDownCycle(false); and then explicitly handle your down cycles rather than clearing and resetting your roots.