[For David, aarku] Carbon Events
This is a source file from an old project of mine showing how to use Carbon events for game input. Make of it what you can...
Code:
#include <Carbon/Carbon.h>
#include "EventHandler.hpp"
#include "MacKeyCodes.hpp"
namespace COSI {
int shiftLevel = 0;
ScreenDimension EventHandler::getScreenResolution() {
ScreenDimension result;
return result;
}
#define CARBON_ERROR(err) if (err != noErr) { fatalError("Carbon error `%d'\n", err); }
static const EventTypeSpec KEY_EVENTS[] = {
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyUp },
{ kEventClassKeyboard, kEventRawKeyModifiersChanged }
};
static const EventTypeSpec MOUSE_EVENTS[] = {
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged }
};
static const EventTypeSpec WINDOW_EVENTS[] = {
{ kEventClassWindow, kEventWindowBoundsChanged },
{ kEventClassWindow, kEventWindowFocusAcquired },
{ kEventClassWindow, kEventWindowFocusRelinquish },
{ kEventClassWindow, kEventWindowCollapsed },
{ kEventClassWindow, kEventWindowExpanded }
};
Key macToCOSIKeyCode(UInt32 macKeyCode);
Key macToCOSIKeyCode(UInt32 macKeyCode) {
if (macKeyCode >= NUM_KEY_CODES) {
return KEY_UNKNOWN;
}
Key result = KEY_CODES[macKeyCode];
//debugMessage("Translating %lx to %s\n", macKeyCode, keyName(result).c_str());
return result;
}
OSStatus keyHandler(EventHandlerCallRef hcr, EventRef event, void* p);
OSStatus mouseHandler(EventHandlerCallRef hcr, EventRef event, void* p);
OSStatus appWindowHandler(EventHandlerCallRef hcr, EventRef event, void* p);
void idleTimer(EventLoopTimerRef timer, void *p);
OSStatus keyHandler(EventHandlerCallRef hcr, EventRef event, void* p) {
EventHandler* handler = (EventHandler*)(p);
if (GetEventClass(event) != kEventClassKeyboard) {
fatalError("Carbon error: wrong event class given to handler\n");
}
switch(GetEventKind(event)) {
case kEventRawKeyDown: {
UInt32 keyCode;
OSStatus error = GetEventParameter(event,
kEventParamKeyCode,
typeUInt32,
NULL,
sizeof(UInt32),
NULL,
&keyCode);
CARBON_ERROR(error);
handler->keyPressed(macToCOSIKeyCode(keyCode));
} break;
case kEventRawKeyUp: {
UInt32 keyCode;
OSStatus error = GetEventParameter(event,
kEventParamKeyCode,
typeUInt32,
NULL,
sizeof(UInt32),
NULL,
&keyCode);
CARBON_ERROR(error);
handler->keyReleased(macToCOSIKeyCode(keyCode));
} break;
case kEventRawKeyModifiersChanged: {
static UInt32 modifiers = 0;
UInt32 newModifiers;
OSStatus error = GetEventParameter(event,
kEventParamKeyModifiers,
typeUInt32,
NULL,
sizeof(UInt32),
NULL,
&newModifiers);
CARBON_ERROR(error);
UInt32 changed = modifiers ^ newModifiers;
if ((changed & cmdKey) != 0) {
if ((modifiers & cmdKey) != 0) {
handler->keyReleased(KEY_COMMAND);
} else {
handler->keyPressed(KEY_COMMAND);
}
}
if ((changed & (shiftKey | rightShiftKey)) != 0) {
if ((modifiers & (shiftKey | rightShiftKey)) != 0) {
handler->keyReleased(KEY_SHIFT);
} else {
handler->keyPressed(KEY_SHIFT);
}
}
if ((changed & (optionKey | rightOptionKey)) != 0) {
if ((modifiers & (optionKey | rightOptionKey)) != 0) {
handler->keyReleased(KEY_OPTION);
} else {
handler->keyPressed(KEY_OPTION);
}
}
if ((changed & (controlKey | rightControlKey)) != 0) {
if ((modifiers & (controlKey | rightControlKey)) != 0) {
handler->keyReleased(KEY_CTRL);
} else {
handler->keyPressed(KEY_CTRL);
}
}
if ((changed & alphaLock) != 0) {
if ((modifiers & alphaLock) != 0) {
handler->keyReleased(KEY_CAPS_LOCK);
} else {
handler->keyPressed(KEY_CAPS_LOCK);
}
}
modifiers = newModifiers;
} break;
default:
fatalError("Carbon error: wrong event kind given to handler\n");
}
return noErr;
}
OSStatus mouseHandler(EventHandlerCallRef hcr, EventRef event, void* p) {
static ButtonMask currentButtons = 0;
EventHandler* handler = (EventHandler*)(p);
if (GetEventClass(event) != kEventClassMouse) {
fatalError("Carbon error: wrong event class given to handler\n");
}
switch(GetEventKind(event)) {
case kEventMouseDown: {
Point where;
OSStatus error;
error = GetEventParameter(event,
kEventParamMouseLocation,
typeQDPoint,
NULL,
sizeof(where),
NULL,
&where);
CARBON_ERROR(error);
GlobalToLocal(&where);
EventMouseButton button;
error = GetEventParameter(event,
kEventParamMouseButton,
typeMouseButton,
NULL,
sizeof(button),
NULL,
&button);
CARBON_ERROR(error);
//debugMessage("Mouse button %d pressed\n", button);
currentButtons |= nthMouseButton(button);
handler->mousePressed(MouseLocation(where.h, where.v),
currentButtons,
nthMouseButton(button));
} break;
case kEventMouseUp: {
Point where;
OSStatus error;
error = GetEventParameter(event,
kEventParamMouseLocation,
typeQDPoint,
NULL,
sizeof(where),
NULL,
&where);
CARBON_ERROR(error);
GlobalToLocal(&where);
EventMouseButton button;
error = GetEventParameter(event,
kEventParamMouseButton,
typeMouseButton,
NULL,
sizeof(button),
NULL,
&button);
CARBON_ERROR(error);
//debugMessage("Mouse button %d released\n", button);
currentButtons &= ~nthMouseButton(button);
handler->mouseReleased(MouseLocation(where.h, where.v),
currentButtons,
nthMouseButton(button));
} break;
case kEventMouseMoved: case kEventMouseDragged: {
Point location, delta;
OSStatus error;
error = GetEventParameter(event,
kEventParamMouseLocation,
typeQDPoint,
NULL,
sizeof(location),
NULL,
&location);
CARBON_ERROR(error);
GlobalToLocal(&location);
// kEventParamMouseDelta doesn't work on MacOS < X, so this code
// will need to be replaced if Carbon COSI is to work on 8.6 or 9.x
error = GetEventParameter(event,
kEventParamMouseDelta,
typeQDPoint,
NULL,
sizeof(delta),
NULL,
&delta);
CARBON_ERROR(error);
handler->mouseMoved(MouseLocation(location.h, location.v),
MouseDelta(delta.h, delta.v),
currentButtons);
} break;
default:
fatalError("Carbon error: wrong event kind given to handler\n");
}
return noErr;
}
OSStatus appWindowHandler(EventHandlerCallRef hcr, EventRef event, void* p) {
EventHandler* handler = (EventHandler*)(p);
if (GetEventClass(event) != kEventClassWindow) {
fatalError("Carbon error: wrong event class given to handler\n");
}
switch(GetEventKind(event)) {
case kEventWindowBoundsChanged: {
Rect bounds;
OSStatus error;
error = GetEventParameter(event,
kEventParamCurrentBounds,
typeQDRectangle,
NULL,
sizeof(bounds),
NULL,
&bounds);
CARBON_ERROR(error);
handler->windowResized(ScreenDimension(bounds.right - bounds.left, bounds.bottom - bounds.top));
} break;
case kEventWindowFocusAcquired: {
handler->windowFocus(ACQUIRED);
} break;
case kEventWindowFocusRelinquish: {
handler->windowFocus(LOST);
} break;
case kEventWindowCollapsed: {
handler->windowStatus(MINIMIZED);
} break;
case kEventWindowExpanded: {
handler->windowStatus(UNMINIMIZED);
} break;
default:
fatalError("Carbon error: wrong event kind given to handler\n");
}
return noErr;
}
void idleTimer(EventLoopTimerRef timer, void *p) {
EventHandler* handler = (EventHandler*)(p);
handler->idle();
}
EventHandler::EventHandler() {
OSStatus error;
error = InstallApplicationEventHandler(NewEventHandlerUPP(keyHandler),
GetEventTypeCount(KEY_EVENTS),
KEY_EVENTS,
this,
NULL);
CARBON_ERROR(error);
error = InstallApplicationEventHandler(NewEventHandlerUPP(mouseHandler),
GetEventTypeCount(MOUSE_EVENTS),
MOUSE_EVENTS,
this,
NULL);
CARBON_ERROR(error);
error = InstallApplicationEventHandler(NewEventHandlerUPP(appWindowHandler),
GetEventTypeCount(WINDOW_EVENTS),
WINDOW_EVENTS,
this,
NULL);
CARBON_ERROR(error);
error = InstallEventLoopTimer(GetMainEventLoop(), //inEventLoop
0, //inFireDelay
5 * kEventDurationMillisecond, //inInterval (200 Hz)
NewEventLoopTimerUPP(idleTimer), //inTimerProc
this, //inTimerData,
NULL //outTimer
);
CARBON_ERROR(error);
}
EventHandler::~EventHandler() {
}
void EventHandler::handleEvents() {
RunApplicationEventLoop();
}
}
Great post Keith! I was going through an old Carbon project.. and someone had a question about using IME input to enter non-english characters, like é. Can this carbon approach be used with IME?
(No one give me crap about resurrecting an old thread. I'm on topic!)
(No one give me crap about resurrecting an old thread. I'm on topic!)
Howling Moon Software - CrayonBall for Mac and iPhone, Contract Game Dev Work
They might give you crap about resurrecting Carbon though.
Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
This is all deprecated these days... and had nothing to do with input methods in the first place.
For a modern equivalent of this code, see https://github.com/elmindreda/glfw/blob/...a_window.m (but it still doesn't deal with input methods).
For a modern equivalent of this code, see https://github.com/elmindreda/glfw/blob/...a_window.m (but it still doesn't deal with input methods).
Someone give this man a trophy for the oldest thread revival ever.
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Carbon events in windowed/full screen mode. Help needed. | Anton Petrov | 1 | 3,162 |
Dec 18, 2008 05:35 AM Last Post: DoG |
|
| Simulating "system idle" events in Carbon applications | ascotti | 4 | 2,924 |
May 2, 2006 03:22 PM Last Post: OneSadCookie |
|
| Carbon Key Events | Nickolei | 7 | 4,396 |
Nov 17, 2002 03:37 PM Last Post: codemattic |
|
| Carbon Keyboard Events | IBethune | 7 | 4,949 |
Oct 22, 2002 05:58 AM Last Post: IBethune |
|
| Carbon events (again) | sealfin | 2 | 3,252 |
Jul 1, 2002 06:34 AM Last Post: sealfin |
|

