We should clarify something here.
A window that is 400x300 will not fill the screen unless the screen's resolution is 400x300.
So, to fill the screen, we can change its resolution and go fullscreen with the window,
or we can make the size of the window the same size as the current resolution (this is commonly called "Windowed Fullscreen".)
The other thing to consider is that I expect you want to work with
co-ordinates that go from (0, 0) to (399, 299) and to set
that, you use a view.
So, first create a "target view" (the one you want to use within the window) like this:
sf::View targetView{};
targetView.setSize({ 400.f, 300.f });
targetView.setCenter({ 200.f, 150.f });
NOTE: I've set the size and center separately so it's clear what is happening but you can also set it in its constructor.
Then, set the window to use this target view:
window.setView(targetView);
Then, you can change the size of the window to match the full screen (or allow it to be resized).
The window will change size but the view will always be 400x300 so drawing at (200, 150) will always be in the centre.
You can just leave it there if you don't don't want the letterboxing effect and the window will always use the co-ordinates (0, 0) - (400, 300)-ish
But, since you do also want the letterboxing effect, you can use that function like this (whenever the window changes size, including when you set it or when it is resized):
window.setView(getLetterboxView(view, windowSize.x, windowSize.y));
windowSize is the actual current size of the window, and
view is the view we created earlier (it doesn't change)
This is obviously C++ code that I've used for the examples so you'll need to adapt to the version/language you're using.