/*
* Copyright (c) 2010-2016, Sikuli.org, sikulix.com
* Released under the MIT License.
*
*/
package org.sikuli.basics;
import java.awt.event.KeyEvent;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import org.sikuli.basics.Debug;
import org.sikuli.basics.PreferencesUser;
import org.sikuli.basics.Settings;
import org.sikuli.script.Key;
import org.sikuli.script.Key;
/**
* Singleton class to bind hotkeys to hotkey listeners
*/
public abstract class HotkeyManager {
private static HotkeyManager _instance = null;
private static Map<Integer, Integer> hotkeys;
private static Map<Integer, Integer> hotkeysGlobal = new HashMap<Integer, Integer>();
private static final String HotkeyTypeCapture = "Capture";
private static int HotkeyTypeCaptureKey;
private static int HotkeyTypeCaptureMod;
private static final String HotkeyTypeAbort = "Abort";
private static int HotkeyTypeAbortKey;
private static int HotkeyTypeAbortMod;
public static HotkeyManager getInstance() {
if (_instance == null) {
/* uncomment for debugging puposes
if (Settings.isWindows()) {
_instance = new WindowsHotkeyManager();
} else if (Settings.isMac()) {
_instance = new MacHotkeyManager();
} else if (Settings.isLinux()) {
_instance = new LinuxHotkeyManager();
}
return _instance;
*/
String cls = getOSHotkeyManagerClass();
if (cls != null) {
try {
Class c = Class.forName(cls);
Constructor constr = c.getConstructor();
_instance = (HotkeyManager) constr.newInstance();
} catch (Exception e) {
Debug.error("HotkeyManager: Can't create " + cls + ": " + e.getMessage());
}
}
hotkeys = new HashMap<Integer, Integer>();
}
return _instance;
}
/**
* remove all hotkeys
*/
public static void reset() {
if (_instance == null || hotkeys.isEmpty()) {
return;
}
Debug.log(3, "HotkeyManager: reset - removing all defined hotkeys.");
boolean res;
int[] hk = new int[hotkeys.size()];
int i = 0;
for (Integer k : hotkeys.keySet()) {
res = _instance._removeHotkey(k, hotkeys.get(k));
if (!res) {
Debug.error("HotkeyManager: reset: failed to remove hotkey: %s %s",
getKeyModifierText(hotkeys.get(k)), getKeyCodeText(k));
hk[i++] = -1;
} else {
hk[i++] = k;
Debug.log(3, "removed (%d, %d)" , k, hotkeys.get(k));
}
}
for (int k : hk) {
if (k == -1) {
continue;
}
hotkeys.remove(k);
}
}
private static String getOSHotkeyManagerClass() {
String pkg = "org.sikuli.basics.";
int theOS = Settings.getOS();
switch (theOS) {
case Settings.ISMAC:
return pkg + "MacHotkeyManager";
case Settings.ISWINDOWS:
return pkg + "WindowsHotkeyManager";
case Settings.ISLINUX:
return pkg + "LinuxHotkeyManager";
default:
Debug.error("HotkeyManager: Hotkey registration is not supported on your OS.");
}
return null;
}
private static String getKeyCodeText(int key) {
return KeyEvent.getKeyText(key).toUpperCase();
}
private static String getKeyModifierText(int modifiers) {
String txtMod = KeyEvent.getKeyModifiersText(modifiers).toUpperCase();
if (Settings.isMac()) {
txtMod = txtMod.replace("META", "CMD");
txtMod = txtMod.replace("WINDOWS", "CMD");
} else {
txtMod = txtMod.replace("META", "WIN");
txtMod = txtMod.replace("WINDOWS", "WIN");
}
return txtMod;
}
/**
* install a hotkey listener for a global hotkey (capture, abort, ...)
* @param hotkeyType a type string
* @param callback HotkeyListener
* @return success
*/
public boolean addHotkey(String hotkeyType, HotkeyListener callback) {
PreferencesUser pref = PreferencesUser.getInstance();
if (hotkeyType == HotkeyTypeCapture) {
HotkeyTypeCaptureKey = pref.getCaptureHotkey();
HotkeyTypeCaptureMod = pref.getCaptureHotkeyModifiers();
return installHotkey(HotkeyTypeCaptureKey, HotkeyTypeCaptureMod, callback, hotkeyType);
} else if (hotkeyType == HotkeyTypeAbort) {
HotkeyTypeAbortKey = pref.getStopHotkey();
HotkeyTypeAbortMod = pref.getStopHotkeyModifiers();
return installHotkey(HotkeyTypeAbortKey, HotkeyTypeAbortMod, callback, hotkeyType);
} else {
Debug.error("HotkeyManager: addHotkey: HotkeyType %s not supported", hotkeyType);
return false;
}
}
public String getHotKeyText(String hotkeyType) {
PreferencesUser pref = PreferencesUser.getInstance();
String key = "";
String mod = "";
if (hotkeyType == HotkeyTypeCapture) {
key = getKeyCodeText(pref.getCaptureHotkey());
mod = getKeyModifierText(pref.getCaptureHotkeyModifiers());
} else if (hotkeyType == HotkeyTypeAbort) {
key = getKeyCodeText(pref.getStopHotkey());
mod = getKeyModifierText(pref.getStopHotkeyModifiers());
} else {
Debug.error("HotkeyManager: getHotKeyText: HotkeyType %s not supported", hotkeyType);
}
return mod + " " + key;
}
/**
* install a hotkey listener.
*
* @param key key character (class Key)
* @param modifiers modifiers flag
* @param callback HotkeyListener
* @return true if success. false otherwise.
*/
public boolean addHotkey(char key, int modifiers, HotkeyListener callback) {
return addHotkey("" + key, modifiers, callback);
}
/**
* install a hotkey listener.
*
* @param key key character (class Key)
* @param modifiers modifiers flag
* @param callback HotkeyListener
* @return true if success. false otherwise.
*/
public boolean addHotkey(String key, int modifiers, HotkeyListener callback) {
int[] keyCodes = Key.toJavaKeyCode(key.toLowerCase());
int keyCode = keyCodes[0];
return installHotkey(keyCode, modifiers, callback, "");
}
private boolean installHotkey(int key, int mod, HotkeyListener callback, String hotkeyType) {
boolean res;
String txtMod = getKeyModifierText(mod);
String txtCode = getKeyCodeText(key);
Debug.info("HotkeyManager: add %s Hotkey: %s %s (%d, %d)" , hotkeyType, txtMod, txtCode, key, mod);
boolean checkGlobal = true;
for (Integer k : hotkeys.keySet()) {
if (k == key && mod == hotkeys.get(key)) {
res = _instance._removeHotkey(key, hotkeys.get(key));
if (!res) {
Debug.error("HotkeyManager: addHotkey: failed to remove already defined hotkey");
return false;
} else {
checkGlobal = false;
}
}
}
if (checkGlobal) {
for (Integer kg : hotkeysGlobal.keySet()) {
if (kg == key && mod == hotkeysGlobal.get(key)) {
Debug.error("HotkeyManager: addHotkey: ignored: trying to redefine a global hotkey");
return false;
}
}
}
res = _instance._addHotkey(key, mod, callback);
if (res) {
if (hotkeyType.isEmpty()) {
hotkeys.put(key, mod);
} else {
hotkeysGlobal.put(key, mod);
}
} else {
Debug.error("HotkeyManager: addHotkey: failed");
}
return res;
}
/**
* remove a hotkey by type (not supported yet)
* @param hotkeyType capture, abort, ...
* @return success
*/
public boolean removeHotkey(String hotkeyType) {
if (hotkeyType == HotkeyTypeCapture) {
return uninstallHotkey(HotkeyTypeCaptureKey, HotkeyTypeCaptureMod, hotkeyType);
} else if (hotkeyType == HotkeyTypeAbort) {
return uninstallHotkey(HotkeyTypeAbortKey, HotkeyTypeAbortMod, hotkeyType);
} else {
Debug.error("HotkeyManager: removeHotkey: using HotkeyType as %s not supported yet", hotkeyType);
return false;
}
}
/**
* remove a hotkey and uninstall a hotkey listener.
*
* @param key key character (class Key)
* @param modifiers modifiers flag
* @return true if success. false otherwise.
*/
public boolean removeHotkey(char key, int modifiers) {
return removeHotkey("" + key, modifiers);
}
/**
* uninstall a hotkey listener.
*
* @param key key string (class Key)
* @param modifiers modifiers flag
* @return true if success. false otherwise.
*/
public boolean removeHotkey(String key, int modifiers) {
int[] keyCodes = Key.toJavaKeyCode(key.toLowerCase());
int keyCode = keyCodes[0];
return uninstallHotkey(keyCode, modifiers, "");
}
private boolean uninstallHotkey(int key, int mod, String hotkeyType) {
boolean res;
String txtMod = getKeyModifierText(mod);
String txtCode = getKeyCodeText(key);
Debug.info("HotkeyManager: remove %s Hotkey: %s %s (%d, %d)" , hotkeyType, txtMod, txtCode, key, mod);
res = _instance._removeHotkey(key, mod);
if (res) {
hotkeys.remove(key);
} else {
Debug.error("HotkeyManager: removeHotkey: failed");
}
return res;
}
abstract public boolean _addHotkey(int keyCode, int modifiers, HotkeyListener callback);
abstract public boolean _removeHotkey(int keyCode, int modifiers);
abstract public void cleanUp();
}