-
-
Save xranby/ec17597f5c079708ce72 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2013 JogAmp Community. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without modification, are | |
* permitted provided that the following conditions are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright notice, this list of | |
* conditions and the following disclaimer. | |
* | |
* 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
* of conditions and the following disclaimer in the documentation and/or other materials | |
* provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR | |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* | |
* The views and conclusions contained in the software and documentation are those of the | |
* authors and should not be interpreted as representing official policies, either expressed | |
* or implied, of JogAmp Community. | |
*/ | |
package jogamp.newt.driver.linux; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.nio.ByteBuffer; | |
import jogamp.newt.WindowImpl; | |
import com.jogamp.common.nio.StructAccessor; | |
import com.jogamp.newt.event.InputEvent; | |
import com.jogamp.newt.event.WindowEvent; | |
import com.jogamp.newt.event.WindowListener; | |
import com.jogamp.newt.event.WindowUpdateEvent; | |
import com.jogamp.newt.event.KeyEvent; | |
/** | |
* Experimental native event device tracker thread for GNU/Linux | |
* just reading <code>/dev/input/event*</code> | |
* within it's own polling thread. | |
*/ | |
public class LinuxEventDeviceTracker implements WindowListener { | |
private static final LinuxEventDeviceTracker ledt; | |
static { | |
ledt = new LinuxEventDeviceTracker(); | |
final Thread t = new Thread(ledt.eventDevicePoller, "NEWT-LinuxEventDeviceTracker"); | |
t.setDaemon(true); | |
t.start(); | |
} | |
public static LinuxEventDeviceTracker getSingleton() { | |
return ledt; | |
} | |
private volatile boolean stop = false; | |
private WindowImpl focusedWindow = null; | |
private EventDevicePoller eventDevicePoller = new EventDevicePoller(); | |
@Override | |
public void windowResized(WindowEvent e) { } | |
@Override | |
public void windowMoved(WindowEvent e) { } | |
@Override | |
public void windowDestroyNotify(WindowEvent e) { | |
Object s = e.getSource(); | |
if(focusedWindow == s) { | |
focusedWindow = null; | |
} | |
} | |
@Override | |
public void windowDestroyed(WindowEvent e) { } | |
@Override | |
public void windowGainedFocus(WindowEvent e) { | |
Object s = e.getSource(); | |
if(s instanceof WindowImpl) { | |
focusedWindow = (WindowImpl) s; | |
} | |
} | |
@Override | |
public void windowLostFocus(WindowEvent e) { | |
Object s = e.getSource(); | |
if(focusedWindow == s) { | |
focusedWindow = null; | |
} | |
} | |
public static void main(String[] args ){ | |
LinuxEventDeviceTracker.getSingleton(); | |
try { | |
Thread.sleep(30000); | |
} catch (InterruptedException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
@Override | |
public void windowRepaint(WindowUpdateEvent e) { } | |
class EventDevicePoller implements Runnable { | |
@Override | |
public void run() { | |
final byte[] b = new byte[16]; | |
/** | |
* The Linux input event interface. | |
* http://www.kernel.org/doc/Documentation/input/input.txt | |
* | |
* struct input_event { | |
* struct timeval time; | |
* unsigned short type; | |
* unsigned short code; | |
* unsigned int value; | |
* }; | |
*/ | |
ByteBuffer bb = ByteBuffer.wrap(b); | |
StructAccessor s = new StructAccessor(bb); | |
final File f = new File("/dev/input/event2"); | |
f.setReadOnly(); | |
InputStream fis; | |
try { | |
fis = new FileInputStream(f); | |
} catch (FileNotFoundException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
return; | |
} | |
int timeSeconds; | |
int timeSecondFraction; | |
short type; | |
short code; | |
int value; | |
int keyCode=KeyEvent.VK_UNDEFINED; | |
char keyChar=' '; | |
int eventType=0; | |
int modifiers=0; | |
while(!stop) { | |
int remaining=16; | |
while(remaining>0) { | |
int read = 0; | |
try { | |
read = fis.read(b, 0, remaining); | |
} catch (IOException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
if(read<0) { | |
stop = true; // EOF of event device file !? | |
} else { | |
remaining -= read; | |
} | |
} | |
timeSeconds = s.getIntAt(0); | |
timeSecondFraction = s.getShortAt(4); | |
type = s.getShortAt(8); | |
code = s.getShortAt(10); | |
value = s.getIntAt(12); | |
if(null != focusedWindow) { | |
/* | |
* Linux sends Keyboard events in the following order: | |
* EV_MSC (optional, contains scancode) | |
* EV_KEY | |
* SYN_REPORT (sent before next key) | |
*/ | |
switch(type) { | |
case 0: // SYN_REPORT | |
// Clear | |
eventType = 0; | |
keyCode = KeyEvent.VK_UNDEFINED; | |
keyChar = 0; // Print null for unprintable char. | |
modifiers = 0; | |
break; | |
case 1: // EV_KEY | |
keyCode = LinuxEVKey2NewtVKey(code); // The device independent code. | |
keyChar = LinuxEVKey2Unicode(code); // The printable character w/o key modifiers. | |
switch(value) { | |
case 0: | |
modifiers=0; | |
eventType=KeyEvent.EVENT_KEY_RELEASED; | |
focusedWindow.sendKeyEvent(eventType, modifiers, keyCode, keyChar); | |
//Send syntetic typed | |
focusedWindow.sendKeyEvent(KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, (char) keyChar); | |
break; | |
case 1: | |
eventType=KeyEvent.EVENT_KEY_PRESSED; | |
focusedWindow.sendKeyEvent(eventType, modifiers, keyCode, keyChar); | |
break; | |
case 2: | |
eventType=KeyEvent.EVENT_KEY_PRESSED; | |
modifiers=InputEvent.AUTOREPEAT_MASK; | |
//Send syntetic autorepeat release | |
focusedWindow.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keyChar); | |
//Send syntetic typed | |
focusedWindow.sendKeyEvent(KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, keyChar); | |
focusedWindow.sendKeyEvent(eventType, modifiers, keyCode, keyChar); | |
break; | |
} | |
break; | |
case 4: // EV_MSC | |
if(code==4) { // MSC_SCAN | |
// scancode ignore, linux kernel specific | |
// keyCode = value; | |
} | |
break; | |
// TODO: handle joystick events | |
// TODO: handle mouse events | |
// TODO: handle headphone/hdmi connector events | |
} | |
//System.out.println("[time "+timeSeconds+":"+timeSecondFraction+"] type "+type+" / code "+code+" = value "+value); | |
} else { | |
//if(Window.DEBUG_KEY_EVENT) | |
System.out.println("[time "+timeSeconds+":"+timeSecondFraction+"] type "+type+" / code "+code+" = value "+value); | |
} | |
} | |
if(null != fis) { | |
try { | |
fis.close(); | |
} catch (IOException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
} | |
private char LinuxEVKey2Unicode(short EVKey) { | |
// This is the stuff normally mapped by a system keymap | |
switch(EVKey){ | |
case 17: // w | |
return 'w'; | |
case 31: // s | |
return 's'; | |
case 30: // a | |
return 'a'; | |
case 32: // d | |
return 'd'; | |
case 1: // ESC | |
return 27; | |
case 28: // Enter | |
case 96: // Keypad Enter | |
return '\n'; | |
case 57: // Space | |
return ' '; | |
case 11: // 0 | |
case 82: // Numpad 0 | |
return '0'; | |
case 2: // 1 | |
case 79: // Numpad 1 | |
return '1'; | |
case 3: // 2 | |
case 80: // Numpad 1 | |
return '2'; | |
case 4: // 3 | |
case 81: // Numpad 3 | |
return '3'; | |
case 5: // 4 | |
case 75: // Numpad 4 | |
return '4'; | |
case 6: // 5 | |
case 76: // Numpad 5 | |
return '5'; | |
case 7: // 6 | |
case 77: // Numpad 6 | |
return '6'; | |
case 8: // 7 | |
case 71: // Numpad 7 | |
return '7'; | |
case 9: // 8 | |
case 72: // Numpad 8 | |
return '8'; | |
case 10: // 9 | |
case 73: // Numpad 9 | |
return '9'; | |
default: | |
} | |
return 0; | |
} | |
static final short KEY_F1 = 59; | |
static final short KEY_F10 = 68; | |
static final short KEY_1 = 2; | |
static final short KEY_0 = 1; | |
private int LinuxEVKey2NewtVKey(short EVKey) { | |
char vkCode = KeyEvent.VK_UNDEFINED; | |
// F1 - F10 | |
if(isLinuxEVKeyWithin(EVKey, KEY_F1, KEY_F10)) | |
return (EVKey-KEY_F1)+KeyEvent.VK_F1; | |
switch(EVKey){ | |
case 103: // KEY_UP | |
return KeyEvent.VK_UP; | |
case 105: // KEY_LEFT | |
return KeyEvent.VK_LEFT; | |
case 106: // KEY_RIGHT | |
return KeyEvent.VK_RIGHT; | |
case 108: // KEY_DOWN | |
return KeyEvent.VK_DOWN; | |
case 14: // Backspace | |
return KeyEvent.VK_BACK_SPACE; | |
case 111: // del | |
return KeyEvent.VK_DELETE; | |
case 17: // w | |
return KeyEvent.VK_W; | |
case 31: // s | |
return KeyEvent.VK_S; | |
case 30: // a | |
return KeyEvent.VK_A; | |
case 32: // d | |
return KeyEvent.VK_D; | |
case 1: // ESC | |
return KeyEvent.VK_ESCAPE; | |
case 28: // Enter | |
case 96: // Keypad Enter | |
return KeyEvent.VK_ENTER; | |
case 57: // Space | |
return KeyEvent.VK_SPACE; | |
case 11: // 0 | |
return KeyEvent.VK_0; | |
case 82: // Numpad 0 | |
return KeyEvent.VK_NUMPAD0; | |
case 2: // 1 | |
return KeyEvent.VK_1; | |
case 79: // Numpad 1 | |
return KeyEvent.VK_NUMPAD1; | |
case 3: // 2 | |
return KeyEvent.VK_2; | |
case 80: // Numpad 2 | |
return KeyEvent.VK_NUMPAD2; | |
case 4: // 3 | |
return KeyEvent.VK_3; | |
case 81: // Numpad 3 | |
return KeyEvent.VK_NUMPAD3; | |
case 5: // 4 | |
return KeyEvent.VK_4; | |
case 75: // Numpad 4 | |
return KeyEvent.VK_NUMPAD4; | |
case 6: // 5 | |
return KeyEvent.VK_5; | |
case 76: // Numpad 5 | |
return KeyEvent.VK_NUMPAD5; | |
case 7: // 6 | |
return KeyEvent.VK_6; | |
case 77: // Numpad 6 | |
return KeyEvent.VK_NUMPAD6; | |
case 8: // 7 | |
return KeyEvent.VK_7; | |
case 71: // Numpad 7 | |
return KeyEvent.VK_NUMPAD7; | |
case 9: // 8 | |
return KeyEvent.VK_8; | |
case 72: // Numpad 8 | |
return KeyEvent.VK_NUMPAD8; | |
case 10: // 9 | |
return KeyEvent.VK_9; | |
case 73: // Numpad 9 | |
return KeyEvent.VK_NUMPAD9; | |
default: | |
//System.out.println("LinuxEVKey2NewtVKey: Unmapped EVKey "+EVKey); | |
} | |
return vkCode; | |
} | |
private boolean isLinuxEVKeyWithin(short eVKey, short min, | |
short max) { | |
if((eVKey>=min) && (eVKey<=max)) | |
return true; | |
return false; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment