forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
@ -0,0 +1,69 @@
|
||||
#ifdef KINC_METAL
|
||||
#import <MetalKit/MTKView.h>
|
||||
#else
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <OpenGL/CGLContext.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import <OpenGL/gl.h>
|
||||
#import <OpenGL/glext.h>
|
||||
#import <OpenGL/glu.h>
|
||||
#endif
|
||||
|
||||
#ifdef KINC_METAL
|
||||
|
||||
struct kinc_g5_render_target;
|
||||
|
||||
@interface BasicOpenGLView : MTKView {
|
||||
@private
|
||||
id<MTLDevice> device;
|
||||
id<MTLCommandQueue> commandQueue;
|
||||
id<MTLLibrary> library;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// (DK) context sharing
|
||||
// www.cocoabuilder.com/archive/cocoa/29573-sharing-opengl-context.html
|
||||
// basically:
|
||||
// -don't use NSOpenGLView, but implement all that by hand
|
||||
// -use -initWithFormat:shareContext: (NSOpenGLContext) to setup the shared contexts
|
||||
@interface BasicOpenGLView : NSOpenGLView {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef KINC_METAL
|
||||
- (CAMetalLayer *)metalLayer;
|
||||
- (id<MTLDevice>)metalDevice;
|
||||
- (id<MTLLibrary>)metalLibrary;
|
||||
- (id<MTLCommandQueue>)metalQueue;
|
||||
#else
|
||||
- (void)prepareOpenGL;
|
||||
- (void)switchBuffers;
|
||||
+ (NSOpenGLPixelFormat *)basicPixelFormat;
|
||||
#endif
|
||||
|
||||
- (void)keyDown:(NSEvent *)theEvent;
|
||||
- (void)keyUp:(NSEvent *)theEvent;
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent;
|
||||
- (void)mouseUp:(NSEvent *)theEvent;
|
||||
- (void)mouseMoved:(NSEvent *)theEvent;
|
||||
- (void)mouseDragged:(NSEvent *)theEvent;
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent;
|
||||
- (void)rightMouseUp:(NSEvent *)theEvent;
|
||||
- (void)rightMouseDragged:(NSEvent *)theEvent;
|
||||
- (void)scrollWheel:(NSEvent *)theEvent;
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
|
||||
|
||||
- (void)update; // moved or resized
|
||||
|
||||
- (BOOL)acceptsFirstResponder;
|
||||
- (BOOL)becomeFirstResponder;
|
||||
- (BOOL)resignFirstResponder;
|
||||
|
||||
- (id)initWithFrame:(NSRect)frameRect;
|
||||
- (void)resize:(NSSize)size;
|
||||
|
||||
@end
|
@ -0,0 +1,483 @@
|
||||
#import "BasicOpenGLView.h"
|
||||
|
||||
#include <kinc/input/keyboard.h>
|
||||
#include <kinc/input/mouse.h>
|
||||
#include <kinc/input/pen.h>
|
||||
#include <kinc/system.h>
|
||||
|
||||
#ifdef KINC_METAL
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#endif
|
||||
|
||||
@implementation BasicOpenGLView
|
||||
|
||||
static bool shift = false;
|
||||
static bool ctrl = false;
|
||||
static bool alt = false;
|
||||
static bool cmd = false;
|
||||
|
||||
#ifndef KINC_METAL
|
||||
+ (NSOpenGLPixelFormat *)basicPixelFormat {
|
||||
// TODO (DK) pass via argument in
|
||||
int aa = 1; // Kore::Application::the()->antialiasing();
|
||||
if (aa > 0) {
|
||||
NSOpenGLPixelFormatAttribute attributes[] = {NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize,
|
||||
(NSOpenGLPixelFormatAttribute)24, // 16 bit depth buffer
|
||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
||||
NSOpenGLPFASupersample, NSOpenGLPFASampleBuffers,
|
||||
(NSOpenGLPixelFormatAttribute)1, NSOpenGLPFASamples,
|
||||
(NSOpenGLPixelFormatAttribute)aa, NSOpenGLPFAStencilSize,
|
||||
(NSOpenGLPixelFormatAttribute)8, (NSOpenGLPixelFormatAttribute)0};
|
||||
return [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||
}
|
||||
else {
|
||||
NSOpenGLPixelFormatAttribute attributes[] = {
|
||||
NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24, // 16 bit depth buffer
|
||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, NSOpenGLPFAStencilSize,
|
||||
(NSOpenGLPixelFormatAttribute)8, (NSOpenGLPixelFormatAttribute)0};
|
||||
return [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)switchBuffers {
|
||||
[[self openGLContext] flushBuffer];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)theEvent {
|
||||
if (shift) {
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_SHIFT);
|
||||
shift = false;
|
||||
}
|
||||
if (ctrl) {
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_CONTROL);
|
||||
ctrl = false;
|
||||
}
|
||||
if (alt) {
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_ALT);
|
||||
alt = false;
|
||||
}
|
||||
if (cmd) {
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_META);
|
||||
cmd = false;
|
||||
}
|
||||
|
||||
if ([theEvent modifierFlags] & NSShiftKeyMask) {
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_SHIFT);
|
||||
shift = true;
|
||||
}
|
||||
if ([theEvent modifierFlags] & NSControlKeyMask) {
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_CONTROL);
|
||||
ctrl = true;
|
||||
}
|
||||
if ([theEvent modifierFlags] & NSAlternateKeyMask) {
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_ALT);
|
||||
alt = true;
|
||||
}
|
||||
if ([theEvent modifierFlags] & NSCommandKeyMask) {
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_META);
|
||||
cmd = true;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)theEvent {
|
||||
if ([theEvent isARepeat])
|
||||
return;
|
||||
NSString *characters = [theEvent charactersIgnoringModifiers];
|
||||
if ([characters length]) {
|
||||
unichar ch = [characters characterAtIndex:0];
|
||||
switch (ch) { // keys that exist in keydown and keypress events
|
||||
case 59:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_SEMICOLON);
|
||||
break;
|
||||
case 91:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_OPEN_BRACKET);
|
||||
break;
|
||||
case 93:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_CLOSE_BRACKET);
|
||||
break;
|
||||
case 39:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_QUOTE);
|
||||
break;
|
||||
case 92:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_BACK_SLASH);
|
||||
break;
|
||||
case 44:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_COMMA);
|
||||
break;
|
||||
case 46:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_PERIOD);
|
||||
break;
|
||||
case 47:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_SLASH);
|
||||
break;
|
||||
case 96:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_BACK_QUOTE);
|
||||
break;
|
||||
case 32:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_SPACE);
|
||||
break;
|
||||
case 45: // we need breaks because EQUALS triggered too for some reason
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_HYPHEN_MINUS);
|
||||
break;
|
||||
case 61:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_EQUALS);
|
||||
break;
|
||||
}
|
||||
switch (ch) {
|
||||
case NSRightArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_RIGHT);
|
||||
break;
|
||||
case NSLeftArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_LEFT);
|
||||
break;
|
||||
case NSUpArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_UP);
|
||||
break;
|
||||
case NSDownArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_DOWN);
|
||||
break;
|
||||
case 27:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_ESCAPE);
|
||||
break;
|
||||
case NSEnterCharacter:
|
||||
case NSNewlineCharacter:
|
||||
case NSCarriageReturnCharacter:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_RETURN);
|
||||
kinc_internal_keyboard_trigger_key_press('\n');
|
||||
break;
|
||||
case 0x7f:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_BACKSPACE);
|
||||
kinc_internal_keyboard_trigger_key_press('\x08');
|
||||
break;
|
||||
case 9:
|
||||
kinc_internal_keyboard_trigger_key_down(KINC_KEY_TAB);
|
||||
kinc_internal_keyboard_trigger_key_press('\t');
|
||||
break;
|
||||
default:
|
||||
if (ch == 'x' && [theEvent modifierFlags] & NSCommandKeyMask) {
|
||||
char *text = kinc_internal_cut_callback();
|
||||
if (text != NULL) {
|
||||
NSPasteboard *board = [NSPasteboard generalPasteboard];
|
||||
[board clearContents];
|
||||
[board setString:[NSString stringWithUTF8String:text] forType:NSStringPboardType];
|
||||
}
|
||||
}
|
||||
if (ch == 'c' && [theEvent modifierFlags] & NSCommandKeyMask) {
|
||||
char *text = kinc_internal_copy_callback();
|
||||
if (text != NULL) {
|
||||
NSPasteboard *board = [NSPasteboard generalPasteboard];
|
||||
[board clearContents];
|
||||
[board setString:[NSString stringWithUTF8String:text] forType:NSStringPboardType];
|
||||
}
|
||||
}
|
||||
if (ch == 'v' && [theEvent modifierFlags] & NSCommandKeyMask) {
|
||||
NSPasteboard *board = [NSPasteboard generalPasteboard];
|
||||
NSString *data = [board stringForType:NSStringPboardType];
|
||||
if (data != nil) {
|
||||
char charData[4096];
|
||||
strcpy(charData, [data UTF8String]);
|
||||
kinc_internal_paste_callback(charData);
|
||||
}
|
||||
}
|
||||
if (ch >= L'a' && ch <= L'z') {
|
||||
kinc_internal_keyboard_trigger_key_down(ch - L'a' + KINC_KEY_A);
|
||||
}
|
||||
else if (ch >= L'A' && ch <= L'Z') {
|
||||
kinc_internal_keyboard_trigger_key_down(ch - L'A' + KINC_KEY_A);
|
||||
}
|
||||
else if (ch >= L'0' && ch <= L'9') {
|
||||
kinc_internal_keyboard_trigger_key_down(ch - L'0' + KINC_KEY_0);
|
||||
}
|
||||
kinc_internal_keyboard_trigger_key_press(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)theEvent {
|
||||
NSString *characters = [theEvent charactersIgnoringModifiers];
|
||||
if ([characters length]) {
|
||||
unichar ch = [characters characterAtIndex:0];
|
||||
switch (ch) {
|
||||
case 59:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_SEMICOLON);
|
||||
break;
|
||||
case 91:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_OPEN_BRACKET);
|
||||
break;
|
||||
case 93:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_CLOSE_BRACKET);
|
||||
break;
|
||||
case 39:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_QUOTE);
|
||||
break;
|
||||
case 92:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_BACK_SLASH);
|
||||
break;
|
||||
case 44:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_COMMA);
|
||||
break;
|
||||
case 46:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_PERIOD);
|
||||
break;
|
||||
case 47:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_SLASH);
|
||||
break;
|
||||
case 96:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_BACK_QUOTE);
|
||||
break;
|
||||
case 45:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_HYPHEN_MINUS);
|
||||
break;
|
||||
case 61:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_EQUALS);
|
||||
break;
|
||||
case NSRightArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_RIGHT);
|
||||
break;
|
||||
case NSLeftArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_LEFT);
|
||||
break;
|
||||
case NSUpArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_UP);
|
||||
break;
|
||||
case NSDownArrowFunctionKey:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_DOWN);
|
||||
break;
|
||||
case 27:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_ESCAPE);
|
||||
break;
|
||||
case NSEnterCharacter:
|
||||
case NSNewlineCharacter:
|
||||
case NSCarriageReturnCharacter:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_RETURN);
|
||||
break;
|
||||
case 0x7f:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_BACKSPACE);
|
||||
break;
|
||||
case 9:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_TAB);
|
||||
break;
|
||||
case 32:
|
||||
kinc_internal_keyboard_trigger_key_up(KINC_KEY_SPACE);
|
||||
break;
|
||||
default:
|
||||
if (ch >= L'a' && ch <= L'z') {
|
||||
kinc_internal_keyboard_trigger_key_up(ch - L'a' + KINC_KEY_A);
|
||||
}
|
||||
else if (ch >= L'A' && ch <= L'Z') {
|
||||
kinc_internal_keyboard_trigger_key_up(ch - L'A' + KINC_KEY_A);
|
||||
}
|
||||
else if (ch >= L'0' && ch <= L'9') {
|
||||
kinc_internal_keyboard_trigger_key_up(ch - L'0' + KINC_KEY_0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int getMouseX(NSEvent *event) {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
NSWindow *window = [[NSApplication sharedApplication] mainWindow];
|
||||
float scale = [window backingScaleFactor];
|
||||
return (int)([event locationInWindow].x * scale);
|
||||
}
|
||||
|
||||
static int getMouseY(NSEvent *event) {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
NSWindow *window = [[NSApplication sharedApplication] mainWindow];
|
||||
float scale = [window backingScaleFactor];
|
||||
return (int)(kinc_height() - [event locationInWindow].y * scale);
|
||||
}
|
||||
|
||||
static bool controlKeyMouseButton = false;
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
if ([theEvent modifierFlags] & NSControlKeyMask) {
|
||||
controlKeyMouseButton = true;
|
||||
kinc_internal_mouse_trigger_press(0, 1, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
else {
|
||||
controlKeyMouseButton = false;
|
||||
kinc_internal_mouse_trigger_press(0, 0, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
if ([theEvent subtype] == NSTabletPointEventSubtype) {
|
||||
kinc_internal_pen_trigger_press(0, getMouseX(theEvent), getMouseY(theEvent), theEvent.pressure);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
if (controlKeyMouseButton) {
|
||||
kinc_internal_mouse_trigger_release(0, 1, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
else {
|
||||
kinc_internal_mouse_trigger_release(0, 0, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
controlKeyMouseButton = false;
|
||||
|
||||
if ([theEvent subtype] == NSTabletPointEventSubtype) {
|
||||
kinc_internal_pen_trigger_release(0, getMouseX(theEvent), getMouseY(theEvent), theEvent.pressure);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
kinc_internal_mouse_trigger_move(0, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
kinc_internal_mouse_trigger_move(0, getMouseX(theEvent), getMouseY(theEvent));
|
||||
|
||||
if ([theEvent subtype] == NSTabletPointEventSubtype) {
|
||||
kinc_internal_pen_trigger_move(0, getMouseX(theEvent), getMouseY(theEvent), theEvent.pressure);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
kinc_internal_mouse_trigger_press(0, 1, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
- (void)rightMouseUp:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
kinc_internal_mouse_trigger_release(0, 1, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
- (void)rightMouseDragged:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
kinc_internal_mouse_trigger_move(0, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)theEvent {
|
||||
kinc_internal_mouse_trigger_press(0, 2, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
- (void)otherMouseUp:(NSEvent *)theEvent {
|
||||
kinc_internal_mouse_trigger_release(0, 2, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
- (void)otherMouseDragged:(NSEvent *)theEvent {
|
||||
kinc_internal_mouse_trigger_move(0, getMouseX(theEvent), getMouseY(theEvent));
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)theEvent {
|
||||
// TODO (DK) map [theEvent window] to window id instead of 0
|
||||
int delta = [theEvent deltaY];
|
||||
kinc_internal_mouse_trigger_scroll(0, -delta);
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
|
||||
NSPasteboard *pboard = [sender draggingPasteboard];
|
||||
NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
|
||||
if ([[pboard types] containsObject:NSURLPboardType]) {
|
||||
if (sourceDragMask & NSDragOperationLink) {
|
||||
return NSDragOperationLink;
|
||||
}
|
||||
}
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
|
||||
NSPasteboard *pboard = [sender draggingPasteboard];
|
||||
// NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
|
||||
if ([[pboard types] containsObject:NSURLPboardType]) {
|
||||
NSURL *fileURL = [NSURL URLFromPasteboard:pboard];
|
||||
wchar_t *filePath = (wchar_t *)[fileURL.path cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
|
||||
kinc_internal_drop_files_callback(filePath);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#ifndef KINC_METAL
|
||||
- (void)prepareOpenGL {
|
||||
const GLint swapInt = 1;
|
||||
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||
[super prepareOpenGL];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)update { // window resizes, moves and display changes (resize, depth and display config change)
|
||||
#ifdef KINC_OPENGL
|
||||
[super update];
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef KINC_METAL
|
||||
- (id)initWithFrame:(NSRect)frameRect {
|
||||
NSOpenGLPixelFormat *pf = [BasicOpenGLView basicPixelFormat];
|
||||
self = [super initWithFrame:frameRect pixelFormat:pf];
|
||||
|
||||
[self prepareOpenGL];
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
[self setWantsBestResolutionOpenGLSurface:YES];
|
||||
return self;
|
||||
}
|
||||
#else
|
||||
|
||||
- (id)initWithFrame:(NSRect)frameRect {
|
||||
self = [super initWithFrame:frameRect];
|
||||
|
||||
device = MTLCreateSystemDefaultDevice();
|
||||
commandQueue = [device newCommandQueue];
|
||||
library = [device newDefaultLibrary];
|
||||
|
||||
CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer;
|
||||
|
||||
metalLayer.device = device;
|
||||
metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
metalLayer.framebufferOnly = YES;
|
||||
// metalLayer.presentsWithTransaction = YES;
|
||||
|
||||
metalLayer.opaque = YES;
|
||||
metalLayer.backgroundColor = nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (BOOL)acceptsFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)resize:(NSSize)size {
|
||||
[self setFrameSize:size];
|
||||
}
|
||||
|
||||
#ifdef KINC_METAL
|
||||
- (CAMetalLayer *)metalLayer {
|
||||
return (CAMetalLayer *)self.layer;
|
||||
}
|
||||
|
||||
- (id<MTLDevice>)metalDevice {
|
||||
return device;
|
||||
}
|
||||
|
||||
- (id<MTLLibrary>)metalLibrary {
|
||||
return library;
|
||||
}
|
||||
|
||||
- (id<MTLCommandQueue>)metalQueue {
|
||||
return commandQueue;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
void kinc_copy_to_clipboard(const char *text) {
|
||||
NSPasteboard *board = [NSPasteboard generalPasteboard];
|
||||
[board clearContents];
|
||||
[board setString:[NSString stringWithUTF8String:text] forType:NSStringPboardType];
|
||||
}
|
@ -0,0 +1,384 @@
|
||||
#include "HIDGamepad.h"
|
||||
#include "HIDManager.h"
|
||||
|
||||
#include <kinc/error.h>
|
||||
#include <kinc/input/gamepad.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef);
|
||||
static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender);
|
||||
|
||||
static void reset(struct HIDGamepad *gamepad);
|
||||
|
||||
static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements);
|
||||
|
||||
static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex);
|
||||
static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex);
|
||||
|
||||
static bool debugButtonInput = false;
|
||||
|
||||
static void logButton(int buttonIndex, bool pressed) {
|
||||
switch (buttonIndex) {
|
||||
case 0:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "A Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "B Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "X Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Y Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Lb Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Rb Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Left Stick Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Right Stick Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Start Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Back Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Home Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Up Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Down Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Left Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
case 14:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Right Pressed %i", pressed);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool debugAxisInput = false;
|
||||
|
||||
static void logAxis(int axisIndex) {
|
||||
switch (axisIndex) {
|
||||
case 0:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Left stick X");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Left stick Y");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Right stick X");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Right stick Y");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Left trigger");
|
||||
break;
|
||||
|
||||
case 5:
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Right trigger");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to copy a CFStringRef to a cstring buffer.
|
||||
// CFStringRef is converted to UTF8 and as many characters as possible are
|
||||
// placed into the buffer followed by a null terminator.
|
||||
// The buffer is set to an empty string if the conversion fails.
|
||||
static void cstringFromCFStringRef(CFStringRef string, char *cstr, size_t clen) {
|
||||
cstr[0] = '\0';
|
||||
if (string != NULL) {
|
||||
char temp[256];
|
||||
if (CFStringGetCString(string, temp, 256, kCFStringEncodingUTF8)) {
|
||||
temp[kinc_mini(255, (int)(clen - 1))] = '\0';
|
||||
strncpy(cstr, temp, clen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HIDGamepad_init(struct HIDGamepad *gamepad) {
|
||||
reset(gamepad);
|
||||
}
|
||||
|
||||
void HIDGamepad_destroy(struct HIDGamepad *gamepad) {
|
||||
HIDGamepad_unbind(gamepad);
|
||||
}
|
||||
|
||||
void HIDGamepad_bind(struct HIDGamepad *gamepad, IOHIDDeviceRef inDeviceRef, int inPadIndex) {
|
||||
kinc_affirm(inDeviceRef != NULL);
|
||||
kinc_affirm(inPadIndex >= 0);
|
||||
kinc_affirm(gamepad->hidDeviceRef == NULL);
|
||||
kinc_affirm(gamepad->hidQueueRef == NULL);
|
||||
kinc_affirm(gamepad->padIndex == -1);
|
||||
|
||||
// Set device and device index
|
||||
gamepad->hidDeviceRef = inDeviceRef;
|
||||
gamepad->padIndex = inPadIndex;
|
||||
|
||||
// Initialise HID Device
|
||||
// ...open device
|
||||
IOHIDDeviceOpen(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
|
||||
|
||||
// ..register callbacks
|
||||
IOHIDDeviceRegisterInputValueCallback(gamepad->hidDeviceRef, inputValueCallback, gamepad);
|
||||
IOHIDDeviceScheduleWithRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
// ...create a queue to access element values
|
||||
gamepad->hidQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, gamepad->hidDeviceRef, 32, kIOHIDOptionsTypeNone);
|
||||
if (CFGetTypeID(gamepad->hidQueueRef) == IOHIDQueueGetTypeID()) {
|
||||
IOHIDQueueStart(gamepad->hidQueueRef);
|
||||
IOHIDQueueRegisterValueAvailableCallback(gamepad->hidQueueRef, valueAvailableCallback, gamepad);
|
||||
IOHIDQueueScheduleWithRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
}
|
||||
|
||||
// ...get all elements (buttons, axes)
|
||||
CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(gamepad->hidDeviceRef, NULL, kIOHIDOptionsTypeNone);
|
||||
initDeviceElements(gamepad, elementCFArrayRef);
|
||||
|
||||
// ...get device manufacturer and product details
|
||||
{
|
||||
CFNumberRef vendorIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDVendorIDKey));
|
||||
CFNumberGetValue(vendorIdRef, kCFNumberIntType, &gamepad->hidDeviceVendorID);
|
||||
|
||||
CFNumberRef productIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductIDKey));
|
||||
CFNumberGetValue(productIdRef, kCFNumberIntType, &gamepad->hidDeviceProductID);
|
||||
|
||||
CFStringRef vendorRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDManufacturerKey));
|
||||
cstringFromCFStringRef(vendorRef, gamepad->hidDeviceVendor, sizeof(gamepad->hidDeviceVendor));
|
||||
|
||||
CFStringRef productRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductKey));
|
||||
cstringFromCFStringRef(productRef, gamepad->hidDeviceProduct, sizeof(gamepad->hidDeviceProduct));
|
||||
}
|
||||
|
||||
// Initialise Kore::Gamepad for this HID Device
|
||||
//**
|
||||
/*Gamepad *gamepad = Gamepad::get(padIndex);
|
||||
gamepad->vendor = hidDeviceVendor;
|
||||
gamepad->productName = hidDeviceProduct;*/
|
||||
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "HIDGamepad.bind: <%p> idx:%d [0x%x:0x%x] [%s] [%s]", inDeviceRef, gamepad->padIndex, gamepad->hidDeviceVendorID,
|
||||
gamepad->hidDeviceProductID, gamepad->hidDeviceVendor, gamepad->hidDeviceProduct);
|
||||
}
|
||||
|
||||
static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements) {
|
||||
kinc_affirm(elements != NULL);
|
||||
|
||||
for (CFIndex i = 0, count = CFArrayGetCount(elements); i < count; ++i) {
|
||||
IOHIDElementRef elementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
||||
IOHIDElementType elemType = IOHIDElementGetType(elementRef);
|
||||
|
||||
IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
|
||||
|
||||
uint32_t usagePage = IOHIDElementGetUsagePage(elementRef);
|
||||
uint32_t usage = IOHIDElementGetUsage(elementRef);
|
||||
|
||||
// Match up items
|
||||
switch (usagePage) {
|
||||
case kHIDPage_GenericDesktop:
|
||||
switch (usage) {
|
||||
case kHIDUsage_GD_X: // Left stick X
|
||||
// log(Info, "Left stick X axis[0] = %i", cookie);
|
||||
gamepad->axis[0] = cookie;
|
||||
break;
|
||||
case kHIDUsage_GD_Y: // Left stick Y
|
||||
// log(Info, "Left stick Y axis[1] = %i", cookie);
|
||||
gamepad->axis[1] = cookie;
|
||||
break;
|
||||
case kHIDUsage_GD_Z: // Left trigger
|
||||
// log(Info, "Left trigger axis[4] = %i", cookie);
|
||||
gamepad->axis[4] = cookie;
|
||||
break;
|
||||
case kHIDUsage_GD_Rx: // Right stick X
|
||||
// log(Info, "Right stick X axis[2] = %i", cookie);
|
||||
gamepad->axis[2] = cookie;
|
||||
break;
|
||||
case kHIDUsage_GD_Ry: // Right stick Y
|
||||
// log(Info, "Right stick Y axis[3] = %i", cookie);
|
||||
gamepad->axis[3] = cookie;
|
||||
break;
|
||||
case kHIDUsage_GD_Rz: // Right trigger
|
||||
// log(Info, "Right trigger axis[5] = %i", cookie);
|
||||
gamepad->axis[5] = cookie;
|
||||
break;
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kHIDPage_Button:
|
||||
if ((usage >= 1) && (usage <= 15)) {
|
||||
// Button 1-11
|
||||
gamepad->buttons[usage - 1] = cookie;
|
||||
// log(Info, "Button %i = %i", usage-1, cookie);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (elemType == kIOHIDElementTypeInput_Misc || elemType == kIOHIDElementTypeInput_Button || elemType == kIOHIDElementTypeInput_Axis) {
|
||||
if (!IOHIDQueueContainsElement(gamepad->hidQueueRef, elementRef))
|
||||
IOHIDQueueAddElement(gamepad->hidQueueRef, elementRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HIDGamepad_unbind(struct HIDGamepad *gamepad) {
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "HIDGamepad.unbind: idx:%d [0x%x:0x%x] [%s] [%s]", gamepad->padIndex, gamepad->hidDeviceVendorID, gamepad->hidDeviceProductID,
|
||||
gamepad->hidDeviceVendor, gamepad->hidDeviceProduct);
|
||||
|
||||
if (gamepad->hidQueueRef) {
|
||||
IOHIDQueueStop(gamepad->hidQueueRef);
|
||||
IOHIDQueueUnscheduleFromRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
}
|
||||
|
||||
if (gamepad->hidDeviceRef) {
|
||||
IOHIDDeviceUnscheduleFromRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDDeviceClose(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
|
||||
}
|
||||
|
||||
if (gamepad->padIndex >= 0) {
|
||||
//**
|
||||
/*Gamepad *gamepad = Gamepad::get(padIndex);
|
||||
gamepad->vendor = nullptr;
|
||||
gamepad->productName = nullptr;*/
|
||||
}
|
||||
|
||||
reset(gamepad);
|
||||
}
|
||||
|
||||
static void reset(struct HIDGamepad *gamepad) {
|
||||
gamepad->padIndex = -1;
|
||||
gamepad->hidDeviceRef = NULL;
|
||||
gamepad->hidQueueRef = NULL;
|
||||
gamepad->hidDeviceVendor[0] = '\0';
|
||||
gamepad->hidDeviceProduct[0] = '\0';
|
||||
gamepad->hidDeviceVendorID = 0;
|
||||
gamepad->hidDeviceProductID = 0;
|
||||
|
||||
memset(gamepad->axis, 0, sizeof(gamepad->axis));
|
||||
memset(gamepad->buttons, 0, sizeof(gamepad->buttons));
|
||||
}
|
||||
|
||||
static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex) {
|
||||
// double rawValue = IOHIDValueGetIntegerValue(valueRef);
|
||||
double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
|
||||
|
||||
// Normalize button value to the range [0.0, 1.0] (0 - release, 1 - pressed)
|
||||
double min = IOHIDElementGetLogicalMin(elementRef);
|
||||
double max = IOHIDElementGetLogicalMax(elementRef);
|
||||
double normalize = (rawValue - min) / (max - min);
|
||||
|
||||
// log(Info, "%f %f %f %f", rawValue, min, max, normalize);
|
||||
|
||||
kinc_internal_gamepad_trigger_button(gamepad->padIndex, buttonIndex, normalize);
|
||||
|
||||
if (debugButtonInput)
|
||||
logButton(buttonIndex, (normalize != 0));
|
||||
}
|
||||
|
||||
static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex) {
|
||||
// double rawValue = IOHIDValueGetIntegerValue(valueRef);
|
||||
double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
|
||||
|
||||
// Normalize axis value to the range [-1.0, 1.0] (e.g. -1 - left, 0 - release, 1 - right)
|
||||
double min = IOHIDElementGetPhysicalMin(elementRef);
|
||||
double max = IOHIDElementGetPhysicalMax(elementRef);
|
||||
double normalize = normalize = (((rawValue - min) / (max - min)) * 2) - 1;
|
||||
|
||||
// Invert Y axis
|
||||
if (axisIndex % 2 == 1)
|
||||
normalize = -normalize;
|
||||
|
||||
// log(Info, "%f %f %f %f", rawValue, min, max, normalize);
|
||||
|
||||
kinc_internal_gamepad_trigger_axis(gamepad->padIndex, axisIndex, normalize);
|
||||
|
||||
if (debugAxisInput)
|
||||
logAxis(axisIndex);
|
||||
}
|
||||
|
||||
static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef) {}
|
||||
|
||||
static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender) {
|
||||
struct HIDGamepad *pad = (struct HIDGamepad *)inContext;
|
||||
do {
|
||||
IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout((IOHIDQueueRef)inSender, 0.);
|
||||
if (!valueRef)
|
||||
break;
|
||||
|
||||
// process the HID value reference
|
||||
IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
|
||||
// IOHIDElementType elemType = IOHIDElementGetType(elementRef);
|
||||
// log(Info, "Type %d %d\n", elemType, elementRef);
|
||||
|
||||
IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
|
||||
// uint32_t page = IOHIDElementGetUsagePage(elementRef);
|
||||
// uint32_t usage = IOHIDElementGetUsage(elementRef);
|
||||
// log(Info, "page %i, usage %i cookie %i", page, usage, cookie);
|
||||
|
||||
// Check button
|
||||
for (int i = 0, c = sizeof(pad->buttons); i < c; ++i) {
|
||||
if (cookie == pad->buttons[i]) {
|
||||
buttonChanged(pad, elementRef, valueRef, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check axes
|
||||
for (int i = 0, c = sizeof(pad->axis); i < c; ++i) {
|
||||
if (cookie == pad->axis[i]) {
|
||||
axisChanged(pad, elementRef, valueRef, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(valueRef);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
const char *kinc_gamepad_vendor(int gamepad) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
const char *kinc_gamepad_product_name(int gamepad) {
|
||||
return "unknown";
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/hid/IOHIDKeys.h>
|
||||
#include <IOKit/hid/IOHIDManager.h>
|
||||
|
||||
struct HIDGamepad {
|
||||
int padIndex;
|
||||
IOHIDDeviceRef hidDeviceRef;
|
||||
IOHIDQueueRef hidQueueRef;
|
||||
int hidDeviceVendorID;
|
||||
int hidDeviceProductID;
|
||||
char hidDeviceVendor[64];
|
||||
char hidDeviceProduct[64];
|
||||
|
||||
IOHIDElementCookie axis[6];
|
||||
IOHIDElementCookie buttons[15];
|
||||
};
|
||||
|
||||
void HIDGamepad_init(struct HIDGamepad *gamepad);
|
||||
void HIDGamepad_destroy(struct HIDGamepad *gamepad);
|
||||
void HIDGamepad_bind(struct HIDGamepad *gamepad, IOHIDDeviceRef deviceRef, int padIndex);
|
||||
void HIDGamepad_unbind(struct HIDGamepad *gamepad);
|
@ -0,0 +1,140 @@
|
||||
#include <kinc/backend/HIDManager.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
static int initHIDManager(struct HIDManager *manager);
|
||||
static bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef);
|
||||
static CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage);
|
||||
|
||||
static void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
static void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
void HIDManager_init(struct HIDManager *manager) {
|
||||
manager->managerRef = 0x0;
|
||||
initHIDManager(manager);
|
||||
}
|
||||
|
||||
void HIDManager_destroy(struct HIDManager *manager) {
|
||||
if (manager->managerRef) {
|
||||
IOHIDManagerUnscheduleFromRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDManagerClose(manager->managerRef, kIOHIDOptionsTypeNone);
|
||||
}
|
||||
}
|
||||
|
||||
static int initHIDManager(struct HIDManager *manager) {
|
||||
// Initialize the IOHIDManager
|
||||
manager->managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
||||
if (CFGetTypeID(manager->managerRef) == IOHIDManagerGetTypeID()) {
|
||||
|
||||
// Create a matching dictionary for gamepads and joysticks
|
||||
CFMutableArrayRef matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
if (matchingCFArrayRef) {
|
||||
// Create a device matching dictionary for joysticks
|
||||
CFDictionaryRef matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
|
||||
addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
|
||||
|
||||
// Create a device matching dictionary for game pads
|
||||
matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
|
||||
addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
|
||||
}
|
||||
else {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "%s: CFArrayCreateMutable failed.", __PRETTY_FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the HID device matching array
|
||||
IOHIDManagerSetDeviceMatchingMultiple(manager->managerRef, matchingCFArrayRef);
|
||||
CFRelease(matchingCFArrayRef);
|
||||
|
||||
// Open manager
|
||||
IOHIDManagerOpen(manager->managerRef, kIOHIDOptionsTypeNone);
|
||||
|
||||
// Register routines to be called when (matching) devices are connected or disconnected
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(manager->managerRef, deviceConnected, manager);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(manager->managerRef, deviceRemoved, manager);
|
||||
|
||||
IOHIDManagerScheduleWithRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef) {
|
||||
if (matchingCFDictRef) {
|
||||
// Add it to the matching array
|
||||
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||
CFRelease(matchingCFDictRef); // and release it
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage) {
|
||||
// Create a dictionary to add usage page/usages to
|
||||
CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
if (result) {
|
||||
if (inUsagePage) {
|
||||
// Add key for device type to refine the matching dictionary.
|
||||
CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage);
|
||||
if (pageCFNumberRef) {
|
||||
CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsagePageKey), pageCFNumberRef);
|
||||
CFRelease(pageCFNumberRef);
|
||||
|
||||
// note: the usage is only valid if the usage page is also defined
|
||||
if (inUsage) {
|
||||
CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage);
|
||||
if (usageCFNumberRef) {
|
||||
CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef);
|
||||
CFRelease(usageCFNumberRef);
|
||||
}
|
||||
else {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "%s: CFNumberCreate(usage) failed.", __PRETTY_FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "%s: CFNumberCreate(usage page) failed.", __PRETTY_FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// HID device plugged callback
|
||||
void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
// Reference manager
|
||||
struct HIDManager *manager = (struct HIDManager *)inContext;
|
||||
|
||||
// Find an empty slot in the devices list and add the new device there
|
||||
// TODO: does this need to be made thread safe?
|
||||
struct HIDManagerDeviceRecord *device = &manager->devices[0];
|
||||
for (int i = 0; i < KINC_MAX_HID_DEVICES; ++i, ++device) {
|
||||
if (!device->connected) {
|
||||
device->connected = true;
|
||||
device->device = inIOHIDDeviceRef;
|
||||
HIDGamepad_bind(&device->pad, inIOHIDDeviceRef, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HID device unplugged callback
|
||||
void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
// Reference manager
|
||||
struct HIDManager *manager = (struct HIDManager *)inContext;
|
||||
|
||||
// TODO: does this need to be made thread safe?
|
||||
struct HIDManagerDeviceRecord *device = &manager->devices[0];
|
||||
for (int i = 0; i < KINC_MAX_HID_DEVICES; ++i, ++device) {
|
||||
// TODO: is comparing IOHIDDeviceRef to match devices safe? Is there a better way?
|
||||
if (device->connected && device->device == inIOHIDDeviceRef) {
|
||||
device->connected = false;
|
||||
device->device = NULL;
|
||||
HIDGamepad_unbind(&device->pad);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/hid/IOHIDKeys.h>
|
||||
#include <IOKit/hid/IOHIDManager.h>
|
||||
|
||||
#include "HIDGamepad.h"
|
||||
|
||||
// Maximum number of devices supported
|
||||
// Corresponds to size of Kore::Gamepad array
|
||||
static const int KINC_MAX_HID_DEVICES = 12;
|
||||
|
||||
// Slots to hold details on connected devices
|
||||
struct HIDManagerDeviceRecord {
|
||||
bool connected; // = false;
|
||||
IOHIDDeviceRef device; // = NULL;
|
||||
struct HIDGamepad pad;
|
||||
};
|
||||
|
||||
struct HIDManager {
|
||||
IOHIDManagerRef managerRef;
|
||||
struct HIDManagerDeviceRecord devices[KINC_MAX_HID_DEVICES];
|
||||
};
|
||||
|
||||
void HIDManager_init(struct HIDManager *manager);
|
||||
void HIDManager_destroy(struct HIDManager *manager);
|
158
Kha/Kinc/Backends/System/macOS/Sources/kinc/backend/audio.c.h
Normal file
158
Kha/Kinc/Backends/System/macOS/Sources/kinc/backend/audio.c.h
Normal file
@ -0,0 +1,158 @@
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include <kinc/audio2/audio.h>
|
||||
#include <kinc/backend/video.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static kinc_internal_video_sound_stream_t *video = NULL;
|
||||
|
||||
void macPlayVideoSoundStream(kinc_internal_video_sound_stream_t *v) {
|
||||
video = v;
|
||||
}
|
||||
|
||||
void macStopVideoSoundStream(void) {
|
||||
video = NULL;
|
||||
}
|
||||
|
||||
static void affirm(OSStatus err) {
|
||||
if (err != kAudioHardwareNoError) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Error: %i\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
static bool initialized;
|
||||
static bool soundPlaying;
|
||||
static AudioDeviceID device;
|
||||
static UInt32 deviceBufferSize;
|
||||
static UInt32 size;
|
||||
static AudioStreamBasicDescription deviceFormat;
|
||||
static AudioObjectPropertyAddress address;
|
||||
|
||||
static AudioDeviceIOProcID theIOProcID = NULL;
|
||||
|
||||
static kinc_a2_buffer_t a2_buffer;
|
||||
|
||||
static uint32_t samples_per_second = 44100;
|
||||
|
||||
uint32_t kinc_a2_samples_per_second(void) {
|
||||
return samples_per_second;
|
||||
}
|
||||
|
||||
static void copySample(void *buffer) {
|
||||
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
|
||||
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
|
||||
a2_buffer.read_location += 1;
|
||||
if (a2_buffer.read_location >= a2_buffer.data_size) {
|
||||
a2_buffer.read_location = 0;
|
||||
}
|
||||
((float *)buffer)[0] = left_value;
|
||||
((float *)buffer)[1] = right_value;
|
||||
}
|
||||
|
||||
static OSStatus appIOProc(AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime,
|
||||
AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *userdata) {
|
||||
affirm(AudioObjectGetPropertyData(device, &address, 0, NULL, &size, &deviceFormat));
|
||||
if (samples_per_second != (int)deviceFormat.mSampleRate) {
|
||||
samples_per_second = (int)deviceFormat.mSampleRate;
|
||||
kinc_a2_internal_sample_rate_callback();
|
||||
}
|
||||
int num_frames = deviceBufferSize / deviceFormat.mBytesPerFrame;
|
||||
kinc_a2_internal_callback(&a2_buffer, num_frames);
|
||||
float *output = (float *)outOutputData->mBuffers[0].mData;
|
||||
for (int i = 0; i < num_frames; ++i) {
|
||||
copySample(output);
|
||||
output += 2;
|
||||
}
|
||||
return kAudioHardwareNoError;
|
||||
}
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
void kinc_a2_init(void) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
kinc_a2_internal_init();
|
||||
initialized = true;
|
||||
|
||||
a2_buffer.read_location = 0;
|
||||
a2_buffer.write_location = 0;
|
||||
a2_buffer.data_size = 128 * 1024;
|
||||
a2_buffer.channel_count = 2;
|
||||
a2_buffer.channels[0] = (float *)malloc(a2_buffer.data_size * sizeof(float));
|
||||
a2_buffer.channels[1] = (float *)malloc(a2_buffer.data_size * sizeof(float));
|
||||
|
||||
device = kAudioDeviceUnknown;
|
||||
|
||||
initialized = false;
|
||||
|
||||
size = sizeof(AudioDeviceID);
|
||||
address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
||||
address.mScope = kAudioObjectPropertyScopeGlobal;
|
||||
address.mElement = kAudioObjectPropertyElementMaster;
|
||||
affirm(AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, &size, &device));
|
||||
|
||||
size = sizeof(UInt32);
|
||||
address.mSelector = kAudioDevicePropertyBufferSize;
|
||||
address.mScope = kAudioDevicePropertyScopeOutput;
|
||||
affirm(AudioObjectGetPropertyData(device, &address, 0, NULL, &size, &deviceBufferSize));
|
||||
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "deviceBufferSize = %i\n", deviceBufferSize);
|
||||
|
||||
size = sizeof(AudioStreamBasicDescription);
|
||||
address.mSelector = kAudioDevicePropertyStreamFormat;
|
||||
address.mScope = kAudioDevicePropertyScopeOutput;
|
||||
|
||||
affirm(AudioObjectGetPropertyData(device, &address, 0, NULL, &size, &deviceFormat));
|
||||
|
||||
if (deviceFormat.mFormatID != kAudioFormatLinearPCM) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "mFormatID != kAudioFormatLinearPCM\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(deviceFormat.mFormatFlags & kLinearPCMFormatFlagIsFloat)) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Only works with float format.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (samples_per_second != (int)deviceFormat.mSampleRate) {
|
||||
samples_per_second = (int)deviceFormat.mSampleRate;
|
||||
kinc_a2_internal_sample_rate_callback();
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "mSampleRate = %g\n", deviceFormat.mSampleRate);
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "mFormatFlags = %08X\n", (unsigned int)deviceFormat.mFormatFlags);
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "mBytesPerPacket = %d\n", (unsigned int)deviceFormat.mBytesPerPacket);
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "mFramesPerPacket = %d\n", (unsigned int)deviceFormat.mFramesPerPacket);
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "mChannelsPerFrame = %d\n", (unsigned int)deviceFormat.mChannelsPerFrame);
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "mBytesPerFrame = %d\n", (unsigned int)deviceFormat.mBytesPerFrame);
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "mBitsPerChannel = %d\n", (unsigned int)deviceFormat.mBitsPerChannel);
|
||||
|
||||
if (soundPlaying)
|
||||
return;
|
||||
|
||||
affirm(AudioDeviceCreateIOProcID(device, appIOProc, NULL, &theIOProcID));
|
||||
affirm(AudioDeviceStart(device, theIOProcID));
|
||||
|
||||
soundPlaying = true;
|
||||
}
|
||||
|
||||
void kinc_a2_update(void) {}
|
||||
|
||||
void kinc_a2_shutdown(void) {
|
||||
if (!initialized)
|
||||
return;
|
||||
if (!soundPlaying)
|
||||
return;
|
||||
|
||||
affirm(AudioDeviceStop(device, theIOProcID));
|
||||
affirm(AudioDeviceDestroyIOProcID(device, theIOProcID));
|
||||
|
||||
soundPlaying = false;
|
||||
}
|
112
Kha/Kinc/Backends/System/macOS/Sources/kinc/backend/display.m.h
Normal file
112
Kha/Kinc/Backends/System/macOS/Sources/kinc/backend/display.m.h
Normal file
@ -0,0 +1,112 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
#define maxDisplays 10
|
||||
// Display displays[maxDisplays];
|
||||
|
||||
/*void initMacDisplays() {
|
||||
for (int i = 0; i < maxDisplays; ++i) {
|
||||
displays[i]._data.index = i;
|
||||
}
|
||||
}*/
|
||||
|
||||
int kinc_count_displays(void) {
|
||||
NSArray *screens = [NSScreen screens];
|
||||
return (int)[screens count];
|
||||
}
|
||||
|
||||
int kinc_primary_display(void) {
|
||||
NSArray *screens = [NSScreen screens];
|
||||
NSScreen *mainScreen = [NSScreen mainScreen];
|
||||
for (int i = 0; i < maxDisplays; ++i) {
|
||||
if (mainScreen == screens[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void kinc_display_init(void) {}
|
||||
|
||||
kinc_display_mode_t kinc_display_available_mode(int display, int mode) {
|
||||
kinc_display_mode_t dm;
|
||||
dm.width = 800;
|
||||
dm.height = 600;
|
||||
dm.frequency = 60;
|
||||
dm.bits_per_pixel = 32;
|
||||
return dm;
|
||||
}
|
||||
|
||||
int kinc_display_count_available_modes(int display) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool kinc_display_available(int display) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *kinc_display_name(int display) {
|
||||
return "Display";
|
||||
}
|
||||
|
||||
kinc_display_mode_t kinc_display_current_mode(int display) {
|
||||
NSArray *screens = [NSScreen screens];
|
||||
NSScreen *screen = screens[display];
|
||||
NSRect screenRect = [screen frame];
|
||||
kinc_display_mode_t dm;
|
||||
dm.width = screenRect.size.width;
|
||||
dm.height = screenRect.size.height;
|
||||
dm.frequency = 60;
|
||||
dm.bits_per_pixel = 32;
|
||||
|
||||
NSDictionary *description = [screen deviceDescription];
|
||||
NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
|
||||
NSNumber *screenNumber = [description objectForKey:@"NSScreenNumber"];
|
||||
CGSize displayPhysicalSize = CGDisplayScreenSize([screenNumber unsignedIntValue]); // in millimeters
|
||||
double ppi = displayPixelSize.width / (displayPhysicalSize.width * 0.039370); // Convert MM to INCH
|
||||
dm.pixels_per_inch = round(ppi);
|
||||
|
||||
return dm;
|
||||
}
|
||||
|
||||
//**
|
||||
/*
|
||||
int Display::x() {
|
||||
NSArray* screens = [NSScreen screens];
|
||||
NSScreen* screen = screens[_data.index];
|
||||
NSRect rect = [screen frame];
|
||||
return rect.origin.x;
|
||||
}
|
||||
|
||||
int Display::y() {
|
||||
NSArray* screens = [NSScreen screens];
|
||||
NSScreen* screen = screens[_data.index];
|
||||
NSRect rect = [screen frame];
|
||||
return rect.origin.y;
|
||||
}
|
||||
|
||||
int Display::width() {
|
||||
NSArray* screenArray = [NSScreen screens];
|
||||
NSScreen* screen = [screenArray objectAtIndex:_data.index];
|
||||
NSRect screenRect = [screen visibleFrame];
|
||||
return screenRect.size.width;
|
||||
}
|
||||
|
||||
int Display::height() {
|
||||
NSArray* screenArray = [NSScreen screens];
|
||||
// unsigned screenCount = [screenArray count];
|
||||
NSScreen* screen = [screenArray objectAtIndex:_data.index];
|
||||
NSRect screenRect = [screen visibleFrame];
|
||||
return screenRect.size.height;
|
||||
}
|
||||
|
||||
int Display::frequency() {
|
||||
return 60;
|
||||
}
|
||||
|
||||
int Display::pixelsPerInch() {
|
||||
return 96;
|
||||
}
|
||||
*/
|
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
struct DisplayData {
|
||||
int index;
|
||||
DisplayData();
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>tech.kode.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2018 the Kore Development Team. All rights reserved.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,24 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
struct WindowData {
|
||||
id handle;
|
||||
id view;
|
||||
bool fullscreen;
|
||||
void (*resizeCallback)(int width, int height, void *data);
|
||||
void *resizeCallbackData;
|
||||
bool (*closeCallback)(void *data);
|
||||
void *closeCallbackData;
|
||||
};
|
||||
|
||||
static struct WindowData windows[10] = {};
|
||||
static int windowCounter = 0;
|
||||
|
||||
#include "BasicOpenGLView.m.h"
|
||||
#include "HIDGamepad.c.h"
|
||||
#include "HIDManager.c.h"
|
||||
#include "audio.c.h"
|
||||
#include "display.m.h"
|
||||
#include "mouse.m.h"
|
||||
#include "system.c.h"
|
||||
#include "system.m.h"
|
||||
#include "window.c.h"
|
@ -0,0 +1,49 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include <kinc/backend/windowdata.h>
|
||||
#include <kinc/input/mouse.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
void kinc_internal_mouse_lock(int window) {
|
||||
kinc_mouse_hide();
|
||||
}
|
||||
|
||||
void kinc_internal_mouse_unlock(void) {
|
||||
kinc_mouse_show();
|
||||
}
|
||||
|
||||
bool kinc_mouse_can_lock(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void kinc_mouse_show(void) {
|
||||
CGDisplayShowCursor(kCGDirectMainDisplay);
|
||||
}
|
||||
|
||||
void kinc_mouse_hide(void) {
|
||||
CGDisplayHideCursor(kCGDirectMainDisplay);
|
||||
}
|
||||
|
||||
void kinc_mouse_set_position(int windowId, int x, int y) {
|
||||
|
||||
NSWindow *window = kinc_get_mac_window_handle(windowId);
|
||||
float scale = [window backingScaleFactor];
|
||||
NSRect rect = [[NSScreen mainScreen] frame];
|
||||
|
||||
CGPoint point;
|
||||
point.x = window.frame.origin.x + (x / scale);
|
||||
point.y = rect.size.height - (window.frame.origin.y + (y / scale));
|
||||
|
||||
CGDisplayMoveCursorToPoint(windowId, point);
|
||||
CGAssociateMouseAndMouseCursorPosition(true);
|
||||
}
|
||||
|
||||
void kinc_mouse_get_position(int windowId, int *x, int *y) {
|
||||
|
||||
NSWindow *window = kinc_get_mac_window_handle(windowId);
|
||||
NSPoint point = [window mouseLocationOutsideOfEventStream];
|
||||
*x = (int)point.x;
|
||||
*y = (int)point.y;
|
||||
}
|
||||
|
||||
void kinc_mouse_set_cursor(int cursor_index) {}
|
@ -0,0 +1,62 @@
|
||||
#include <kinc/graphics4/graphics.h>
|
||||
#include <kinc/input/gamepad.h>
|
||||
#include <kinc/input/keyboard.h>
|
||||
#include <kinc/input/mouse.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/video.h>
|
||||
|
||||
static int mouseX, mouseY;
|
||||
static bool keyboardShown = false;
|
||||
|
||||
void Kinc_Mouse_GetPosition(int window, int *x, int *y) {
|
||||
*x = mouseX;
|
||||
*y = mouseY;
|
||||
}
|
||||
|
||||
void kinc_keyboard_show(void) {
|
||||
keyboardShown = true;
|
||||
}
|
||||
|
||||
void kinc_keyboard_hide(void) {
|
||||
keyboardShown = false;
|
||||
}
|
||||
|
||||
bool kinc_keyboard_active(void) {
|
||||
return keyboardShown;
|
||||
}
|
||||
|
||||
void kinc_vibrate(int ms) {}
|
||||
|
||||
const char *kinc_system_id(void) {
|
||||
return "macOS";
|
||||
}
|
||||
|
||||
static const char *videoFormats[] = {"ogv", NULL};
|
||||
|
||||
const char **kinc_video_formats(void) {
|
||||
return videoFormats;
|
||||
}
|
||||
|
||||
void kinc_set_keep_screen_on(bool on) {}
|
||||
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
double kinc_frequency(void) {
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
return (double)info.denom / (double)info.numer / 1e-9;
|
||||
}
|
||||
|
||||
kinc_ticks_t kinc_timestamp(void) {
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
void kinc_login(void) {}
|
||||
|
||||
void kinc_unlock_achievement(int id) {}
|
||||
|
||||
bool kinc_gamepad_connected(int num) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void kinc_gamepad_rumble(int gamepad, float left, float right) {}
|
331
Kha/Kinc/Backends/System/macOS/Sources/kinc/backend/system.m.h
Normal file
331
Kha/Kinc/Backends/System/macOS/Sources/kinc/backend/system.m.h
Normal file
@ -0,0 +1,331 @@
|
||||
#import "BasicOpenGLView.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include <kinc/backend/HIDManager.h>
|
||||
#include <kinc/graphics4/graphics.h>
|
||||
#include <kinc/input/keyboard.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
#include "windowdata.h"
|
||||
|
||||
#include <kinc/backend/windowdata.h>
|
||||
|
||||
bool withAutoreleasepool(bool (*f)(void)) {
|
||||
@autoreleasepool {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
|
||||
extern const char *macgetresourcepath(void);
|
||||
|
||||
const char *macgetresourcepath(void) {
|
||||
return [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@interface KincApplication : NSApplication {
|
||||
}
|
||||
- (void)terminate:(id)sender;
|
||||
@end
|
||||
|
||||
@interface KincAppDelegate : NSObject <NSWindowDelegate> {
|
||||
}
|
||||
- (void)windowWillClose:(NSNotification *)notification;
|
||||
- (void)windowDidResize:(NSNotification *)notification;
|
||||
- (void)windowWillMiniaturize:(NSNotification *)notification;
|
||||
- (void)windowDidDeminiaturize:(NSNotification *)notification;
|
||||
- (void)windowDidResignMain:(NSNotification *)notification;
|
||||
- (void)windowDidBecomeMain:(NSNotification *)notification;
|
||||
@end
|
||||
|
||||
static NSApplication *myapp;
|
||||
static NSWindow *window;
|
||||
static BasicOpenGLView *view;
|
||||
static KincAppDelegate *delegate;
|
||||
static struct HIDManager *hidManager;
|
||||
|
||||
/*struct KoreWindow : public KoreWindowBase {
|
||||
NSWindow* handle;
|
||||
BasicOpenGLView* view;
|
||||
|
||||
KoreWindow(NSWindow* handle, BasicOpenGLView* view, int x, int y, int width, int height)
|
||||
: KoreWindowBase(x, y, width, height), handle(handle), view(view) {
|
||||
::view = view;
|
||||
}
|
||||
};*/
|
||||
|
||||
#ifdef KINC_METAL
|
||||
CAMetalLayer *getMetalLayer(void) {
|
||||
return [view metalLayer];
|
||||
}
|
||||
|
||||
id getMetalDevice(void) {
|
||||
return [view metalDevice];
|
||||
}
|
||||
|
||||
id getMetalLibrary(void) {
|
||||
return [view metalLibrary];
|
||||
}
|
||||
|
||||
id getMetalQueue(void) {
|
||||
return [view metalQueue];
|
||||
}
|
||||
#endif
|
||||
|
||||
bool kinc_internal_handle_messages(void) {
|
||||
NSEvent *event = [myapp nextEventMatchingMask:NSAnyEventMask
|
||||
untilDate:[NSDate distantPast]
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES]; // distantPast: non-blocking
|
||||
if (event != nil) {
|
||||
[myapp sendEvent:event];
|
||||
[myapp updateWindows];
|
||||
}
|
||||
|
||||
// Sleep for a frame to limit the calls when the window is not visible.
|
||||
if (!window.visible) {
|
||||
[NSThread sleepForTimeInterval:1.0 / 60];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void swapBuffersMac(int windowId) {
|
||||
#ifndef KINC_METAL
|
||||
[windows[windowId].view switchBuffers];
|
||||
#endif
|
||||
}
|
||||
|
||||
static int createWindow(kinc_window_options_t *options) {
|
||||
int width = options->width / [[NSScreen mainScreen] backingScaleFactor];
|
||||
int height = options->height / [[NSScreen mainScreen] backingScaleFactor];
|
||||
int styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
|
||||
if ((options->window_features & KINC_WINDOW_FEATURE_RESIZEABLE) || (options->window_features & KINC_WINDOW_FEATURE_MAXIMIZABLE)) {
|
||||
styleMask |= NSWindowStyleMaskResizable;
|
||||
}
|
||||
if (options->window_features & KINC_WINDOW_FEATURE_MINIMIZABLE) {
|
||||
styleMask |= NSWindowStyleMaskMiniaturizable;
|
||||
}
|
||||
|
||||
view = [[BasicOpenGLView alloc] initWithFrame:NSMakeRect(0, 0, width, height)];
|
||||
[view registerForDraggedTypes:[NSArray arrayWithObjects:NSURLPboardType, nil]];
|
||||
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height) styleMask:styleMask backing:NSBackingStoreBuffered defer:TRUE];
|
||||
delegate = [KincAppDelegate alloc];
|
||||
[window setDelegate:delegate];
|
||||
[window setTitle:[NSString stringWithCString:options->title encoding:NSUTF8StringEncoding]];
|
||||
[window setAcceptsMouseMovedEvents:YES];
|
||||
[[window contentView] addSubview:view];
|
||||
[window center];
|
||||
|
||||
windows[windowCounter].handle = window;
|
||||
windows[windowCounter].view = view;
|
||||
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
|
||||
if (options->mode == KINC_WINDOW_MODE_FULLSCREEN || options->mode == KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
|
||||
[window toggleFullScreen:nil];
|
||||
windows[windowCounter].fullscreen = true;
|
||||
}
|
||||
|
||||
return windowCounter++;
|
||||
}
|
||||
|
||||
int kinc_count_windows(void) {
|
||||
return windowCounter;
|
||||
}
|
||||
|
||||
void kinc_window_change_window_mode(int window_index, kinc_window_mode_t mode) {
|
||||
switch (mode) {
|
||||
case KINC_WINDOW_MODE_WINDOW:
|
||||
if (windows[window_index].fullscreen) {
|
||||
[window toggleFullScreen:nil];
|
||||
windows[window_index].fullscreen = false;
|
||||
}
|
||||
break;
|
||||
case KINC_WINDOW_MODE_FULLSCREEN:
|
||||
case KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
|
||||
if (!windows[window_index].fullscreen) {
|
||||
[window toggleFullScreen:nil];
|
||||
windows[window_index].fullscreen = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_window_set_close_callback(int window, bool (*callback)(void *), void *data) {
|
||||
windows[window].closeCallback = callback;
|
||||
windows[window].closeCallbackData = data;
|
||||
}
|
||||
|
||||
static void addMenubar(void) {
|
||||
NSString *appName = [[NSProcessInfo processInfo] processName];
|
||||
|
||||
NSMenu *appMenu = [NSMenu new];
|
||||
NSString *quitTitle = [@"Quit " stringByAppendingString:appName];
|
||||
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
[appMenu addItem:quitMenuItem];
|
||||
|
||||
NSMenuItem *appMenuItem = [NSMenuItem new];
|
||||
[appMenuItem setSubmenu:appMenu];
|
||||
|
||||
NSMenu *menubar = [NSMenu new];
|
||||
[menubar addItem:appMenuItem];
|
||||
[NSApp setMainMenu:menubar];
|
||||
}
|
||||
|
||||
#ifdef KINC_KONG
|
||||
void kong_init(void);
|
||||
#endif
|
||||
|
||||
int kinc_init(const char *name, int width, int height, kinc_window_options_t *win, kinc_framebuffer_options_t *frame) {
|
||||
@autoreleasepool {
|
||||
myapp = [KincApplication sharedApplication];
|
||||
[myapp finishLaunching];
|
||||
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
|
||||
NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
|
||||
|
||||
hidManager = (struct HIDManager *)malloc(sizeof(struct HIDManager));
|
||||
HIDManager_init(hidManager);
|
||||
addMenubar();
|
||||
}
|
||||
|
||||
// System::_init(name, width, height, &win, &frame);
|
||||
kinc_window_options_t defaultWindowOptions;
|
||||
if (win == NULL) {
|
||||
kinc_window_options_set_defaults(&defaultWindowOptions);
|
||||
win = &defaultWindowOptions;
|
||||
}
|
||||
|
||||
kinc_framebuffer_options_t defaultFramebufferOptions;
|
||||
if (frame == NULL) {
|
||||
kinc_framebuffer_options_set_defaults(&defaultFramebufferOptions);
|
||||
frame = &defaultFramebufferOptions;
|
||||
}
|
||||
|
||||
win->width = width;
|
||||
win->height = height;
|
||||
if (win->title == NULL) {
|
||||
win->title = name;
|
||||
}
|
||||
|
||||
int windowId = createWindow(win);
|
||||
kinc_g4_internal_init();
|
||||
kinc_g4_internal_init_window(windowId, frame->depth_bits, frame->stencil_bits, true);
|
||||
|
||||
#ifdef KINC_KONG
|
||||
kong_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kinc_window_width(int window_index) {
|
||||
NSWindow *window = windows[window_index].handle;
|
||||
float scale = [window backingScaleFactor];
|
||||
return [[window contentView] frame].size.width * scale;
|
||||
}
|
||||
|
||||
int kinc_window_height(int window_index) {
|
||||
NSWindow *window = windows[window_index].handle;
|
||||
float scale = [window backingScaleFactor];
|
||||
return [[window contentView] frame].size.height * scale;
|
||||
}
|
||||
|
||||
NSWindow *kinc_get_mac_window_handle(int window_index) {
|
||||
return windows[window_index].handle;
|
||||
}
|
||||
|
||||
void kinc_load_url(const char *url) {
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithUTF8String:url]]];
|
||||
}
|
||||
|
||||
static char language[3];
|
||||
|
||||
const char *kinc_language(void) {
|
||||
NSString *nsstr = [[NSLocale preferredLanguages] objectAtIndex:0];
|
||||
const char *lang = [nsstr UTF8String];
|
||||
language[0] = lang[0];
|
||||
language[1] = lang[1];
|
||||
language[2] = 0;
|
||||
return language;
|
||||
}
|
||||
|
||||
void kinc_internal_shutdown(void) {}
|
||||
|
||||
static const char *getSavePath(void) {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
NSString *resolvedPath = [paths objectAtIndex:0];
|
||||
NSString *appName = [NSString stringWithUTF8String:kinc_application_name()];
|
||||
resolvedPath = [resolvedPath stringByAppendingPathComponent:appName];
|
||||
|
||||
NSFileManager *fileMgr = [[NSFileManager alloc] init];
|
||||
|
||||
NSError *error;
|
||||
[fileMgr createDirectoryAtPath:resolvedPath withIntermediateDirectories:YES attributes:nil error:&error];
|
||||
|
||||
resolvedPath = [resolvedPath stringByAppendingString:@"/"];
|
||||
return [resolvedPath cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
const char *kinc_internal_save_path(void) {
|
||||
return getSavePath();
|
||||
}
|
||||
|
||||
#ifndef KINC_NO_MAIN
|
||||
int main(int argc, char **argv) {
|
||||
return kickstart(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
@implementation KincApplication
|
||||
|
||||
- (void)terminate:(id)sender {
|
||||
kinc_stop();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation KincAppDelegate
|
||||
- (BOOL)windowShouldClose:(NSWindow *)sender {
|
||||
if (windows[0].closeCallback != NULL) {
|
||||
if (windows[0].closeCallback(windows[0].closeCallbackData)) {
|
||||
return YES;
|
||||
}
|
||||
else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *)notification {
|
||||
kinc_stop();
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification {
|
||||
NSWindow *window = [notification object];
|
||||
NSSize size = [[window contentView] frame].size;
|
||||
[view resize:size];
|
||||
if (windows[0].resizeCallback != NULL) {
|
||||
windows[0].resizeCallback(size.width, size.height, windows[0].resizeCallbackData);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowWillMiniaturize:(NSNotification *)notification {
|
||||
kinc_internal_background_callback();
|
||||
}
|
||||
|
||||
- (void)windowDidDeminiaturize:(NSNotification *)notification {
|
||||
kinc_internal_foreground_callback();
|
||||
}
|
||||
|
||||
- (void)windowDidResignMain:(NSNotification *)notification {
|
||||
kinc_internal_pause_callback();
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeMain:(NSNotification *)notification {
|
||||
kinc_internal_resume_callback();
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,58 @@
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/graphics4/graphics.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
int kinc_window_x(int window) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kinc_window_y(int window) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kinc_window_resize(int window, int width, int height) {}
|
||||
|
||||
void kinc_window_move(int window, int x, int y) {}
|
||||
|
||||
void kinc_internal_change_framebuffer(int window, struct kinc_framebuffer_options *frame);
|
||||
|
||||
void kinc_window_change_framebuffer(int window, struct kinc_framebuffer_options *frame) {
|
||||
kinc_internal_change_framebuffer(0, frame);
|
||||
}
|
||||
|
||||
#ifdef KINC_METAL
|
||||
void kinc_internal_change_framebuffer(int window, struct kinc_framebuffer_options *frame) {}
|
||||
#endif
|
||||
|
||||
void kinc_window_change_features(int window, int features) {}
|
||||
|
||||
void kinc_window_change_mode(int window, kinc_window_mode_t mode) {}
|
||||
|
||||
void kinc_window_destroy(int window) {}
|
||||
|
||||
void kinc_window_show(int window) {}
|
||||
|
||||
void kinc_window_hide(int window) {}
|
||||
|
||||
void kinc_window_set_title(int window, const char *title) {}
|
||||
|
||||
int kinc_window_create(kinc_window_options_t *win, kinc_framebuffer_options_t *frame) {
|
||||
windowCounter += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kinc_window_set_resize_callback(int window, void (*callback)(int x, int y, void *data), void *data) {
|
||||
assert(window < windowCounter);
|
||||
windows[window].resizeCallback = callback;
|
||||
windows[window].resizeCallbackData = data;
|
||||
}
|
||||
|
||||
void kinc_window_set_ppi_changed_callback(int window, void (*callback)(int ppi, void *data), void *data) {}
|
||||
|
||||
kinc_window_mode_t kinc_window_get_mode(int window) {
|
||||
return KINC_WINDOW_MODE_WINDOW;
|
||||
}
|
||||
|
||||
int kinc_window_display(int window) {
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <objc/runtime.h>
|
||||
|
||||
NSWindow *kinc_get_mac_window_handle(int window_index);
|
Reference in New Issue
Block a user