diff options
author | Sebastien Vincent <seb@jitsi.org> | 2010-09-28 07:46:45 +0000 |
---|---|---|
committer | Sebastien Vincent <seb@jitsi.org> | 2010-09-28 07:46:45 +0000 |
commit | 6a67589c86221faedcebd370824274013be64026 (patch) | |
tree | b5a73d1deec90532057f70b801cafaa015a907e0 /src/native/hid | |
parent | a4ddb0361ebc3848e30eefbf0391c755adb3387c (diff) | |
download | jitsi-6a67589c86221faedcebd370824274013be64026.zip jitsi-6a67589c86221faedcebd370824274013be64026.tar.gz jitsi-6a67589c86221faedcebd370824274013be64026.tar.bz2 |
Desktop sharing support for SIP and XMPP. Note that GUI is not ready yet to propose this feature to the users.
Diffstat (limited to 'src/native/hid')
-rw-r--r-- | src/native/hid/KeyboardUtil.h | 34 | ||||
-rw-r--r-- | src/native/hid/KeyboardUtil_mac.c | 228 | ||||
-rw-r--r-- | src/native/hid/KeyboardUtil_unix.c | 203 | ||||
-rw-r--r-- | src/native/hid/KeyboardUtil_windows.c | 132 | ||||
-rw-r--r-- | src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.c | 59 | ||||
-rw-r--r-- | src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.h | 29 |
6 files changed, 685 insertions, 0 deletions
diff --git a/src/native/hid/KeyboardUtil.h b/src/native/hid/KeyboardUtil.h new file mode 100644 index 0000000..6282540 --- /dev/null +++ b/src/native/hid/KeyboardUtil.h @@ -0,0 +1,34 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +/** + * \file KeyboardUtil.h + * \brief Prototypes of the function to press/release keys. + * \author Sebastien Vincent + */ + +#ifndef KEYBOARD_UTIL_H +#define KEYBOARD_UTIL_H + +#include <jni.h> + +/** + * \brief Press or release a key. + * \param key ascii code of the key + * \param pressed if the key have to be pressed or released + */ +void generateKey(jchar key, jboolean pressed); + +/** + * \brief Press or release a symbol. + * \param symbol symbol name + * \param pressed if the key have to be pressed or released + */ +void generateSymbol(const char* symbol, jboolean pressed); + +#endif /* KEYBOARD_UTIL_H */ + diff --git a/src/native/hid/KeyboardUtil_mac.c b/src/native/hid/KeyboardUtil_mac.c new file mode 100644 index 0000000..b514be3 --- /dev/null +++ b/src/native/hid/KeyboardUtil_mac.c @@ -0,0 +1,228 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +/** + * \file KeyboardUtil_unix.c + * \brief Mac OS X specific code to press/release keys. + * \author Sebastien Vincent + */ + +#include <ApplicationServices/ApplicationServices.h> +#include <Carbon/Carbon.h> + +#include "KeyboardUtil.h" + +/** + * \brief Get the keycode from a specific keyboard layout. + * \param c ascii character + * \param uchrHeader keyboard layout + * \param pshift if the character need shift modifier, value will have 1 otherwise 0 + * \param palt if the character need alt modifier, value will have 1 otherwise 0 + */ +void checkModifiers(const char c, const UCKeyboardLayout* uchrHeader, CGKeyCode keycode, int* pshift, int* palt) +{ + int alt = (optionKey >> 8) & 0xff; + int shift = (shiftKey >> 8) & 0xff; + int altShift = ((optionKey | shiftKey) >> 8) & 0xff; + UInt32 deadKeyState = 0; + UniCharCount count; + char character; + + if(UCKeyTranslate(uchrHeader, keycode, kUCKeyActionDown, alt, LMGetKbdType(), 0, + &deadKeyState, 1, &count, &character) == 0 && character == c) + { + *palt = 1; + } + else if(UCKeyTranslate(uchrHeader, keycode, kUCKeyActionDown, shift, LMGetKbdType(), 0, + &deadKeyState, 1, &count, &character) == 0 && character == c) + { + *pshift = 1; + } + else if(UCKeyTranslate(uchrHeader, keycode, kUCKeyActionDown, altShift, LMGetKbdType(), 0, + &deadKeyState, 1, &count, &character) == 0 && character == c) + { + *pshift = 1; + *palt = 1; + } +} + +/* following two functions has been taken from + * http://stackoverflow.com/questions/1918841/how-to-convert-ascii-character-to-cgkeycode + */ + +/** + * \brief Get the keycode from a specific keyboard layout. + * \param c ascii character + * \param uchrHeader keyboard layout + * \param shift if the character needs shift modifier, value will have 1 otherwise 0 + * \param alt if the character needs alt modifier, value will have 1 otherwise 0 + * \return keycode or UINT16_MAX if not found + * \note Function taken from http://stackoverflow.com/questions/1918841/how-to-convert-ascii-character-to-cgkeycode + */ +CGKeyCode keyCodeForCharWithLayout(const char c, + const UCKeyboardLayout *uchrHeader, int* shift, int* alt) +{ + uint8_t *uchrData = (uint8_t *)uchrHeader; + UCKeyboardTypeHeader *uchrKeyboardList = (UCKeyboardTypeHeader*)uchrHeader->keyboardTypeList; + + /* Loop through the keyboard type list. */ + ItemCount i, j; + for (i = 0; i < uchrHeader->keyboardTypeCount; ++i) + { + /* Get a pointer to the keyToCharTable structure. */ + UCKeyToCharTableIndex *uchrKeyIX = (UCKeyToCharTableIndex *) + (uchrData + (uchrKeyboardList[i].keyToCharTableIndexOffset)); + + /* Not sure what this is for but it appears to be a safeguard... */ + UCKeyStateRecordsIndex *stateRecordsIndex; + if(uchrKeyboardList[i].keyStateRecordsIndexOffset != 0) + { + stateRecordsIndex = (UCKeyStateRecordsIndex *) + (uchrData + (uchrKeyboardList[i].keyStateRecordsIndexOffset)); + + if((stateRecordsIndex->keyStateRecordsIndexFormat) != + kUCKeyStateRecordsIndexFormat) + { + stateRecordsIndex = NULL; + } + } + else + { + stateRecordsIndex = NULL; + } + + /* Make sure structure is a table that can be searched. */ + if((uchrKeyIX->keyToCharTableIndexFormat) != kUCKeyToCharTableIndexFormat) + { + continue; + } + + /* Check the table of each keyboard for character */ + for (j = 0; j < uchrKeyIX->keyToCharTableCount; ++j) + { + UCKeyOutput *keyToCharData = + (UCKeyOutput *)(uchrData + (uchrKeyIX->keyToCharTableOffsets[j])); + + /* Check THIS table of the keyboard for the character. */ + UInt16 k; + for (k = 0; k < uchrKeyIX->keyToCharTableSize; ++k) + { + /* Here's the strange safeguard again... */ + if((keyToCharData[k] & kUCKeyOutputTestForIndexMask) == + kUCKeyOutputStateIndexMask) + { + long keyIndex = (keyToCharData[k] & kUCKeyOutputGetIndexMask); + if(stateRecordsIndex != NULL && + keyIndex <= (stateRecordsIndex->keyStateRecordCount)) + { + UCKeyStateRecord *stateRecord = (UCKeyStateRecord *) + (uchrData + + (stateRecordsIndex->keyStateRecordOffsets[keyIndex])); + + if((stateRecord->stateZeroCharData) == c) + { + checkModifiers(c, uchrHeader, k, shift, alt); + return (CGKeyCode)k; + } + } + else if(keyToCharData[k] == c) + { + checkModifiers(c, uchrHeader, k, shift, alt); + return (CGKeyCode)k; + } + } + else if(((keyToCharData[k] & kUCKeyOutputTestForIndexMask) + != kUCKeyOutputSequenceIndexMask) && + keyToCharData[k] != 0xFFFE && + keyToCharData[k] != 0xFFFF && + keyToCharData[k] == c) + { + /* try to see if character is obtained with modifiers such as + * Option (alt) or shift + */ + checkModifiers(c, uchrHeader, k, shift, alt); + return (CGKeyCode)k; + } + } + } + } + + return UINT16_MAX; +} + +/** + * \brief Get the keycode from a specific keyboard layout. + * \param c ascii character + * \param shift if the character need shift modifier, value will have 1 otherwise 0 + * \param alt if the character need shift modifier, value will have 1 otherwise 0 + * \return keycode or UINT16_MAX if not found + * \note Function taken from http://stackoverflow.com/questions/1918841/how-to-convert-ascii-character-to-cgkeycode + */ +CGKeyCode keyCodeForChar(const char c, int* shift, int* alt) +{ + CFDataRef currentLayoutData; + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); + + if(currentKeyboard == NULL) + { + printf("Could not find keyboard layout\n"); + return UINT16_MAX; + } + + currentLayoutData = TISGetInputSourceProperty(currentKeyboard, + kTISPropertyUnicodeKeyLayoutData); + CFRelease(currentKeyboard); + if(currentLayoutData == NULL) + { + printf("Could not find layout data\n"); + return UINT16_MAX; + } + + return keyCodeForCharWithLayout(c, + (const UCKeyboardLayout *)CFDataGetBytePtr(currentLayoutData), shift, alt); +} + +void generateSymbol(const char* symbol, jboolean pressed) +{ + /* avoid warnings */ + symbol = symbol; + pressed = pressed; +} + +void generateKey(jchar key, jboolean pressed) +{ + int keycode = -1; + int shift = 0; + int alt = 0; + CGEventRef e = NULL; + int flags = 0; + + keycode = keyCodeForChar((char)key, &shift, &alt); + + if(keycode == UINT16_MAX) + { + return; + } + + e = CGEventCreateKeyboardEvent(NULL, keycode, pressed ? 1 : 0); + + if(pressed && shift) + { + flags |= kCGEventFlagMaskShift; + } + + if(pressed && alt) + { + flags |= kCGEventFlagMaskAlternate; + } + + CGEventSetFlags(e, flags); + + CGEventPost(kCGSessionEventTap, e); + CFRelease(e); +} + diff --git a/src/native/hid/KeyboardUtil_unix.c b/src/native/hid/KeyboardUtil_unix.c new file mode 100644 index 0000000..8d8673b --- /dev/null +++ b/src/native/hid/KeyboardUtil_unix.c @@ -0,0 +1,203 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +/** + * \file KeyboardUtil_unix.c + * \brief Unix specific code to press/release keys. + * \author Sebastien Vincent + */ + +#include "KeyboardUtil.h" + +#include <stdio.h> +#include <string.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/extensions/XTest.h> + +/** + * \struct keysymcharmap + * \brief Map structure between the string representation of the keysym and + * the ascii character. + */ +typedef struct keysymcharmap +{ + char *keysym; /**< String representation of the keysym */ + char key; /**< Ascii character */ +} keysymcharmap_t; + +/** + * \var g_symbolmap + * \brief Map between symbol name and X11 string representation of the keysym. + */ +static char *g_symbolmap[] = +{ + "alt", "Alt_L", + "altgr", "ISO_Level3_Shift", + "ctrl", "Control_L", + "control", "Control_L", + "meta", "Meta_L", + "super", "Super_L", + "shift", "Shift_L", + NULL, NULL, +}; + +/** + * \var g_specialcharmap + * \brief Map of the special characters. + */ +static keysymcharmap_t g_specialcharmap[] = +{ + {"Return", '\n'}, + {"ampersand", '&'}, + {"apostrophe", '\''}, + {"asciicircum", '^'}, + {"asciitilde", '~'}, + {"asterisk", '*'}, + {"at", '@'}, + {"backslash", '\\'}, + {"bar", '|'}, + {"braceleft", '{'}, + {"braceright", '}'}, + {"bracketleft", '['}, + {"bracketright", ']'}, + {"colon", ':'}, + {"comma", ','}, + {"dollar", '$'}, + {"equal", '='}, + {"exclam", '!'}, + {"grave", '`'}, + {"greater", '>'}, + {"less", '<'}, + {"minus", '-'}, + {"numbersign", '#'}, + {"parenleft", '('}, + {"parenright", ')'}, + {"percent", '%'}, + {"period", '.'}, + {"plus", '+'}, + {"question", '?'}, + {"quotedbl", '"'}, + {"semicolon", ';'}, + {"slash", '/'}, + {"space", ' '}, + {"tab", '\t'}, + {"underscore", '_'}, + {NULL, 0}, +}; + +/** + * \brief Find X11 string representation of a symbol. + * \param k human string representation of the symbol + * \return X11 string representation of the symbol + */ +static char* find_symbol(const char* k) +{ + size_t i = 0; + + while(g_symbolmap[i]) + { + if(!strcmp(g_symbolmap[i], k)) + { + return g_symbolmap[i + 1]; + } + + i += 2; + } + + return NULL; +} + +/** + * \brief Find X11 string representation of a special character. + * \param k ascii representation of the special character + * \return X11 string representation of the special character + */ +static char* find_keysym(char k) +{ + size_t i = 0; + + while(g_specialcharmap[i].key) + { + keysymcharmap_t ks = g_specialcharmap[i]; + + if(ks.key == k) + { + return ks.keysym; + } + + i++; + } + + return NULL; +} + +void generateSymbol(const char* symbol, jboolean pressed) +{ + Display *dpy = NULL; + char* s = NULL; + + dpy = XOpenDisplay(NULL); + + if(!dpy) + { + return; + } + + s = find_symbol(symbol); + + if(!s) + { + /* printf("no symbol %s\n", s); */ + XCloseDisplay(dpy); + return; + } + + XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, XStringToKeysym(s)), pressed ? True : False, 1); + + XFlush(dpy); + XCloseDisplay(dpy); +} + +void generateKey(jchar key, jboolean pressed) +{ + Display *dpy = NULL; + + dpy = XOpenDisplay(NULL); + + if(!dpy) + { + return; + } + + KeySym sym = XStringToKeysym((const char*)&key); + KeyCode code; + + if(sym == NoSymbol) + { + char* special = find_keysym(key); + + if(special) + { + sym = XStringToKeysym(special); + } + else + { + XCloseDisplay(dpy); + return; + } + } + + code = XKeysymToKeycode(dpy, sym); + + XTestFakeKeyEvent(dpy, code, pressed ? True : False, 1); + + XFlush(dpy); + XCloseDisplay(dpy); +} + diff --git a/src/native/hid/KeyboardUtil_windows.c b/src/native/hid/KeyboardUtil_windows.c new file mode 100644 index 0000000..ce5993a --- /dev/null +++ b/src/native/hid/KeyboardUtil_windows.c @@ -0,0 +1,132 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +/** + * \file KeyboardUtil_unix.c + * \brief Windows specific code to press/release keys. + * \author Sebastien Vincent + */ + +#include <windows.h> + +#include "KeyboardUtil.h" + +void generateSymbol(const char* symbol, jboolean pressed) +{ + /* on Windows AltGr correspond to CTRL-ALT */ + if(!strcmp(symbol, "altgr")) + { + int scancode = MapVirtualKey(VK_CONTROL, 0); + keybd_event(VK_CONTROL, scancode, pressed ? 0 : KEYEVENTF_KEYUP, 0); + scancode = MapVirtualKey(VK_MENU, 0); + keybd_event(VK_MENU, scancode, pressed ? 0 : KEYEVENTF_KEYUP, 0); + } + else if(!strcmp(symbol, "shift")) + { + int scancode = MapVirtualKey(VK_SHIFT, 0); + keybd_event(VK_SHIFT, scancode, pressed ? 0 : KEYEVENTF_KEYUP, 0); + } + else if(!strcmp(symbol, "ctrl")) + { + int scancode = MapVirtualKey(VK_CONTROL, 0); + keybd_event(VK_CONTROL, scancode, pressed ? 0 : KEYEVENTF_KEYUP, 0); + } + else if(!strcmp(symbol, "alt")) + { + int scancode = MapVirtualKey(VK_MENU, 0); + keybd_event(VK_MENU, scancode, pressed ? 0 : KEYEVENTF_KEYUP, 0); + } + else if(!strcmp(symbol, "hankaku")) + { + /* XXX constant name for HANKAKU ? */ + /* + int scancode = MapVirtualKey(VK_HANKAKU, 0); + keybd_event(VK_HANKAKU, scancode, pressed ? 0 : KEYEVENTF_KEYUP, 0); + */ + } +} + +void generateKey(jchar key, jboolean pressed) +{ + SHORT letter = 0; + TCHAR ch = key; + UINT scancode = 0; + SHORT modifiers = 0; + + letter = VkKeyScan(ch); + + if(letter == -1) + { + /* printf("No key found\n"); */ + return; + } + + modifiers = HIBYTE(letter); + letter = LOBYTE(letter); + + if(pressed) + { + /* shift */ + if(modifiers & 1) + { + generateSymbol("shift", JNI_TRUE); + } + + /* ctrl */ + if(modifiers & 2) + { + generateSymbol("ctrl", JNI_TRUE); + } + + /* alt */ + if(modifiers & 4) + { + generateSymbol("alt", JNI_TRUE); + } + + /* hankaku */ + if(modifiers & 8) + { + generateSymbol("hankaku", JNI_TRUE); + } + } + + /* find scancode */ + scancode = MapVirtualKey(letter, 0); + + /* press and release key as well as modifiers */ + keybd_event(letter, scancode, pressed ? 0 : KEYEVENTF_KEYUP, 0); + + if(!pressed) + { + /* shift */ + if(modifiers & 1) + { + generateSymbol("shift", JNI_FALSE); + } + + /* ctrl */ + if(modifiers & 2) + { + generateSymbol("ctrl", JNI_FALSE); + } + + /* alt */ + if(modifiers & 4) + { + generateSymbol("alt", JNI_FALSE); + } + + /* hankaku */ + if(modifiers & 8) + { + generateSymbol("hankaku", JNI_FALSE); + } + } +} + + diff --git a/src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.c b/src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.c new file mode 100644 index 0000000..1233e32 --- /dev/null +++ b/src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.c @@ -0,0 +1,59 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +/** + * \file net_java_sip_communicator_util_KeyboardUtil.c + * \brief Native method to get keycode from ascii. + * \author Sebastien Vincent + */ + +#include "net_java_sip_communicator_impl_hid_NativeKeyboard.h" + +#include "KeyboardUtil.h" + +/** + * \brief Press or release a key. + * \param env JNI environment + * \param clazz class + * \param key string representation of the key + * \param pressed true if the key has to be pressed, false if the key has to be released + */ +JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_hid_NativeKeyboard_doKeyAction + (JNIEnv *env, jclass clazz, jchar key, jboolean pressed) +{ + /* avoid warnings */ + env = env; + clazz = clazz; + + generateKey(key, pressed); +} + +/** + * \brief Press or release a symbol (i.e. CTRL, ALT, ...). + * \param env JNI environment + * \param clazz class + * \param symbol symbol string representation + * \param pressed true if the key has to be pressed, false if the key has to be released + */ +JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_hid_NativeKeyboard_doSymbolAction + (JNIEnv *env, jclass clazz, jstring symbol, jboolean pressed) +{ + const char* s; + + /* avoid warnings */ + env = env; + clazz = clazz; + + s = (*env)->GetStringUTFChars(env, symbol, 0); + + if(s) + { + generateSymbol(s, pressed); + (*env)->ReleaseStringUTFChars(env, symbol, s); + } +} + diff --git a/src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.h b/src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.h new file mode 100644 index 0000000..a59b9f9 --- /dev/null +++ b/src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class net_java_sip_communicator_impl_hid_NativeKeyboard */ + +#ifndef _Included_net_java_sip_communicator_impl_hid_NativeKeyboard +#define _Included_net_java_sip_communicator_impl_hid_NativeKeyboard +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: net_java_sip_communicator_impl_hid_NativeKeyboard + * Method: doKeyAction + * Signature: (CZ)V + */ +JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_hid_NativeKeyboard_doKeyAction + (JNIEnv *, jclass, jchar, jboolean); + +/* + * Class: net_java_sip_communicator_impl_hid_NativeKeyboard + * Method: doSymbolAction + * Signature: (Ljava/lang/String;Z)V + */ +JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_hid_NativeKeyboard_doSymbolAction + (JNIEnv *, jclass, jstring, jboolean); + +#ifdef __cplusplus +} +#endif +#endif |