aboutsummaryrefslogtreecommitdiffstats
path: root/src/native/hid
diff options
context:
space:
mode:
authorSebastien Vincent <seb@jitsi.org>2010-09-28 07:46:45 +0000
committerSebastien Vincent <seb@jitsi.org>2010-09-28 07:46:45 +0000
commit6a67589c86221faedcebd370824274013be64026 (patch)
treeb5a73d1deec90532057f70b801cafaa015a907e0 /src/native/hid
parenta4ddb0361ebc3848e30eefbf0391c755adb3387c (diff)
downloadjitsi-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.h34
-rw-r--r--src/native/hid/KeyboardUtil_mac.c228
-rw-r--r--src/native/hid/KeyboardUtil_unix.c203
-rw-r--r--src/native/hid/KeyboardUtil_windows.c132
-rw-r--r--src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.c59
-rw-r--r--src/native/hid/net_java_sip_communicator_impl_hid_NativeKeyboard.h29
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