Make a haystack (with a needle) (Essentially the inverse of Find the needle in the haystack)

Given two tuples, (w, h) and (x, y), generate a haystack composed of a single random printable ASCII character of w width and h height with a needle made of a different random printable ASCII character at (x, y) when measured from the upper-left.

For example, when given (5,4) for the width and height, and (3,1) (zero-indexed) for the location of the needle, a possible haystack could be the following:

#####
###N#
#####
#####


Another possibility could be

*****
***$*
*****
*****


among hundreds of others.

Rules and Clarifications


Input and output can be given by any convenient method. This means you can take input as a list of list of integers, as a single string, as two integers via command-line and a tuple via function argument, etc.
You can print the result to STDOUT or return it as a function result.
Either a full program or a function are acceptable.
You can choose whether the (x, y) tuple is zero-indexed or one-indexed, but please specify in your solution which you're using.
You do not get to pick which characters to use. That's part of the challenge - randomly selecting the characters.
Every possible output for a given input must have a non-zero chance of appearing, but the randomness doesn't need to be uniform.
The haystack is guaranteed to be at least 2x2 in size, so it's unambiguous which is the needle and which is the hay.
There is only ever one needle, and it's only ever one character in size, and it's guaranteed to be within the boundaries of the haystack.
Standard loopholes are forbidden.
This is code-golf so all usual golfing rules apply, and the shortest code (in bytes) wins.
JavaScript (Node.js),  122 120 106  103 bytes
Recursively builds the output character by character. The coordinates are 0-indexed.

(w,h,x,y)=&gt;(s=new Date%9023,g=X=&gt;Y&lt;h?Buffer([X-w?(x-X|y-Y?s+1:s%96)%95+32:13])+g(X&lt;w?X+1:!++Y):'')(Y=0)

Try it online!
How?
Problem
To generate the haystack and the needle, we could either:

generate a random haystack and process some loop to generate a random needle until it's different from the haystack
shuffle the whole range of printable characters and pick the first 2 of them

Unfortunately, both approaches are rather lengthy in JS.
Solution
We use instead a method that guarantees to generate 2 distinct characters with a single random number and without any loop.
We pick a random seed \$s\$ in \$[0..9022]\$ and define the haystack \$h\$ and needle \$n\$ as:
$$\begin{align}&amp;h=(s+1)\bmod 95\\
&amp;n=(s\bmod 96)\bmod 95\end{align}$$
(we then need to add \$32\$ to turn them into printable ASCII codes)
Basically, \$h\$ follows the pattern:
$$1,2,3,...,94,0,1,2,3,...$$
while \$n\$ follows the pattern:
$$0,1,2,3,...,94,\color{red}0,0,1,2,3,...$$
The sequences are progressively shifted relative to each other because of the extra \$0\$ in the needle pattern.
This code shows that it does eventually lead to all possible pairs \$(h,n)\$ with \$h\neq n\$ (there are \$95\times 94=8930\$ of them).
And because we need only one random number, we can afford to use the current timestamp in milliseconds as our entropy source with new Date%9023 instead of the longer Math.random()*9023.
Commented
(w, h, x, y) =&gt; (      // w = width, h = height, (x, y) = coordinates
  s = new Date % 9023, // s = random seed in [0..9022]
  g = X =&gt;             // g = recursive function taking X
    Y &lt; h ?            //   if we've not reached the end of the grid:
      Buffer([         //     append the next character:
        X - w ?        //       if we haven't reached the end of the line:
          ( x - X |    //         if this is not the position of the needle:
            y - Y ?    //
              s + 1    //           append the haystack character
            :          //         else:
              s % 96   //           append the needle character
          ) % 95 + 32  //
        :              //       else:
          13           //         append a linefeed
      ]) +             //
      g(X &lt; w ? X + 1  //     append the result of a recursive call
              : !++Y)  //     with either (X+1, Y) or (0, Y+1)
    :                  //   else:
      ''               //     stop recursion
)(Y = 0)               // initial call to g with X = Y = 0