[For David, aarku] Carbon Events - OneSadCookie - Aug 9, 2003 03:44 AM
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();
}
}
RE: [For David, aarku] Carbon Events - AndyKorth - Mar 5, 2013 06:56 PM
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!)
RE: [For David, aarku] Carbon Events - Skorche - Mar 5, 2013 07:46 PM
They might give you crap about resurrecting Carbon though.
RE: [For David, aarku] Carbon Events - OneSadCookie - Mar 5, 2013 08:02 PM
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/master/src/cocoa_window.m (but it still doesn't deal with input methods).
RE: [For David, aarku] Carbon Events - SethWillits - Mar 5, 2013 10:20 PM
Someone give this man a trophy for the oldest thread revival ever.
|