This is an implementation-specific question, but broad strokes: direct access to hardware via interrupts is generally limited to the OS (specifically, to the kernel.) Your code will not have such access on any modern system. Rather, you'd use OS-specific APIs to access hardware.
In short: desktop operating systems do not behave like embedded, microcontrolled devices.
User input is generally handled on modern systems by something called an event loop. Your application does something like this, the specific implementation varying between OSes:
int main(int argc, char *argv[]) {
Event *e = NULL;
while (e = App::GetNextEvent()) {
switch (e->getType()) {
case E_MOUSEUP:
case E_RIGHTMOUSEDOWN:
case E_KEYDOWN:
// etc.
}
}
return EXIT_SUCCESS;
}
In this example, App::GetNextEvent()
doesn't busy-wait: it simply sits and does nothing until signalled internally by the OS that an event has arrived. In this way, no constant polling is required and the OS can dole out time slices to processes more efficiently.
However... the NES is not a modern system; emulating one means you need to emulate the interrupts and hardware of the NES. Doing so is a very large undertaking and has no relation to the underlying hardware or interrupts of the host operating system. The 6502 processor in the NES is very simple by modern standards; there are books available that discuss emulating similar simple processors, though titles escape me at the moment.
Does that help?