Historically, writing to the screen was done by writing either ASCII or pixel values to a special region in memory (e.g. Apple II, IBM PC). I'm not sure what you're suggesting the book should do instead? Use a serial port and terminal? Implement a GPU? (I'm not being sarcastic, just looking for clarification.)
My point is that after reading the book I kind of knew how I could implement a simple CPU in real HW (with ALU, memory, etc.) but it was not clear to me how the IO part (kbd, screen) would work. Is the kbd connected directly to a certain place of memory? How is this implemented? Would there be some screen/gpu HW that is directly connected to the memory region? How is the CPU clock involved?
E.g. if you press a key, hold it and then release it, it is possible that this event gets missed as it was too short and the key press method did not check the memory region at the right point of time. For me their implementation enforces this bogus "I am in total control of everything that happens feeling" which often leads to bad design as it ignores the messy real world. I would have appreciated something more sophisticated and generic there which would work for different kinds of HW. Maybe I am missing some simple bus-system one might say ...
Nevertheless it is a wonderful book and I had lots of fun with it! :)
If I'm not mistaken, the keyboard should raise high an interrupt pin on the CPU, which should cause an interrupt service routine to be called.
That routine should then mask lower-priority interrupts, poll the appropriate region of memory (assuming memory-mapped IO) for the byte or bytes held down, push those onto the buffer for key inputs or into the STDIN equivalent, unmask lower-priorty interrupts, and return.
It is then up to the user program to read in from the buffer and do the needful.
I was actually working on implementing a simple little VM library in C as a fun exercise, and deciding how to handle interrupts was where I got caught up.
Most VMs don't have interrupts. As a less-complex alternative, you might consider implementing an I/O thread, something rarely done in hardware because an extra CPU is a lot more hardware than an interrupt mechanism.
One interesting exception is the Unix VM, whose interrupts are called "signals".