What is a good strategy to read many button inputs while still doing USB?
This sounds very reasonable, as long as you bear in mind that accessing the same data by the normal code and the interrupt code can cause trouble, if it happens at the same time.

Imagine, you have a buffer for sending data via USB, and a counter for the number of data bytes actually inside the buffer.

There are actually 10 bytes to be send in the buffer, so counter=10.

If your code wants to append three further bytes, it will:


Read counter to know at which position of the buffer the bytes have to be inserted
Write the bytes to positions 11, 12, 13
Increase counter by 3, as there are now three more bytes in the buffer.


The USB routine called later, will to this:


Read counter to know how many bytes have to be sent
Send that bytes
Set counter to zero


Now, if the USB routine is called by a timer interrupt, it is called while your normal function is executing a random line. For example, it may be called just after the normal function processed step 2. What happens?


The normal routine has already written the new bytes to position 11, 12 and 13.
The USB routine reads counter, which still is 10, and so sends just the first ten bytes in the buffer. After, it sets counter to zero.
The normal routine continues where it was interrupted and increases counter by three. It is counter=3 !!!


The code does not only ignore the new three bytes. On the next call, the USB routine will send the first three bytes in the buffer, which are the same three bytes sent by the last call.

To circumvent this problem, just do all the button reading / data processing while the USB routine is called by the timer interrupt. As soon as you want to put data into the buffer, disable the interrupt/timer, write to the buffer and to counter, and enable the interrupt again.

The USB routine has to be called at least once within a given time interval. If your timing is too tight, it's possible you exceed the interval when disabling the interrupt. Therefore, call the USB routine manually directly after disabling the interrupt, or choose a much shorter period for your timer.