OSDN Git Service

lejos_NXJ_win32_0_6_0beta.zip
[nxt-jsp/lejos_nxj.git] / nxtOSEK / lejos_nxj / src / java / classes / lejos / devices / Keyboard.java
diff --git a/nxtOSEK/lejos_nxj/src/java/classes/lejos/devices/Keyboard.java b/nxtOSEK/lejos_nxj/src/java/classes/lejos/devices/Keyboard.java
new file mode 100644 (file)
index 0000000..cbf76eb
--- /dev/null
@@ -0,0 +1,170 @@
+package lejos.devices;\r
+\r
+import java.io.*;\r
+\r
+/*\r
+ * Developer Notes:\r
+ * The following document explains keyboard control:\r
+ * http://www.computer-engineering.org/ps2keyboard/\r
+ */\r
+\r
+/**\r
+ * This class will only work with SPP keyboards, not standard HID\r
+ * keyboards. If it doesn't say it supports Bluetooth SPP then it\r
+ * will not work. There are only two known SPP models (also available\r
+ * on eBay or Amazon):\r
+ * Freedom Universal Bluetooth keyboard\r
+ * http://www.freedominput.com\r
+ * iTech Virtual Keyboard (SPP only)\r
+ * http://www.virtual-laser-keyboard.com/\r
+ * \r
+ * Note: This class is currently only tested with Freedom Universal\r
+ * \r
+ */\r
+// TODO: Create a method that returns a stream of ASCII from keyboard. Thread handles keep alive, auto connect\r
+// and reconnecting if disconnected.\r
+// TODO: Currently only handles make code. Need break code (key release).\r
+// TODO: Repeat when key held down. (See above)\r
+\r
+\r
+// Typematic Key Repeat:\r
+// Typematic delay - 0.25 seconds to 1.00 second (500ms default)\r
+// Typematic rate - 2.0 cps (characters per second) to 30.0 cps (10.9 default)\r
+// "Set Typematic Rate/Delay" (0xF3) command\r
+// Typematic data is not buffered within the keyboard.  In the case \r
+// where more than one key is held down, only the last key pressed \r
+// becomes typematic.  Typematic repeat then stops when that key is \r
+// released, even though other keys may be held down.\r
+\r
+public class Keyboard extends Thread {\r
+       \r
+       /**\r
+        * Command used by keyboards. Full list of commands can be found here:\r
+        * http://www.computer-engineering.org/ps2keyboard/\r
+        */\r
+       private static int ECHO = 0xEE; \r
+       \r
+       /**\r
+        * Time between echo command sent to keyboard to prevent it\r
+        * from going to sleep. Universal Keyboard sleeps after 5000 ms\r
+        */\r
+       private static int KEEP_ALIVE_DELAY = 4000; // milliseconds\r
+       \r
+       private static int MAX_LISTENERS = 3;\r
+       \r
+       private InputStream in = null;\r
+       private OutputStream out = null;\r
+       \r
+       // Use Vector? Resizable array?\r
+       private KeyListener [] listeners = new KeyListener[MAX_LISTENERS];\r
+               \r
+       /**\r
+        * The index of this array is the Scan Code (e.g. 0x1C) and the\r
+        * value at that index is the appropriate ASCII key (without shift key).\r
+        * NOTE: There is no ASCII Caps Lock for 0x58. There is shift-in and shift-out, but that\r
+        * seems to have a different function than Caps (i.e. Caps only applies to A-Z, but shift \r
+        * applies to number keys displaying symbols).\r
+        * Note: Scan code 0x12 is left-shift, however ASCII has shift-in (0x0F) and shift-out (0x0E) so\r
+        * I'm uncertain how to handle this as a stream. Will have to do some special case statements. This\r
+        * might not really be a factor anyway since shifts probably irrelevant to ASCII stream.\r
+        * Note: ASCII has "Device Control" 1-4 I'm assuming ALT and CTRL fit in here. Maybe Fn. Maybe Windows key. \r
+        * Again, these might be irrelevant to ASCII stream.\r
+        * NOTE: Enter - equivalent to line feed? (ASCII 0x0A) Should stream\r
+        * send two characters: line feed and carriage return?\r
+        * NOTE: There are no ASCII characters for arrow keys.\r
+        */\r
+       // 64 unique keys on Freedom Universal, array is 113, many blanks       \r
+       private static byte [] scanCodes = {\r
+               0,0,0,0,0,0,0,0x14,0,0,0,0,0,0x09,0x60,0, // 0x00\r
+               0,0x12,0x0F,0x12,0x11,0x71,0x31,0,0,0,0x7A,0x73,0x61,0x77,0x32,0, // 0x10\r
+               0,0x63,0x78,0x64,0x65,0x34,0x33,0,0,0x20,0x76,0x66,0x74,0x72,0x35,0, // 0x20\r
+               0,0x6E,0x62,0x68,0x67,0x79,0x36,0,0,0,0x6D,0x6A,0x75,0x37,0x38,0, // 0x30\r
+               0,0,0x6B,0x69,0x6F,0x30,0x39,0,0,0x2E,0x2F,0x6C,0x3B,0x70,0x2D,0, // 0x40\r
+               0,0,0x27,0,0x5B,0x3D,0,0,0x00,0x0F,0x0A,0x5D,0x20,0x5C,0,0, // 0x50\r
+               0,0,0,0,0,0,0x7F,0,0,0,0,0,0,0,0,0, // 0x60\r
+               0,0x08 // 0x70\r
+       }; \r
+       \r
+       public Keyboard(InputStream in, OutputStream out) {\r
+               this.in = in;\r
+               this.out = out;\r
+               this.setDaemon(true);\r
+               this.start();\r
+       }\r
+       \r
+       // TODO: Make InputStream that implements KeyListener, outputs ASCII\r
+       public void addKeyListener(KeyListener l) {\r
+               // !! Test code until I figure out storage object\r
+               listeners[0] = l;\r
+       }\r
+       \r
+       public void removeKeylistener(KeyListener l) {\r
+               // !! Test code until I figure out storage object\r
+               listeners[0] = null;\r
+       }\r
+       \r
+       private void notifyListeners(KeyEvent e) {\r
+               // !! Test code until I figure out storage object\r
+               if(e.getID() == KeyEvent.KEY_PRESSED)\r
+                       listeners[0].keyPressed(e);\r
+               else if(e.getID() == KeyEvent.KEY_RELEASED)\r
+                       listeners[0].keyReleased(e);\r
+               else if(e.getID() == KeyEvent.KEY_TYPED)\r
+                       listeners[0].keyTyped(e);\r
+       }\r
+       \r
+       /**\r
+        * Converts raw keyboard scan code into ASCII.\r
+        * Works with lower case only.\r
+        * @param scanCode\r
+        * @return the ascii character\r
+        */\r
+       // TODO: Make private\r
+       public static byte getASCII(byte scanCode) {\r
+               if(scanCode < 0) // bit 8 makes value 0\r
+                       return 0; // !! Need to handle break code here\r
+               return scanCodes[scanCode]; // !! handles make codes only\r
+       }\r
+       \r
+       public void run() {\r
+               //Debug.out("Keyboard thread started.\n");\r
+               int previousEcho = (int)System.currentTimeMillis();\r
+               while(true) {\r
+                       \r
+                       // Keep-alive code:\r
+                       int now = (int)System.currentTimeMillis();\r
+                       if(now - previousEcho >= KEEP_ALIVE_DELAY) {\r
+                               try {\r
+                                       //Debug.out("Echo Sent\n");\r
+                                       out.write(ECHO);\r
+                                       out.flush();\r
+                               } catch(IOException e) {/*Debug.out("COMMAND EXCEPTION");*/}\r
+                               previousEcho = now;\r
+                       }\r
+\r
+                       // Notifier code:\r
+                       try {\r
+                               if(in.available() > 0) { // Check if byte available.\r
+                                       int bval = in.read();\r
+                                       KeyEvent e = getKeyEvent(bval, now);\r
+                                       if(e != null) notifyListeners(e); // ignore non-chars\r
+                               }\r
+                       } catch(IOException e) {/*Debug.out("EXCEPTION");*/}\r
+                       Thread.yield();\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Helper method to generate keyEvent from scan code from keyboard \r
+        * @return\r
+        */\r
+       private KeyEvent getKeyEvent(int scanCode, int timeStamp) {\r
+               // TEST CODE:\r
+               char curChar = (char)Keyboard.getASCII((byte)scanCode);\r
+               if((byte)scanCode < 0) return null; // if 8th bit on (i.e. key release)\r
+               KeyEvent e = new KeyEvent(this, KeyEvent.KEY_PRESSED, timeStamp, 0, 0, curChar);\r
+               //Debug.out(++sentenceCount + ": " + bval + " = " + (char)Keyboard.getASCII((byte)bval) + "\n");\r
+               //System.out.println("" + (char)Keyboard.getASCII((byte)scanCode));\r
+               return e;\r
+       }\r
+}\r