Here is a schematic, taken from this site. Note that there is an error in the pinout, the Detect and Trigger lines are reversed. The ones in blue are correct.
The electrical interface is quite simple. It has two outputs:
+--+ +--+ | | | | | | | | ------+ +----------+ +------- <--> 3mS <-------------> 17 mS (60 Hz)
I then hooked the Zapper up to the joystick port of the XGS and wrote a simple program with the Tile Engine to display the state of the two ports.
You can connect the Zapper to the XGS joystick port with a suitable connector adaptor. You need to hook up all 4 pins. Fortunately the XGS joystick connector provides +5V. A cheap way to connect to the NES connector is just to use small nails with wires soldered to them.
Reading the joystick port is a little slow since you have to go through the shift register and clock the bits out one at a time. The provided joystick routines typically read both joysticks as well (16 bits). If you want to read the Zapper quickly during video processing then it is much better to hook it directly to an i/o port where it can be read in one clock cycle with no overhead. The only caveats are: use a port that is otherwise unused, and it needs a pullup resistor (which the SX52 can do in software!). I used port RB5 which is available on the header near the joystick 1 port.
The First Problem: the Tile Engine calls the game logic during the vertical retrace period. At this time the Zapper does not detect any video signal, you need to do this during video output. I then played for a while with hooking into the video portion of the tile Engine but quickly ran into problems with the code getting too big and overflowing page boundaries. There is not a lot of time to spare in the Tile Engine as it has a lot to do (getting maps from SRAM, etc.).
I thought it would be easier to modify a smaller program so my next experiment was to start with the simple colour bar demo included on the XGS CD and modify it to indicate the state of the Zapper light detector. This was quite easy to do. I started with a single check once per scan line and then extended it to check the status 8 times per scan line to see if I could get both vertical and horizontal position information. This actually worked, at least as far as getting a pretty accurate vertical position.
I'm now experimenting with the accuracy I can get on the horizontal axis. This is not absolutely required for a game but would be cool if I can do it. If anyone wants a copy of this demo code I can send it to them.