1 /* Copyright 2008 Edwin Stang (edwinstang@gmail.com), 2 * 3 * This file is part of JXGrabKey. 4 * 5 * JXGrabKey is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * JXGrabKey is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with JXGrabKey. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 package jxgrabkey; 20 21 import java.awt.event.KeyEvent; 22 import java.util.Vector; 23 24 /** 25 * This class implements the API access. 26 * All public methods are synchronized, hence thread-safe. 27 * 28 * @author subes 29 */ 30 public class JXGrabKey { 31 32 private static final int SLEEP_WHILE_LISTEN_EXITS = 100; 33 34 private static boolean debug; 35 36 private static JXGrabKey instance; 37 private static Thread thread; 38 private static Vector<HotkeyListener> listeners = new Vector<HotkeyListener>(); 39 40 /** 41 * This constructor starts a seperate Thread for the main listen loop. 42 */ JXGrabKey()43 private JXGrabKey() { 44 thread = new Thread(){ 45 @Override 46 public void run() { 47 listen(); 48 debugCallback("-- listen()"); 49 } 50 }; 51 thread.start(); 52 } 53 54 /** 55 * Retrieves the singleton. Initializes it, if not yet done. 56 * 57 * @return 58 */ getInstance()59 public static synchronized JXGrabKey getInstance(){ 60 if(instance == null){ 61 instance = new JXGrabKey(); 62 } 63 return instance; 64 } 65 66 /** 67 * Adds a HotkeyListener. 68 * 69 * @param listener 70 */ addHotkeyListener(HotkeyListener listener)71 public void addHotkeyListener(HotkeyListener listener){ 72 if(listener == null){ 73 throw new IllegalArgumentException("listener must not be null"); 74 } 75 JXGrabKey.listeners.add(listener); 76 } 77 78 /** 79 * Removes a HotkeyListener. 80 * 81 * @param listener 82 */ removeHotkeyListener(HotkeyListener listener)83 public void removeHotkeyListener(HotkeyListener listener){ 84 if(listener == null){ 85 throw new IllegalArgumentException("listener must not be null"); 86 } 87 JXGrabKey.listeners.remove(listener); 88 } 89 90 /** 91 * Unregisters all hotkeys, removes all HotkeyListeners, 92 * stops the main listen loop and deinitializes the singleton. 93 */ cleanUp()94 public void cleanUp(){ 95 clean(); 96 if(thread.isAlive()){ 97 while(thread.isAlive()){ 98 try { 99 Thread.sleep(SLEEP_WHILE_LISTEN_EXITS); 100 } catch (InterruptedException e) { 101 debugCallback("cleanUp() - InterruptedException: "+e.getMessage()); 102 } 103 } 104 instance = null; //next time getInstance is called, reinitialize JXGrabKey 105 } 106 if(listeners.size() > 0){ 107 listeners.clear(); 108 } 109 } 110 111 /** 112 * Registers a X11 hotkey. 113 * 114 * @param id 115 * @param x11Mask 116 * @param x11Keysym 117 * @throws jxgrabkey.HotkeyConflictException 118 */ registerX11Hotkey(int id, int x11Mask, int x11Keysym)119 public void registerX11Hotkey(int id, int x11Mask, int x11Keysym) throws HotkeyConflictException{ 120 registerHotkey(id, x11Mask, x11Keysym); 121 } 122 123 /** 124 * Converts an AWT hotkey into a X11 hotkey and registers it. 125 * 126 * @param id 127 * @param awtMask 128 * @param awtKey 129 * @throws jxgrabkey.HotkeyConflictException 130 */ registerAwtHotkey(int id, int awtMask, int awtKey)131 public void registerAwtHotkey(int id, int awtMask, int awtKey) throws HotkeyConflictException{ 132 debugCallback("++ registerAwtHotkey("+id+", 0x"+ 133 Integer.toHexString(awtMask)+", 0x"+ 134 Integer.toHexString(awtKey)+")"); 135 136 int x11Mask = X11MaskDefinitions.awtMaskToX11Mask(awtMask); 137 int x11Keysym = X11KeysymDefinitions.awtKeyToX11Keysym(awtKey); 138 139 debugCallback("registerAwtHotkey() - converted AWT mask '"+ 140 KeyEvent.getKeyModifiersText(awtMask)+"' (0x"+Integer.toHexString(awtMask)+ 141 ") to X11 mask (0x"+Integer.toHexString(x11Mask)+")"); 142 143 debugCallback("registerAwtHotkey() - converted AWT key '"+ 144 KeyEvent.getKeyText(awtKey)+"' (0x"+Integer.toHexString(awtKey)+ 145 ") to X11 keysym (0x"+Integer.toHexString(x11Keysym)+")"); 146 147 registerHotkey(id, x11Mask, x11Keysym); 148 149 debugCallback("-- registerAwtHotkey()"); 150 } 151 152 /** 153 * Enables/Disables printing of debug messages. 154 * 155 * @param enabled 156 */ setDebugOutput(boolean enabled)157 public static void setDebugOutput(boolean enabled){ 158 debug = enabled; 159 setDebug(enabled); 160 } 161 162 /** 163 * Notifies HotkeyListeners about a received KeyEvent. 164 * 165 * This method is used by the C++ code. 166 * Do not use this method from externally. 167 * 168 * @param id 169 */ fireKeyEvent(int id)170 public static void fireKeyEvent(int id){ 171 for(int i = 0; i < listeners.size(); i++){ 172 listeners.get(i).onHotkey(id); 173 } 174 } 175 176 /** 177 * Either gives debug messages to a HotkeyListenerDebugEnabled if registered, 178 * or prints to console otherwise. 179 * Does only print if debug is enabled. 180 * 181 * This method is both used by the C++ and Java code, so it should not be synchronized. 182 * Don't use this method from externally. 183 * 184 * @param debugmessage 185 */ debugCallback(String debugmessage)186 public static void debugCallback(String debugmessage){ 187 if(debug){ 188 debugmessage.trim(); 189 if(debugmessage.charAt(debugmessage.length()-1) != '\n'){ 190 debugmessage += "\n"; 191 }else{ 192 while(debugmessage.endsWith("\n\n")){ 193 debugmessage = debugmessage.substring(0, debugmessage.length()-1); 194 } 195 } 196 197 boolean found = false; 198 for(HotkeyListener l : listeners){ 199 if(l instanceof HotkeyListenerDebugEnabled){ 200 ((HotkeyListenerDebugEnabled)l).debugCallback(debugmessage); 201 found = true; 202 } 203 } 204 205 if(found == false){ 206 System.out.print(debugmessage); 207 } 208 } 209 } 210 211 /** 212 * This method unregisters a hotkey. 213 * If the hotkey is not yet registered, nothing will happen. 214 * 215 * @param id 216 */ unregisterHotKey(int id)217 public native void unregisterHotKey(int id); 218 listen()219 private native void listen(); 220 setDebug(boolean debug)221 private static native void setDebug(boolean debug); 222 clean()223 private native void clean(); 224 registerHotkey(int id, int mask, int key)225 private native void registerHotkey(int id, int mask, int key) throws HotkeyConflictException; 226 227 } 228