So I thought I'd see if HorizonV by Nasir would do the joyport thing, and it does but it's a little bit strange.

It will only ask you once what controller you are going to use, and if you don't type CTRL+SHIFT+P right at that moment you won't be able to switch to the joyport. But it isn't consistent about how it uses the ports. Note that it doesn't list the joyport as an option.

[Linked Image from]

I think that it was written with using the switch in the Left Position where it completely ignores what the m_an0 is doing. Because it wants to turn an0 on and off which chooses the other joystick. So the fire button ends up on the other joystick from where the left/right and up/down is.

[Linked Image from]

So why don't we try to reproduce that functionality with a little configuration option:
        PORT_CONFNAME(0x03, 0x01, "Joyport Switch Setting")
        PORT_CONFSETTING(0x00, "Left (Joystick 1)")
        PORT_CONFSETTING(0x01, "Middle (2 Player - Both)")
        PORT_CONFSETTING(0x02, "Right (Joystick 2)")

        PORT_CONFNAME(0x0C, 0x04, "Atari Joystick / Paddle Switch")
        PORT_CONFSETTING(0x04, "Joystick")
        PORT_CONFSETTING(0x08, "4 Player Paddle")
add it to our device:
apple2_joyport_device::apple2_joyport_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
        : device_t(mconfig, APPLE2_JOYPORT, tag, owner, clock)
        , device_a2gameio_interface(mconfig, *this)
        , m_player1(*this, "joystick_p1")
        , m_player2(*this, "joystick_p2")
        , m_joyport_config(*this, "joyport_config")

and add the required_ioport to our .h file:
        // input ports
        required_ioport m_player1, m_player2;
        required_ioport m_joyport_config;

        u8 port_read;
        if      ((m_joyport_config->read() & 0x03) == 0x00) port_read = m_player1->read();
        else if ((m_joyport_config->read() & 0x03) == 0x01) port_read = m_an0 ? m_player2->read() : m_player1->read();
        else if ((m_joyport_config->read() & 0x03) == 0x02) port_read = m_player2->read();
        return BIT(port_read, 4);

the other switches are pretty similar to this one:

and now you can just switch the port into left / middle (both) / right

[Linked Image from]

And I reckon I could implement the Paddle Adapple functionality with a similar configuration option, one for each of the inputs, have a corresponding output and just select the one you want.