The best way to do this is to make the whole inventory system its own scene. Then, go to Project > Project Settings > AutoLoad, and then from "path" click the folder icon and add your inventory.tscn
scene as a singleton. Make sure it's enabled. This will ensure that the inventory scene is persistent and always loaded across all of your scenes during run-time automatically. You can load your levels normally and your inventory will always be loaded.
After this, you can simply attach a script somewhere in your inventory scene that will have a function responsible for handling input. For instance, if you want the "i" key to open your inventory you could put a script in your inventory scene with the func _input(event)
function that will check for input events. And when the "i" key is pressed it could show/hide the inventory menu when all conditions are met.
You can then use get_tree().paused = !get_tree().paused
to toggle the game being paused/unpaused when it's called. In your inventory scene set the pause mode to "process" on your root control node, which will ensure that all the child elements also inherit that property automatically. That will make it so the inventory menu will continue to process input even while the game is paused.
That's one way to go about solving this problem and probably the most straightforward and easy. It also has basically no drawbacks, other than always taking up a small number of resources in the background, but for something as simple and lightweight as an inventory menu, the impact is unnoticeable.
I've used this exact technique on my own project for something similar:https://github.com/SirQuartz/debugconsole
While not an inventory system, my debug console is a UI element that functions in a similar way to how you'll want the inventory to work.