I just accidentally found out how to do it without any mods or extra texture packs, Just 1 command.

First make your gun model replace a crossbow instead of a carrot on a stick so that you have the aim animation when the player holds the weapon and insert this command in a repeating command block in your world:

/replaceitem entity @p[nbt={SelectedItem:{id:"minecraft:crossbow",tag:{Charged:0b,Gun:1}}}] weapon.mainhand crossbow{ChargedProjectiles:[{id:"minecraft:arrow{disappearBug:1}",Count:1b}],Charged:1b,Gun:1}

This replaces a non charged crossbow with the Gun:1 tag with a loaded crossbow with a bugged arrow that won't appear when shot. The crossbow will activate scoreboards and will immediately reload making it the same as a carrot on a stick 

The bugged arrow won't appear, make any noise or spawn particles


Give command for the crossbow (you can get it normally but you would have to shoot an arrow once to activate the above command without this):

/give @p minecraft:crossbow{ChargedProjectiles:[{id:"minecraft:arrow{disappearBug:1}",Count:1b}],Charged:1b,Gun:1}

This was tested in minecraft 1.16 but should work anywhere there is a crossbow