For Windows:
I don't know of any app off the top of my head, but here are some ideas that might work within 100 lines of code...
I would avoid SetWindowsHook, as that would inject your code into all apps. (Because I've spent good time debugging crash dumps and bugs as a result of poorly written hooks...)
You could write a console app with DirectInput (old gaming keyboard API). I believe you just pass DISCL_BACKGROUND and DISCL_NONEXCLUSIVE into IDirectInputDevice8::SetCooperativeLevel call. Use IDirectInputDevice8::SetEventNotification to set the event handle so you don't have get into a busy wait loop polling for input. And that should do it. I did this once for my app a long time ago on Windows 98 and it worked really well. But DirectInput is very close to being deprecated technology so YMMV.
Another simple hacked up way to do what you are doing is to have your app create a hidden window, call call RegisterHotkey for all the keyboard, and pump window messages. Your wndproc will get a WM_HOTKEY window message that you can use that to generate a message to stdout.
The simplest way, but will be slightly error prone and cpu-expensive is to have your console app get into a loop and call GetKeyboardState. This will return the entire state of the keyboard of all keys that are up and down. You'll have to figure out how translate each poll into a logical keystroke. I'd recommend sleeping a few milliseconds between polls so you don't kill system-wide performance.
Can't help you on OSX.