PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/org/spoutcraft/client/controls/SimpleKeyBindingManager.java

https://bitbucket.org/kingbowser/hysteria-spoutcraft
Java | 358 lines | 294 code | 24 blank | 40 comment | 101 complexity | a2e3ff09ae275e3a3d9b86c6e4975762 MD5 | raw file
  1. /*
  2. * This file is part of Hysteria-Spoutcraft.
  3. *
  4. * Copyright (c) 2011 Hysteria Group <http://www.hysteria.us.pn/>
  5. * Hysteria-Spoutcraft is licensed under the GNU Lesser General Public License.
  6. *
  7. * Hysteria-Spoutcraft is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Hysteria-Spoutcraft is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /*
  21. * This file is part of Spoutcraft.
  22. *
  23. * Copyright (c) 2011 Spout LLC <http://www.spout.org/>
  24. * Spoutcraft is licensed under the GNU Lesser General Public License.
  25. *
  26. * Spoutcraft is free software: you can redistribute it and/or modify
  27. * it under the terms of the GNU Lesser General Public License as published by
  28. * the Free Software Foundation, either version 3 of the License, or
  29. * (at your option) any later version.
  30. *
  31. * Spoutcraft is distributed in the hope that it will be useful,
  32. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  33. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  34. * GNU Lesser General Public License for more details.
  35. *
  36. * You should have received a copy of the GNU Lesser General Public License
  37. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  38. */
  39. package org.spoutcraft.client.controls;
  40. import java.io.File;
  41. import java.io.FileReader;
  42. import java.io.FileWriter;
  43. import java.io.IOException;
  44. import java.util.ArrayList;
  45. import java.util.Collections;
  46. import java.util.HashMap;
  47. import java.util.List;
  48. import org.lwjgl.input.Keyboard;
  49. import org.yaml.snakeyaml.Yaml;
  50. import org.yaml.snakeyaml.introspector.BeanAccess;
  51. import net.minecraft.src.Block;
  52. import net.minecraft.src.GuiScreen;
  53. import net.minecraft.src.GuiChat;
  54. import org.spoutcraft.api.Spoutcraft;
  55. import org.spoutcraft.api.gui.ScreenType;
  56. import org.spoutcraft.api.keyboard.AbstractBinding;
  57. import org.spoutcraft.api.keyboard.KeyBinding;
  58. import org.spoutcraft.api.keyboard.KeyBindingManager;
  59. import org.spoutcraft.api.keyboard.KeyBindingPress;
  60. import org.spoutcraft.client.SpoutClient;
  61. import org.spoutcraft.client.gui.controls.GuiControls;
  62. import org.spoutcraft.client.io.FileUtil;
  63. import org.spoutcraft.client.packet.PacketKeyBinding;
  64. public class SimpleKeyBindingManager implements KeyBindingManager {
  65. private ArrayList<KeyBinding> bindings;
  66. private ArrayList<Shortcut> shortcuts = new ArrayList<Shortcut>();
  67. private HashMap<Integer, ArrayList<AbstractBinding>> bindingsForKey = new HashMap<Integer, ArrayList<AbstractBinding>>();
  68. public static final int MOUSE_OFFSET = -100;
  69. public SimpleKeyBindingManager() {
  70. }
  71. public void registerControl(KeyBinding binding) {
  72. KeyBinding result = null;
  73. for (KeyBinding check:bindings) {
  74. if (check.getId().equals(binding.getId()) && check.getAddonName().equals(binding.getAddonName())) {
  75. result = check;
  76. }
  77. }
  78. if (result != null) {
  79. result.takeChanges(binding);
  80. } else {
  81. bindings.add(binding);
  82. }
  83. updateBindings();
  84. save();
  85. }
  86. public void registerShortcut(Shortcut shortcut) {
  87. shortcuts.add(shortcut);
  88. updateBindings();
  89. save();
  90. }
  91. public void unregisterShortcut(Shortcut shortcut) {
  92. if (shortcut == null) {
  93. return;
  94. }
  95. shortcuts.remove(shortcut);
  96. if (bindingsForKey.get(shortcut.getKey()) == null) {
  97. return;
  98. }
  99. bindingsForKey.get(shortcut.getKey()).remove(shortcut);
  100. save();
  101. }
  102. public void unregisterControl(KeyBinding binding) {
  103. if (binding == null) {
  104. return;
  105. }
  106. bindings.remove(binding);
  107. if (bindingsForKey.get(binding.getKey()) == null) {
  108. return;
  109. }
  110. bindingsForKey.get(binding.getKey()).remove(binding);
  111. save();
  112. }
  113. public void updateBindings() {
  114. if (bindings == null) {
  115. bindings = new ArrayList<KeyBinding>();
  116. }
  117. if (shortcuts == null) {
  118. shortcuts = new ArrayList<Shortcut>();
  119. }
  120. bindingsForKey.clear();
  121. for (KeyBinding binding:bindings) {
  122. ArrayList<AbstractBinding> bindings = bindingsForKey.get(binding.getKey());
  123. if (bindings == null) {
  124. bindings = new ArrayList<AbstractBinding>();
  125. bindingsForKey.put(binding.getKey(), bindings);
  126. }
  127. bindings.add(binding);
  128. }
  129. for (Shortcut binding:shortcuts) {
  130. ArrayList<AbstractBinding> bindings = bindingsForKey.get(binding.getKey());
  131. if (bindings == null) {
  132. bindings = new ArrayList<AbstractBinding>();
  133. bindingsForKey.put(binding.getKey(), bindings);
  134. }
  135. bindings.add(binding);
  136. }
  137. }
  138. public void save() {
  139. Yaml yaml = new Yaml();
  140. yaml.setBeanAccess(BeanAccess.FIELD); // To ignore transient fields
  141. try {
  142. // KeyBindings saving
  143. FileWriter writer = new FileWriter(getBindingsFile());
  144. ArrayList<Object> kbsave = new ArrayList<Object>();
  145. for (KeyBinding binding:bindings) {
  146. HashMap<String, Object> item = new HashMap<String, Object>();
  147. item.put("key", binding.getKey());
  148. item.put("id", binding.getId());
  149. item.put("description", binding.getDescription());
  150. item.put("addonName", binding.getAddonName());
  151. item.put("modifiers", binding.getModifiers());
  152. kbsave.add(item);
  153. }
  154. yaml.dump(kbsave, writer);
  155. // Shortcuts saving
  156. writer = new FileWriter(getShortcutsFile());
  157. ArrayList<Object> shsave = new ArrayList<Object>();
  158. for (Shortcut sh:shortcuts) {
  159. HashMap<String, Object> item = new HashMap<String, Object>();
  160. item.put("title", sh.getTitle());
  161. item.put("key", sh.getKey());
  162. item.put("modifiers", sh.getModifiers());
  163. item.put("commands", sh.getCommands());
  164. item.put("delay", sh.getDelay());
  165. shsave.add(item);
  166. }
  167. yaml.dump(shsave, writer);
  168. } catch (IOException e) {
  169. e.printStackTrace();
  170. }
  171. }
  172. private File getBindingsFile() throws IOException {
  173. File file = new File(FileUtil.getConfigDir(), "bindings.yml");
  174. if (!file.exists()) {
  175. file.createNewFile();
  176. }
  177. return file;
  178. }
  179. private File getShortcutsFile() throws IOException {
  180. File file = new File(FileUtil.getConfigDir(), "shortcuts.yml");
  181. if (!file.exists()) {
  182. file.createNewFile();
  183. }
  184. return file;
  185. }
  186. @SuppressWarnings("unchecked")
  187. public void load() {
  188. Yaml yaml = new Yaml();
  189. try {
  190. bindings = new ArrayList<KeyBinding>();
  191. ArrayList<Object> kbsave = yaml.loadAs(new FileReader(getBindingsFile()), ArrayList.class);
  192. if (kbsave == null) {
  193. kbsave = new ArrayList<Object>();
  194. }
  195. for (Object obj:kbsave) {
  196. HashMap<String, Object> item = (HashMap<String, Object>) obj;
  197. int key = (Integer) item.get("key");
  198. String id, description, addonName;
  199. id = (String) item.get("id");
  200. description = (String) item.get("description");
  201. byte modifiers = 0;
  202. if (item.containsKey("modifiers")) {
  203. modifiers = (byte)(int)(Integer) item.get("modifiers");
  204. }
  205. if (item.containsKey("addonName")) {
  206. addonName = (String) item.get("addonName");
  207. } else if (item.containsKey("plugin")) {
  208. addonName = (String) item.get("plugin");
  209. } else {
  210. continue; // Invalid item
  211. }
  212. KeyBinding binding = new KeyBinding(key, addonName, id, description);
  213. binding.setRawModifiers(modifiers);
  214. bindings.add(binding);
  215. }
  216. } catch (Exception e) {
  217. e.printStackTrace();
  218. bindings = new ArrayList<KeyBinding>();
  219. }
  220. try {
  221. shortcuts.clear();
  222. ArrayList<Object> shsave = yaml.loadAs(new FileReader(getShortcutsFile()), ArrayList.class);
  223. if (shsave == null) {
  224. shsave = new ArrayList<Object>();
  225. }
  226. for (Object obj:shsave) {
  227. HashMap<String, Object> item = (HashMap<String, Object>) obj;
  228. Shortcut sh = new Shortcut();
  229. sh.setTitle((String)item.get("title"));
  230. sh.setKey((Integer)item.get("key"));
  231. sh.setCommands((ArrayList<String>)item.get("commands"));
  232. if (item.containsKey("modifiers")) {
  233. sh.setRawModifiers((byte)(int)(Integer)item.get("modifiers"));
  234. }
  235. if (item.containsKey("delay")) {
  236. sh.setDelay((Integer) item.get("delay"));
  237. }
  238. shortcuts.add(sh);
  239. }
  240. } catch (Exception e) {
  241. e.printStackTrace();
  242. shortcuts = new ArrayList<Shortcut>();
  243. }
  244. updateBindings();
  245. }
  246. public void pressKey(int key, boolean keyPressed, int screen) {
  247. if (SpoutClient.getHandle().currentScreen instanceof GuiAmbigousInput || SpoutClient.getHandle().currentScreen instanceof GuiControls) {
  248. return;
  249. }
  250. if (bindingsForKey.containsKey(key)) {
  251. ArrayList<AbstractBinding> bindings = bindingsForKey.get(key);
  252. ArrayList<AbstractBinding> effective = new ArrayList<AbstractBinding>();
  253. for (AbstractBinding b:bindings) {
  254. if (b.matches(key, getPressedModifiers())) {
  255. effective.add(b);
  256. }
  257. }
  258. if (effective.size() == 0) {
  259. return;
  260. } else if (effective.size() == 1) {
  261. effective.iterator().next().summon(key, !keyPressed, screen);
  262. } else if (screen == 0 || (getPressedModifiers() != 0 && getPressedModifiers() != AbstractBinding.MOD_SHIFT)) {
  263. GuiScreen parent = SpoutClient.getHandle().currentScreen;
  264. SpoutClient.getHandle().displayGuiScreen(new GuiAmbigousInput(effective, parent));
  265. } else {
  266. GuiScreen parent = SpoutClient.getHandle().currentScreen;
  267. if (!(parent instanceof GuiChat)) {
  268. Spoutcraft.getActivePlayer().showAchievement("Multiple Bindings ...", "are assigned to Key " + Keyboard.getKeyName(key), Block.workbench.blockID);
  269. }
  270. }
  271. }
  272. }
  273. public static boolean isModifierKey(int key) {
  274. if (key == Keyboard.KEY_LSHIFT
  275. || key == Keyboard.KEY_RSHIFT
  276. || key == Keyboard.KEY_LMENU
  277. || key == Keyboard.KEY_RMENU
  278. || key == Keyboard.KEY_LCONTROL
  279. || key == Keyboard.KEY_RCONTROL
  280. || key == Keyboard.KEY_LMETA
  281. || key == Keyboard.KEY_RMETA) {
  282. return true;
  283. }
  284. return false;
  285. }
  286. public List<KeyBinding> getAllBindings() {
  287. return Collections.unmodifiableList(bindings);
  288. }
  289. public List<Shortcut> getAllShortcuts() {
  290. return Collections.unmodifiableList(shortcuts);
  291. }
  292. public static void setModifiersToShortcut(Shortcut sh) {
  293. if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
  294. sh.setModifier(AbstractBinding.MOD_SHIFT, true);
  295. }
  296. if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
  297. sh.setModifier(AbstractBinding.MOD_CTRL, true);
  298. }
  299. if (Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU)) {
  300. sh.setModifier(AbstractBinding.MOD_ALT, true);
  301. }
  302. if (Keyboard.isKeyDown(Keyboard.KEY_LMETA) || Keyboard.isKeyDown(Keyboard.KEY_RMETA)) {
  303. sh.setModifier(AbstractBinding.MOD_SUPER, true);
  304. }
  305. }
  306. public static byte getPressedModifiers() {
  307. byte res = 0;
  308. if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
  309. res|=Shortcut.MOD_SHIFT;
  310. }
  311. if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
  312. res|=Shortcut.MOD_CTRL;
  313. }
  314. if (Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU)) {
  315. res|=Shortcut.MOD_ALT;
  316. }
  317. if (Keyboard.isKeyDown(Keyboard.KEY_LMETA) || Keyboard.isKeyDown(Keyboard.KEY_RMETA)) {
  318. res|=Shortcut.MOD_SUPER;
  319. }
  320. return res;
  321. }
  322. public void summon(KeyBinding binding, int key, boolean keyReleased, int screen) {
  323. if (binding.getDelegate() == null && binding.getUniqueId() != null) { // Server-side
  324. SpoutClient.getInstance().getPacketManager().sendSpoutPacket(new PacketKeyBinding(binding, key, !keyReleased, screen));
  325. } else if (binding.getDelegate() != null) { // Client-side
  326. KeyBindingPress event = new KeyBindingPress(org.spoutcraft.api.gui.Keyboard.getKey(key), binding, ScreenType.getType(screen));
  327. if (!keyReleased) {
  328. binding.getDelegate().onKeyPress(event);
  329. } else {
  330. binding.getDelegate().onKeyRelease(event);
  331. }
  332. }
  333. }
  334. }