for a more general answer, if you rewind the clock back to the 80s and early 90s: a hardware device required setting a COM port or IRQ, which was often done by physically setting jumpers on the device, and the user was responsible for making sure that, e.g. IRQ21 wasn't already being used by the BIOS or another device on the system. Then, you'd install a device driver that knew the specific memory addresses to read/write to in order to communicate with the controller on the device, based on the proprietary way the company decided to do it.
fast forward to today, and the hardware industry has made great advancements in standardizing how devices operate. memory-mapped I/O allows the OS to treat many device drivers the same, they just need to handle manipulation of the memory after it's read/written. for USB, the industry standardized on device classes , so something either acts like a communication device (serial port, JTAG reader), an audio device, a video capture device, or in this case, an HID (human interface device). So based on the general characteristics of how the thing operates, the kernel can do 80% or more of the driver development for you. especially because of the linux credo that "everything is a file"
you plug in a usb dongle and you get (hypothetically) a few files called /sys/class/hid//{control, data}. so you could, say, change the RF channel of the dongle by writing a very specific value to the "control" file, which will get sucked in by the kernel and sent to the device. Or you could get raw kb/mouse data by catting the .../data file. this would in theory, allow you to write a device driver in python by connecting the .../data file to a read handler, processing the input (the hard part, which requires reverse engineering), and emitting the corresponding output, such as the OS command to move the mouse or generate a keyboard event.
I made some generalizations here, but this is the main idea.