RGFW Di Bawah Hud: Koko dalam Pure C

WBOY
Lepaskan: 2024-08-27 06:40:02
asal
527 orang telah melayarinya

RGFW Under the Hood: Cocoa in Pure C

pengenalan

Untuk menggunakan Apple's Cocoa API, anda mesti menggunakan panggilan fungsi Objective-C. Walau bagaimanapun, anda tidak perlu menulis kod Objective-C kerana Objective-C boleh diakses melalui fungsi C seperti objc_msgSend.

Sebab utama untuk menggunakan Pure-C berbanding Objective-C adalah untuk dapat menyusun projek anda dalam C. Ini berguna jika anda ingin mencipta fail pengepala tunggal yang tidak memerlukan pengguna menyusun menggunakan Objective-C.

Dua contoh ini ialah:

Silicon.h, C-Wrapper untuk API Koko yang menyelubungi fungsi Objective-C memanggil supaya anda boleh menggunakan API Koko dalam kod C yang kelihatan biasa dan RGFW, perpustakaan tetingkap satu tajuk yang ringan.

Kedua-dua projek boleh dijadikan rujukan untuk menggunakan Koko dalam C.

Gambaran keseluruhan

Tinjauan ringkas tentang topik yang akan dibincangkan oleh artikel

1) Asas Penggunaan Objective-C dalam Pure C
2) Menentukan Jenis Koko
3) Mencipta Tetingkap Koko Asas

1. Asas penggunaan Objektif-C dalam C Tulen

Fungsi Objektif-C boleh dipanggil menggunakan objc_msgsend.

Disebabkan perbezaan ABI, ARM menggunakan objc_msgsend untuk semua kes. Walau bagaimanapun, CPU x86_64 memerlukan penggunaan fungsi khusus untuk titik terapung dan pulangan struktur.
objc_msgsend_fpret untuk fungsi dengan pengembalian titik terapung dan
objc_msgsend_fstret untuk fungsi yang mengembalikan struktur.

RGFW mengendalikan ini seperti ini:

#include  #include  #ifdef __arm64__ /* ARM just uses objc_msgSend */ #define abi_objc_msgSend_stret objc_msgSend #define abi_objc_msgSend_fpret objc_msgSend #else /* __i386__ */ /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ #define abi_objc_msgSend_stret objc_msgSend_stret #define abi_objc_msgSend_fpret objc_msgSend_fpret #endif
Salin selepas log masuk

objc_msgSend ialah fungsi generik, jadi jenisnya mesti dihantar berdasarkan jenis pemulangan dan hujah yang anda inginkan.

Contohnya: ((int (*)(id, SEL, int))objc_msgSend) untuk fungsi yang mengambil hujah int dan mengembalikan int.

Untuk mengelakkan pengulangan penghantaran jenis yang biasa digunakan, RGFW mentakrifkan makro untuk mengendalikan kes biasa.

#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend) #define objc_msgSend_id_id ((id (*)(id, SEL, id))objc_msgSend) #define objc_msgSend_id_rect ((id (*)(id, SEL, NSRect))objc_msgSend) #define objc_msgSend_uint ((NSUInteger (*)(id, SEL))objc_msgSend) #define objc_msgSend_int ((NSInteger (*)(id, SEL))objc_msgSend) #define objc_msgSend_SEL ((SEL (*)(id, SEL))objc_msgSend) #define objc_msgSend_float ((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) #define objc_msgSend_bool ((BOOL (*)(id, SEL))objc_msgSend) #define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend) #define objc_msgSend_double ((double (*)(id, SEL))objc_msgSend) #define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend) #define objc_msgSend_void_uint ((void (*)(id, SEL, NSUInteger))objc_msgSend) #define objc_msgSend_void_int ((void (*)(id, SEL, NSInteger))objc_msgSend) #define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend) #define objc_msgSend_void_float ((void (*)(id, SEL, CGFloat))objc_msgSend) #define objc_msgSend_void_double ((void (*)(id, SEL, double))objc_msgSend) #define objc_msgSend_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend) #define objc_msgSend_id_char_const ((id (*)(id, SEL, char const *))objc_msgSend)
Salin selepas log masuk

Anda mungkin melihat dua hujah biasa dalam fungsi ini, id dan SEL

Argumen id merujuk kepada ID objek atau kelas Objektif-C.

SEL merujuk kepada pemilih fungsi.

Sebagai contoh MyObject *bar = [MyObject objectWithString:@"RGFW"]; boleh diterjemahkan kepada id* bar = [id SEL:@"RGFW"];

Untuk mendapatkan ID ke kelas Objektif-C anda mesti menjalankan objc_getClass

Sebagai contoh: objc_getClass("NSWindow");

Untuk mendapatkan pemilih untuk fungsi Objektif-C anda mesti menggunakan sel_registerName

Sintaks fungsi Objektif-C adalah seperti ini , kemudian : digunakan sebagai ruang letak untuk hujah.

Fungsi dengan satu hujah akan kelihatan seperti ini:

sel_registerName("makeKeyAndOrderFront:");

Walau bagaimanapun, fungsi tanpa hujah akan kelihatan seperti ini.

sel_registerName("isKeyWindow");

Jika fungsi mempunyai berbilang argumen, anda juga perlu menambah nama argumen (tidak termasuk argumen pertama)

sel_registerName("initWithContentRect:styleMask:backing:defer:");

Untuk mentakrifkan kaedah kelas (cth. fungsi panggil balik untuk objek) anda mesti menggunakan class_addMethod fungsi ini mengambil kelas perwakilan (kelas objek yang memanggil perwakilan
), pemilih fungsi yang sedang dipanggil, fungsi yang anda mahu dipanggil dan hujah yang dijangkakan dalam format rentetan.

Tetapi pertama, anda mesti memperuntukkan kelas perwakilan untuk mengaksesnya.
Anda boleh melakukan ini menggunakan objc_allocateClassPair.

Sebagai contoh untuk memperuntukkan kelas perwakilan untuk NSWindow:

Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
Salin selepas log masuk

Untuk membuat panggilan balik anda perlu menggunakan class_addMethod untuk menetapkannya sebagai panggilan balik untuk kelas.

Mencipta panggilan balik untuk tetingkap NSWindowWillResize akan kelihatan seperti ini:

class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) windowResize, "{NSSize=ff}@:{NSSize=ff}");
Salin selepas log masuk

Anda juga boleh menambah pembolehubah pengguna tersuai pada kelas, ini boleh digunakan untuk melampirkan data pengguna pada kelas.

Sebagai contoh, RGFW melampirkan RGFW_window pada kelas NSWindow untuk mengubah suai data RGFW_window*. Ini boleh dilakukan menggunakan class_addIvar

class_addIvar( delegateClass, "RGFW_window", sizeof(RGFW_window*), rint(log2(sizeof(RGFW_window*))), "L" );
Salin selepas log masuk

Untuk menetapkan pembolehubah untuk digunakan bagi contoh NSWindow anda, gunakan

objek_setInstanceVariable

Untuk menetapkan objek RGFW_window menjadi contoh pembolehubah untuk objek NSWindownya:

object_setInstanceVariable(wakil, "NSWindow", tetingkap);

Anda boleh mendapatkan pembolehubah contoh objek melalui object_getInstanceVariable

RGFW_window* win = NULL; //The object variable would be called "self" in a callback object_getInstanceVariable(self, "RGFW_window", (void*)&win);
Salin selepas log masuk

Menentukan Jenis Koko

Fail pengepala Koko ditulis dalam Objektif-C. Ini bermakna kita perlu menentukan sendiri jenis dan enum.

Jenis bentuk boleh ditakrifkan sebagai Bentuk CG seperti ini:

typedef CGRect NSRect; typedef CGPoint NSPoint; typedef CGSize NSSize;
Salin selepas log masuk

Koko juga menggunakan nama jenis integer tersuai,
ini boleh ditakrifkan sebagai jenis data c yang sepadan.

typedef unsigned long NSUInteger; typedef long NSInteger;
Salin selepas log masuk

Anda juga boleh menentukan objek Koko. Saya mentakrifkannya sebagai tidak sah supaya saya boleh menggunakannya sebagai petunjuk.

// Note: void is being used here // type* can be used ( type* == void* == id ) typedef void NSEvent; typedef void NSString; typedef void NSWindow; typedef void NSApplication;
Salin selepas log masuk

Bagi enum, berikut adalah beberapa enum yang akan saya gunakan dalam tutorial ini.

Many of the other enums can be found in Cocoa's headers, documentation, RGFW.h, or Silicon. h.

/* this macro is used to give an enum a type */ #define NS_ENUM(type, name) type name; enum typedef NS_ENUM(NSUInteger, NSWindowStyleMask) { NSWindowStyleMaskBorderless = 0, NSWindowStyleMaskTitled = 1 << 0, NSWindowStyleMaskClosable = 1 << 1, NSWindowStyleMaskMiniaturizable = 1 << 2, NSWindowStyleMaskResizable = 1 << 3, NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, NSWindowStyleMaskFullScreen = 1 << 14, NSWindowStyleMaskFullSizeContentView = 1 << 15, NSWindowStyleMaskUtilityWindow = 1 << 4, NSWindowStyleMaskDocModalWindow = 1 << 6, NSWindowStyleMaskNonactivatingPanel = 1 << 7, NSWindowStyleMaskHUDWindow = 1 << 13 }; typedef NS_ENUM(NSUInteger, NSBackingStoreType) { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 }; typedef NS_ENUM(NSUInteger, NSEventType) { /* various types of events */ NSEventTypeLeftMouseDown = 1, NSEventTypeLeftMouseUp = 2, NSEventTypeRightMouseDown = 3, NSEventTypeRightMouseUp = 4, NSEventTypeMouseMoved = 5, NSEventTypeLeftMouseDragged = 6, NSEventTypeRightMouseDragged = 7, NSEventTypeMouseEntered = 8, NSEventTypeMouseExited = 9, NSEventTypeKeyDown = 10, NSEventTypeKeyUp = 11, NSEventTypeFlagsChanged = 12, NSEventTypeAppKitDefined = 13, NSEventTypeSystemDefined = 14, NSEventTypeApplicationDefined = 15, NSEventTypePeriodic = 16, NSEventTypeCursorUpdate = 17, NSEventTypeScrollWheel = 22, NSEventTypeTabletPoint = 23, NSEventTypeTabletProximity = 24, NSEventTypeOtherMouseDown = 25, NSEventTypeOtherMouseUp = 26, NSEventTypeOtherMouseDragged = 27, /* The following event types are available on some hardware on 10.5.2 and later */ NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29, NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30, NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31, NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18, NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19, NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20, NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32, NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33, NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34, NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37, NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38, }; typedef NS_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */ NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown, NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp, NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown, NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp, NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved, NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged, NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged, NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered, NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited, NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown, NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp, NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged, NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined, NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined, NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined, NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic, NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate, NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel, NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint, NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity, NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown, NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp, NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged, }; /* The following event masks are available on some hardware on 10.5.2 and later */ #define NSEventMaskGesture API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeGesture) #define NSEventMaskMagnify API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeMagnify) #define NSEventMaskSwipe API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeSwipe) #define NSEventMaskRotate API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeRotate) #define NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeBeginGesture) #define NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeEndGesture) /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit. */ #define NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) (1ULL << NSEventTypeSmartMagnify) #define NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) (1ULL << NSEventTypePressure) #define NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) (1ULL << NSEventTypeDirectTouch) #define NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) (1ULL << NSEventTypeChangeMode) #define NSEventMaskAny NSUIntegerMax typedef NS_ENUM(NSUInteger, NSEventModifierFlags) { NSEventModifierFlagCapsLock = 1 << 16, // Set if Caps Lock key is pressed. NSEventModifierFlagShift = 1 << 17, // Set if Shift key is pressed. NSEventModifierFlagControl = 1 << 18, // Set if Control key is pressed. NSEventModifierFlagOption = 1 << 19, // Set if Option or Alternate key is pressed. NSEventModifierFlagCommand = 1 << 20, // Set if Command key is pressed. NSEventModifierFlagNumericPad = 1 << 21, // Set if any key in the numeric keypad is pressed. NSEventModifierFlagHelp = 1 << 22, // Set if the Help key is pressed. NSEventModifierFlagFunction = 1 << 23, // Set if any function key is pressed. };
Salin selepas log masuk

RGFW also defines NSAlloc and NSRelease because they're basic functions that are used a lot.

#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) #define NSRelease(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("release"))
Salin selepas log masuk

3. Creating a Basic Cocoa Window

Now that you understand the basics of calling Objective-C functions from C, and the setup required to use Cocoa, it's time to apply that for creating a basic window using Cocoa.

First, some library headers are required.

#include  // ! #include  #include 
Salin selepas log masuk

These functions will be used for printing information about the current event.

const char* NSEventTypeToChar(NSEventType eventType); const char* NSEventModifierFlagsToChar(NSEventModifierFlags modifierFlags); // These will be placed after the main function and will be defined like this: const char* NSEventTypeToChar(NSEventType eventType) { switch (eventType) { case NSEventTypeLeftMouseDown: return "LeftMouseDown"; case NSEventTypeLeftMouseUp: return "LeftMouseUp"; case NSEventTypeRightMouseDown: return "RightMouseDown"; case NSEventTypeRightMouseUp: return "RightMouseUp"; case NSEventTypeMouseMoved: return "MouseMoved"; case NSEventTypeLeftMouseDragged: return "LeftMouseDragged"; case NSEventTypeRightMouseDragged: return "RightMouseDragged"; case NSEventTypeMouseEntered: return "MouseEntered"; case NSEventTypeMouseExited: return "MouseExited"; case NSEventTypeKeyDown: return "KeyDown"; case NSEventTypeKeyUp: return "KeyUp"; case NSEventTypeFlagsChanged: return "FlagsChanged"; case NSEventTypeAppKitDefined: return "AppKitDefined"; case NSEventTypeSystemDefined: return "SystemDefined"; case NSEventTypeApplicationDefined: return "ApplicationDefined"; case NSEventTypePeriodic: return "Periodic"; case NSEventTypeCursorUpdate: return "CursorUpdate"; case NSEventTypeScrollWheel: return "ScrollWheel"; case NSEventTypeTabletPoint: return "TabletPoint"; case NSEventTypeTabletProximity: return "TabletProximity"; case NSEventTypeOtherMouseDown: return "OtherMouseDown"; case NSEventTypeOtherMouseUp: return "OtherMouseUp"; case NSEventTypeOtherMouseDragged: return "OtherMouseDragged"; default: return "N/A"; } } char* ns_strcat(register char *s, register const char *append) { char *save = s; for (; *s; ++s); while ((*s++ = *append++)); return save; } const char* NSEventModifierFlagsToChar(NSEventModifierFlags modifierFlags) { static char result[100]; result[0] = '\0'; if ((modifierFlags & NSEventModifierFlagCapsLock) == NSEventModifierFlagCapsLock) ns_strcat(result, "CapsLock, "); if ((modifierFlags & NSEventModifierFlagShift) == NSEventModifierFlagShift) ns_strcat(result, "NShift, "); if ((modifierFlags & NSEventModifierFlagControl) == NSEventModifierFlagControl) ns_strcat(result, "Control, "); if ((modifierFlags & NSEventModifierFlagOption) == NSEventModifierFlagOption) ns_strcat(result, "Option, "); if ((modifierFlags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand) ns_strcat(result, "Command, "); if ((modifierFlags & NSEventModifierFlagNumericPad) == NSEventModifierFlagNumericPad) ns_strcat(result, "NumericPad, "); if ((modifierFlags & NSEventModifierFlagHelp) == NSEventModifierFlagHelp) ns_strcat(result, "Help, "); if ((modifierFlags & NSEventModifierFlagFunction) == NSEventModifierFlagFunction) ns_strcat(result, "Function, "); return result; }
Salin selepas log masuk

Cocoa does not handle certain events using the event loop.
Instead, they're fed to the NSWindow via callbacks.

Here's how these functions will be defined for this example:

bool running = true; unsigned int onClose(void* self) { NSWindow* win = NULL; object_getInstanceVariable(self, "NSWindow", (void*)&win); if (win == NULL) return true; running = false; return true; } NSSize windowResize(void* self, SEL sel, NSSize frameSize) { NSWindow* win = NULL; object_getInstanceVariable(self, "NSWindow", (void*)&win); if (win == NULL) return frameSize; printf("window resized to %f %f\n", frameSize.width, frameSize.height); return frameSize; }
Salin selepas log masuk

The first thing that I will do in the main function is define the windowShouldClose callback.

This is so that way the program doesn't keep running after the window is closed.

class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP) onClose, 0);
Salin selepas log masuk

Next, the NSApplication is set up.

This requires the use of sharedApplication and setActivationPolicy

NSApplication* NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); objc_msgSend_void_id(NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
Salin selepas log masuk

Now you can create a NSWindow can be created, I broke the window creation process into three steps so it's more readable.

The window is created using initWithContentRect

NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable; SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); NSWindow* window = ((id (*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend) (NSAlloc(objc_getClass("NSWindow")), func, (NSRect){{200, 200}, {200, 200}}, macArgs, macArgs, false);
Salin selepas log masuk

You can then set up the delegate class and window resize callback.

Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); class_addIvar( delegateClass, "NSWindow", sizeof(NSWindow*), rint(log2(sizeof(NSWindow*))), "L" ); class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) windowResize, "{NSSize=ff}@:{NSSize=ff}");
Salin selepas log masuk

After that, the delegate must be initialized using init

Then I will set the delegate's variable data as our NSWindow and set the NSWindow's delegate to be the delegate we initialized using setDelegate

id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init")); object_setInstanceVariable(delegate, "NSWindow", window); objc_msgSend_void_id(window, sel_registerName("setDelegate:"), delegate);
Salin selepas log masuk

Then the window can be shown using setIsVisible and made key and front via makeKeyAndOrderFront, this puts it in focus.

activatIgnoredOtherApps is required to open the window

objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); ((id(*)(id, SEL, SEL))objc_msgSend)(window, sel_registerName("makeKeyAndOrderFront:"), NULL); objc_msgSend_void_bool(window, sel_registerName("setIsVisible:"), true); objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));
Salin selepas log masuk

Now, in the draw loop, I'd start by creating a memory pool.

This is so that way all memory allocated by event checking can be freed at once, avoiding a memory leak.

This can be done using NSAutoreleasePool

id pool = objc_msgSend_id(NSAlloc(objc_getClass("NSAutoreleasePool")), sel_registerName("init"));
Salin selepas log masuk

Now the current event can be checked using an NSEvent object and nextEventMatchingMask

The event type can be found using type
The event mouse point can be found using locationInWindow
The event modifier flags can be found using modifierFlags

NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend) (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), ULONG_MAX, NULL, ((id(*)(id, SEL, const char*))objc_msgSend) ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "kCFRunLoopDefaultMode"), true); unsigned int type = objc_msgSend_uint(e, sel_registerName("type")); NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
Salin selepas log masuk

Before I check the event, I make sure there is an event.

if (type == 0) printf("Event [type=%s location={%f, %f} modifierFlags={%s}]\n", NSEventTypeToChar(type), p.x, p.y, NSEventModifierFlagsToChar(objc_msgSend_uint(e, sel_registerName("modifierFlags"))));
Salin selepas log masuk

The event can be pushed out using sendEvent and the window can be updated using updateWindows

objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
Salin selepas log masuk

At the end of the draw loop, the event pool should be freed.

NSRelease(pool);
Salin selepas log masuk

Full code example

// compile with: // gcc example.c -lm -framework Foundation -framework AppKit -framework CoreVideo #include
         
          #include
          
           #include
           
            #include
            
             #ifdef __arm64__ /* ARM just uses objc_msgSend */ #define abi_objc_msgSend_stret objc_msgSend #define abi_objc_msgSend_fpret objc_msgSend #else /* __i386__ */ /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ #define abi_objc_msgSend_stret objc_msgSend_stret #define abi_objc_msgSend_fpret objc_msgSend_fpret #endif typedef CGRect NSRect; typedef CGPoint NSPoint; typedef CGSize NSSize; typedef void NSEvent; typedef void NSString; typedef void NSWindow; typedef void NSApplication; typedef unsigned long NSUInteger; typedef long NSInteger; #define NS_ENUM(type, name) type name; enum typedef NS_ENUM(NSUInteger, NSWindowStyleMask) { NSWindowStyleMaskBorderless = 0, NSWindowStyleMaskTitled = 1 << 0, NSWindowStyleMaskClosable = 1 << 1, NSWindowStyleMaskMiniaturizable = 1 << 2, NSWindowStyleMaskResizable = 1 << 3, NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, NSWindowStyleMaskFullScreen = 1 << 14, NSWindowStyleMaskFullSizeContentView = 1 << 15, NSWindowStyleMaskUtilityWindow = 1 << 4, NSWindowStyleMaskDocModalWindow = 1 << 6, NSWindowStyleMaskNonactivatingPanel = 1 << 7, NSWindowStyleMaskHUDWindow = 1 << 13 }; typedef NS_ENUM(NSUInteger, NSBackingStoreType) { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 }; typedef NS_ENUM(NSUInteger, NSEventType) { /* various types of events */ NSEventTypeLeftMouseDown = 1, NSEventTypeLeftMouseUp = 2, NSEventTypeRightMouseDown = 3, NSEventTypeRightMouseUp = 4, NSEventTypeMouseMoved = 5, NSEventTypeLeftMouseDragged = 6, NSEventTypeRightMouseDragged = 7, NSEventTypeMouseEntered = 8, NSEventTypeMouseExited = 9, NSEventTypeKeyDown = 10, NSEventTypeKeyUp = 11, NSEventTypeFlagsChanged = 12, NSEventTypeAppKitDefined = 13, NSEventTypeSystemDefined = 14, NSEventTypeApplicationDefined = 15, NSEventTypePeriodic = 16, NSEventTypeCursorUpdate = 17, NSEventTypeScrollWheel = 22, NSEventTypeTabletPoint = 23, NSEventTypeTabletProximity = 24, NSEventTypeOtherMouseDown = 25, NSEventTypeOtherMouseUp = 26, NSEventTypeOtherMouseDragged = 27, /* The following event types are available on some hardware on 10.5.2 and later */ NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29, NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30, NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31, NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18, NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19, NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20, NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32, NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33, NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34, NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37, NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38, }; typedef NS_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */ NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown, NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp, NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown, NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp, NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved, NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged, NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged, NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered, NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited, NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown, NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp, NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged, NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined, NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined, NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined, NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic, NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate, NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel, NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint, NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity, NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown, NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp, NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged, }; /* The following event masks are available on some hardware on 10.5.2 and later */ #define NSEventMaskGesture API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeGesture) #define NSEventMaskMagnify API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeMagnify) #define NSEventMaskSwipe API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeSwipe) #define NSEventMaskRotate API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeRotate) #define NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeBeginGesture) #define NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) (1ULL << NSEventTypeEndGesture) /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit. */ #define NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) (1ULL << NSEventTypeSmartMagnify) #define NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) (1ULL << NSEventTypePressure) #define NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) (1ULL << NSEventTypeDirectTouch) #define NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) (1ULL << NSEventTypeChangeMode) #define NSEventMaskAny NSUIntegerMax typedef NS_ENUM(NSUInteger, NSEventModifierFlags) { NSEventModifierFlagCapsLock = 1 << 16, // Set if Caps Lock key is pressed. NSEventModifierFlagShift = 1 << 17, // Set if Shift key is pressed. NSEventModifierFlagControl = 1 << 18, // Set if Control key is pressed. NSEventModifierFlagOption = 1 << 19, // Set if Option or Alternate key is pressed. NSEventModifierFlagCommand = 1 << 20, // Set if Command key is pressed. NSEventModifierFlagNumericPad = 1 << 21, // Set if any key in the numeric keypad is pressed. NSEventModifierFlagHelp = 1 << 22, // Set if the Help key is pressed. NSEventModifierFlagFunction = 1 << 23, // Set if any function key is pressed. }; #define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend) #define objc_msgSend_id_id ((id (*)(id, SEL, id))objc_msgSend) #define objc_msgSend_id_rect ((id (*)(id, SEL, NSRect))objc_msgSend) #define objc_msgSend_uint ((NSUInteger (*)(id, SEL))objc_msgSend) #define objc_msgSend_int ((NSInteger (*)(id, SEL))objc_msgSend) #define objc_msgSend_SEL ((SEL (*)(id, SEL))objc_msgSend) #define objc_msgSend_float ((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) #define objc_msgSend_bool ((BOOL (*)(id, SEL))objc_msgSend) #define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend) #define objc_msgSend_double ((double (*)(id, SEL))objc_msgSend) #define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend) #define objc_msgSend_void_uint ((void (*)(id, SEL, NSUInteger))objc_msgSend) #define objc_msgSend_void_int ((void (*)(id, SEL, NSInteger))objc_msgSend) #define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend) #define objc_msgSend_void_float ((void (*)(id, SEL, CGFloat))objc_msgSend) #define objc_msgSend_void_double ((void (*)(id, SEL, double))objc_msgSend) #define objc_msgSend_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend) #define objc_msgSend_id_char_const ((id (*)(id, SEL, char const *))objc_msgSend) typedef enum NSApplicationActivationPolicy { NSApplicationActivationPolicyRegular, NSApplicationActivationPolicyAccessory, NSApplicationActivationPolicyProhibited } NSApplicationActivationPolicy; #define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) #define NSRelease(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("release")) bool running = true; unsigned int onClose(void* self) { NSWindow* win = NULL; object_getInstanceVariable(self, "NSWindow", (void*)&win); if (win == NULL) return true; running = false; return true; } NSSize windowResize(void* self, SEL sel, NSSize frameSize) { NSWindow* win = NULL; object_getInstanceVariable(self, "NSWindow", (void*)&win); if (win == NULL) return frameSize; printf("window resized to %f %f\n", frameSize.width, frameSize.height); return frameSize; } #include
             
              const char* NSEventTypeToChar(NSEventType eventType); const char* NSEventModifierFlagsToChar(NSEventModifierFlags modifierFlags); int main(int argc, char* argv[]) { class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP) onClose, 0); NSApplication* NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); objc_msgSend_void_int(NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable; SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); NSWindow* window = ((id (*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend) (NSAlloc(objc_getClass("NSWindow")), func, (NSRect){{200, 200}, {200, 200}}, macArgs, macArgs, false); Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); class_addIvar( delegateClass, "NSWindow", sizeof(NSWindow*), rint(log2(sizeof(NSWindow*))), "L" ); class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) windowResize, "{NSSize=ff}@:{NSSize=ff}"); id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init")); object_setInstanceVariable(delegate, "NSWindow", window); objc_msgSend_void_id(window, sel_registerName("setDelegate:"), delegate); objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); ((id(*)(id, SEL, SEL))objc_msgSend)(window, sel_registerName("makeKeyAndOrderFront:"), NULL); objc_msgSend_void_bool(window, sel_registerName("setIsVisible:"), true); objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); while (running) { id pool = objc_msgSend_id(NSAlloc(objc_getClass("NSAutoreleasePool")), sel_registerName("init")); NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend) (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), ULONG_MAX, NULL, ((id(*)(id, SEL, const char*))objc_msgSend) ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "kCFRunLoopDefaultMode"), true); unsigned int type = objc_msgSend_uint(e, sel_registerName("type")); NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); if (type != 0) printf("Event [type=%s location={%f, %f} modifierFlags={%s}]\n", NSEventTypeToChar(type), p.x, p.y, NSEventModifierFlagsToChar(objc_msgSend_uint(e, sel_registerName("modifierFlags")))); objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); NSRelease(pool); } } const char* NSEventTypeToChar(NSEventType eventType) { switch (eventType) { case NSEventTypeLeftMouseDown: return "LeftMouseDown"; case NSEventTypeLeftMouseUp: return "LeftMouseUp"; case NSEventTypeRightMouseDown: return "RightMouseDown"; case NSEventTypeRightMouseUp: return "RightMouseUp"; case NSEventTypeMouseMoved: return "MouseMoved"; case NSEventTypeLeftMouseDragged: return "LeftMouseDragged"; case NSEventTypeRightMouseDragged: return "RightMouseDragged"; case NSEventTypeMouseEntered: return "MouseEntered"; case NSEventTypeMouseExited: return "MouseExited"; case NSEventTypeKeyDown: return "KeyDown"; case NSEventTypeKeyUp: return "KeyUp"; case NSEventTypeFlagsChanged: return "FlagsChanged"; case NSEventTypeAppKitDefined: return "AppKitDefined"; case NSEventTypeSystemDefined: return "SystemDefined"; case NSEventTypeApplicationDefined: return "ApplicationDefined"; case NSEventTypePeriodic: return "Periodic"; case NSEventTypeCursorUpdate: return "CursorUpdate"; case NSEventTypeScrollWheel: return "ScrollWheel"; case NSEventTypeTabletPoint: return "TabletPoint"; case NSEventTypeTabletProximity: return "TabletProximity"; case NSEventTypeOtherMouseDown: return "OtherMouseDown"; case NSEventTypeOtherMouseUp: return "OtherMouseUp"; case NSEventTypeOtherMouseDragged: return "OtherMouseDragged"; default: return "N/A"; } } char* ns_strcat(register char *s, register const char *append) { char *save = s; for (; *s; ++s); while ((*s++ = *append++)); return save; } const char* NSEventModifierFlagsToChar(NSEventModifierFlags modifierFlags) { static char result[100]; result[0] = '\0'; if ((modifierFlags & NSEventModifierFlagCapsLock) == NSEventModifierFlagCapsLock) ns_strcat(result, "CapsLock, "); if ((modifierFlags & NSEventModifierFlagShift) == NSEventModifierFlagShift) ns_strcat(result, "NShift, "); if ((modifierFlags & NSEventModifierFlagControl) == NSEventModifierFlagControl) ns_strcat(result, "Control, "); if ((modifierFlags & NSEventModifierFlagOption) == NSEventModifierFlagOption) ns_strcat(result, "Option, "); if ((modifierFlags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand) ns_strcat(result, "Command, "); if ((modifierFlags & NSEventModifierFlagNumericPad) == NSEventModifierFlagNumericPad) ns_strcat(result, "NumericPad, "); if ((modifierFlags & NSEventModifierFlagHelp) == NSEventModifierFlagHelp) ns_strcat(result, "Help, "); if ((modifierFlags & NSEventModifierFlagFunction) == NSEventModifierFlagFunction) ns_strcat(result, "Function, "); return result; }
             
            
           
          
         
Salin selepas log masuk

Atas ialah kandungan terperinci RGFW Di Bawah Hud: Koko dalam Pure C. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!