More low-level approach would be to use raw input API. DirectInput actually uses raw input to talk to controllers. There are advantages and disadvantages to that.
Advantages:
1) more low-level API = more control what you do
2) event based input - you get windows message when new input is available, so less lag. No need to poll (DirectInput uses polling on separate thread = more lag).
3) one more library (DirectInput) less you depend on
Disadvantages
1) low-level API = more code to write :)
2) probably very tricky to get force-feedback to work (not sure, maybe it's not a big issue)
I have tried to use raw input to work with PS4 DualShock 4 controller. I mentioned it here:
https://hero.handmadedev.org/foru...n/351-xinput-and-directinput#2296
It's pretty straight forward there and you can get force feedback working and even control led color on controller (something DirectInput cann't do).