diff --git a/CMakeLists.txt b/CMakeLists.txt index f2a868e..c1153c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,13 @@ set(CMAKE_CXX_STANDARD 17) project(libnut) # Source -set(SOURCE_FILES "src/main.cc" "src/deadbeef_rand.c" "src/keycode.c" "src/MMBitmap.c") +set(SOURCE_FILES "src/main.cc" "src/deadbeef_rand.c" "src/MMBitmap.c") if (UNIX AND NOT APPLE) - set(SOURCE_FILES "${SOURCE_FILES}" "src/linux/keypress.c" "src/linux/mouse.c" "src/linux/screen.c" "src/linux/screengrab.c" "src/linux/xdisplay.c" "src/linux/highlightwindow.c" "src/linux/window_manager.cc") + set(SOURCE_FILES "${SOURCE_FILES}" "src/linux/keycode.c" "src/linux/keypress.c" "src/linux/mouse.c" "src/linux/screen.c" "src/linux/screengrab.c" "src/linux/xdisplay.c" "src/linux/highlightwindow.c" "src/linux/window_manager.cc") elseif (UNIX AND APPLE) - set(SOURCE_FILES "${SOURCE_FILES}" "src/macos/keypress.c" "src/macos/mouse.c" "src/macos/screen.c" "src/macos/screengrab.c" "src/macos/highlightwindow.m" "src/macos/window_manager.mm") + set(SOURCE_FILES "${SOURCE_FILES}" "src/macos/keycode.c" "src/macos/keypress.c" "src/macos/mouse.c" "src/macos/screen.c" "src/macos/screengrab.c" "src/macos/highlightwindow.m" "src/macos/window_manager.mm") elseif (WIN32) - set(SOURCE_FILES "${SOURCE_FILES}" "src/win32/keypress.c" "src/win32/mouse.c" "src/win32/screen.c" "src/win32/screengrab.c" "src/win32/highlightwindow.c" "src/win32/window_manager.cc") + set(SOURCE_FILES "${SOURCE_FILES}" "src/win32/keycode.c" "src/win32/keypress.c" "src/win32/mouse.c" "src/win32/screen.c" "src/win32/screengrab.c" "src/win32/highlightwindow.c" "src/win32/window_manager.cc") endif() add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC}) diff --git a/src/keycode.c b/src/keycode.c deleted file mode 100644 index 235482e..0000000 --- a/src/keycode.c +++ /dev/null @@ -1,163 +0,0 @@ -#include "keycode.h" - -#if defined(IS_MACOSX) - -#include -#include /* For kVK_ constants, and TIS functions. */ - -/* Returns string representation of key, if it is printable. - * Ownership follows the Create Rule; that is, it is the caller's - * responsibility to release the returned object. */ -CFStringRef createStringForKey(CGKeyCode keyCode); - -#elif defined(USE_X11) - -/* - * Structs to store key mappings not handled by XStringToKeysym() on some - * Linux systems. - */ - -struct XSpecialCharacterMapping { - char name; - MMKeyCode code; -}; - -struct XSpecialCharacterMapping XSpecialCharacterTable[] = { - {'~', XK_asciitilde}, - {'_', XK_underscore}, - {'[', XK_bracketleft}, - {']', XK_bracketright}, - {'!', XK_exclam}, - {'\'', XK_quotedbl}, - {'#', XK_numbersign}, - {'$', XK_dollar}, - {'%', XK_percent}, - {'&', XK_ampersand}, - {'\'', XK_quoteright}, - {'*', XK_asterisk}, - {'+', XK_plus}, - {',', XK_comma}, - {'-', XK_minus}, - {'.', XK_period}, - {'?', XK_question}, - {'<', XK_less}, - {'>', XK_greater}, - {'=', XK_equal}, - {'@', XK_at}, - {':', XK_colon}, - {';', XK_semicolon}, - {'\\', XK_backslash}, - {'`', XK_grave}, - {'{', XK_braceleft}, - {'}', XK_braceright}, - {'|', XK_bar}, - {'^', XK_asciicircum}, - {'(', XK_parenleft}, - {')', XK_parenright}, - {' ', XK_space}, - {'/', XK_slash}, - {'\t', XK_Tab}, - {'\n', XK_Return} -}; - -#endif - -MMKeyCode keyCodeForChar(const char c) -{ -#if defined(IS_MACOSX) - /* OS X does not appear to have a built-in function for this, so instead we - * have to write our own. */ - static CFMutableDictionaryRef charToCodeDict = NULL; - CGKeyCode code; - UniChar character = c; - CFStringRef charStr = NULL; - - /* Generate table of keycodes and characters. */ - if (charToCodeDict == NULL) { - size_t i; - charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, - 128, - &kCFCopyStringDictionaryKeyCallBacks, - NULL); - if (charToCodeDict == NULL) return UINT16_MAX; - - /* Loop through every keycode (0 - 127) to find its current mapping. */ - for (i = 0; i < 128; ++i) { - CFStringRef string = createStringForKey((CGKeyCode)i); - if (string != NULL) { - CFDictionaryAddValue(charToCodeDict, string, (const void *)i); - CFRelease(string); - } - } - } - - charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1); - - /* Our values may be NULL (0), so we need to use this function. */ - if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr, - (const void **)&code)) { - code = UINT16_MAX; /* Error */ - } - - CFRelease(charStr); - return (MMKeyCode)code; -#elif defined(IS_WINDOWS) - return VkKeyScan(c); -#elif defined(USE_X11) - MMKeyCode code; - - char buf[2]; - buf[0] = c; - buf[1] = '\0'; - - code = XStringToKeysym(buf); - if (code == NoSymbol) { - /* Some special keys are apparently not handled properly by - * XStringToKeysym() on some systems, so search for them instead in our - * mapping table. */ - size_t i; - const size_t specialCharacterCount = - sizeof(XSpecialCharacterTable) / sizeof(XSpecialCharacterTable[0]); - for (i = 0; i < specialCharacterCount; ++i) { - if (c == XSpecialCharacterTable[i].name) { - code = XSpecialCharacterTable[i].code; - break; - } - } - } - - return code; -#endif -} - -#if defined(IS_MACOSX) - -CFStringRef createStringForKey(CGKeyCode keyCode) -{ - TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource(); - CFDataRef layoutData = - TISGetInputSourceProperty(currentKeyboard, - kTISPropertyUnicodeKeyLayoutData); - const UCKeyboardLayout *keyboardLayout = - (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); - - UInt32 keysDown = 0; - UniChar chars[4]; - UniCharCount realLength; - - UCKeyTranslate(keyboardLayout, - keyCode, - kUCKeyActionDisplay, - 0, - LMGetKbdType(), - kUCKeyTranslateNoDeadKeysBit, - &keysDown, - sizeof(chars) / sizeof(chars[0]), - &realLength, - chars); - CFRelease(currentKeyboard); - - return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); -} - -#endif diff --git a/src/linux/keycode.c b/src/linux/keycode.c new file mode 100644 index 0000000..bdd662a --- /dev/null +++ b/src/linux/keycode.c @@ -0,0 +1,76 @@ +#include "../keycode.h" + +/* + * Structs to store key mappings not handled by XStringToKeysym() on some + * Linux systems. + */ + +struct XSpecialCharacterMapping { + char name; + MMKeyCode code; +}; + +struct XSpecialCharacterMapping XSpecialCharacterTable[] = { + {'~', XK_asciitilde}, + {'_', XK_underscore}, + {'[', XK_bracketleft}, + {']', XK_bracketright}, + {'!', XK_exclam}, + {'\'', XK_quotedbl}, + {'#', XK_numbersign}, + {'$', XK_dollar}, + {'%', XK_percent}, + {'&', XK_ampersand}, + {'\'', XK_quoteright}, + {'*', XK_asterisk}, + {'+', XK_plus}, + {',', XK_comma}, + {'-', XK_minus}, + {'.', XK_period}, + {'?', XK_question}, + {'<', XK_less}, + {'>', XK_greater}, + {'=', XK_equal}, + {'@', XK_at}, + {':', XK_colon}, + {';', XK_semicolon}, + {'\\', XK_backslash}, + {'`', XK_grave}, + {'{', XK_braceleft}, + {'}', XK_braceright}, + {'|', XK_bar}, + {'^', XK_asciicircum}, + {'(', XK_parenleft}, + {')', XK_parenright}, + {' ', XK_space}, + {'/', XK_slash}, + {'\t', XK_Tab}, + {'\n', XK_Return} +}; + +MMKeyCode keyCodeForChar(const char c) +{ + MMKeyCode code; + + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + + code = XStringToKeysym(buf); + if (code == NoSymbol) { + /* Some special keys are apparently not handled properly by + * XStringToKeysym() on some systems, so search for them instead in our + * mapping table. */ + size_t i; + const size_t specialCharacterCount = + sizeof(XSpecialCharacterTable) / sizeof(XSpecialCharacterTable[0]); + for (i = 0; i < specialCharacterCount; ++i) { + if (c == XSpecialCharacterTable[i].name) { + code = XSpecialCharacterTable[i].code; + break; + } + } + } + + return code; +} diff --git a/src/macos/keycode.c b/src/macos/keycode.c new file mode 100644 index 0000000..91eca7c --- /dev/null +++ b/src/macos/keycode.c @@ -0,0 +1,82 @@ +#include "../keycode.h" + +#include +#include /* For kVK_ constants, and TIS functions. */ + +/* Returns string representation of key, if it is printable. + * Ownership follows the Create Rule; that is, it is the caller's + * responsibility to release the returned object. */ +CFStringRef createStringForKey(CGKeyCode keyCode); + +MMKeyCode keyCodeForChar(const char c) +{ + /* OS X does not appear to have a built-in function for this, so instead we + * have to write our own. */ + static CFMutableDictionaryRef charToCodeDict = NULL; + CGKeyCode code; + UniChar character = c; + CFStringRef charStr = NULL; + + /* Generate table of keycodes and characters. */ + if (charToCodeDict == NULL) + { + size_t i; + charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, + 128, + &kCFCopyStringDictionaryKeyCallBacks, + NULL); + if (charToCodeDict == NULL) + return UINT16_MAX; + + /* Loop through every keycode (0 - 127) to find its current mapping. */ + for (i = 0; i < 128; ++i) + { + CFStringRef string = createStringForKey((CGKeyCode)i); + if (string != NULL) + { + CFDictionaryAddValue(charToCodeDict, string, (const void *)i); + CFRelease(string); + } + } + } + + charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1); + + /* Our values may be NULL (0), so we need to use this function. */ + if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr, + (const void **)&code)) + { + code = UINT16_MAX; /* Error */ + } + + CFRelease(charStr); + return (MMKeyCode)code; +} + +CFStringRef createStringForKey(CGKeyCode keyCode) +{ + TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource(); + CFDataRef layoutData = + TISGetInputSourceProperty(currentKeyboard, + kTISPropertyUnicodeKeyLayoutData); + const UCKeyboardLayout *keyboardLayout = + (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); + + UInt32 keysDown = 0; + UniChar chars[4]; + UniCharCount realLength; + + UCKeyTranslate(keyboardLayout, + keyCode, + kUCKeyActionDisplay, + 0, + LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + &keysDown, + sizeof(chars) / sizeof(chars[0]), + &realLength, + chars); + CFRelease(currentKeyboard); + + return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); +} diff --git a/src/win32/keycode.c b/src/win32/keycode.c new file mode 100644 index 0000000..7a01dc9 --- /dev/null +++ b/src/win32/keycode.c @@ -0,0 +1,6 @@ +#include "../keycode.h" + +MMKeyCode keyCodeForChar(const char c) +{ + return VkKeyScan(c); +}