Волшебство действительно происходит в драйвере устройства. ОС предоставляет интерфейс для программистов приложений. Это несколько массажируется (например, буферизируется), а затем отправляется на устройство. Затем устройство принимает общее представление и преобразует его в сигналы, которые может понять конкретное устройство. Таким образом, ASCII отображается в приемлемом формате на консоли, или в файле PDF, или на принтере, или на диске, в форме, подходящей для этого устройства. Попробуйте что-то кроме ASCII (или UTF8), которое драйвер не понимает, и вы поймете, о чем я говорю.
Для вещей, которые ОС не может обработать (например, специальные графические карты), приложение записывает данные непосредственно в память устройства. Вот как работает что-то вроде DirectX (для упрощения).
Каждый драйвер устройства отличается. Но каждый из них одинаков с точки зрения того, как они взаимодействуют с ОС, по крайней мере для каждого класса устройств (диск, сетевая карта, клавиатура и т. Д.).