Mercurial > projects > mde
view mde/input/config.d @ 17:5f90774ea1ef
Applied the GNU GPL v2 to mde.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sat, 15 Mar 2008 15:14:25 +0000 |
parents | 4608be19ebe2 |
children | 838577503598 |
line wrap: on
line source
/* LICENSE BLOCK Part of mde: a Modular D game-oriented Engine Copyright © 2007-2008 Diggory Hardy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /// This module contains a class for holding configs and handles saving, loading and editing. module mde.input.config; debug import tango.scrapple.text.convert.parseFrom : parseFrom; import mde.input.exception; import MT = mde.mergetag.Reader; import mde.resource.paths; import tango.scrapple.text.convert.parseTo : parseTo; import tango.util.log.Log : Log, Logger; import tango.util.collection.TreeBag : TreeBag; /** Class to hold the configuration for the input system. Thus loading and switching between * multiple configurations should be easy. * * Class extends DataSection so that it can be loaded by mergetag easily. */ class Config : MT.IDataSection { alias uint[] outQueue; // This is the type for the out queue config data. /** Button event type bit-codes * * These bitcodes are OR'd to the identifier code for the input device, to indicate which type * of input they are for. E.g. when a key event is recieved with code x, look up * $(_B _B.SDLKEY) | x in button. Keyboard events are SDL-specific since the codes may differ * for other libraries. * * For joystick hat events, a motion is converted into up and down events on separate U,L,D,R * positions and up and down events sent to the appropriate outputs (effectively making four * buttons, some pairs of which can be pressed simultaneously). For output to axes, see * A.JOYHAT_* . */ enum B : uint { KEY = 0x8000_0000u, /// 0x8000_0000 SDLKEY = 0x8800_0000u, /// 0x8800_0000 MOUSE = 0x4000_0000u, /// 0x4000_0000 JOYBUTTON = 0x2000_0000u, /// 0x2000_0000 JOYHAT = 0x1000_0000u, /// 0x1000_0000 JOYHAT_U = 0x1800_0000u, /// 0x1800_0000 JOYHAT_D = 0x1400_0000u, /// 0x1400_0000 JOYHAT_L = 0x1200_0000u, /// 0x1200_0000 JOYHAT_R = 0x1100_0000u, /// 0x1100_0000 } /** Axis event type bit-codes * * SDL only supports one type of axis now, but this could be extended in the future. * * This can also be used to make joystick hats output to two axes (and can be used in * conjuction with B.JOYHAT_* to output as buttons as well). */ enum A : uint { JOYAXIS = 0x8000_0000u, /// 0x8000_0000 JOYHAT = 0x1000_0000u, /// 0x1000_0000 JOYHAT_LR = 0x1300_0000u, /// 0x1300_0000 JOYHAT_UD = 0x1C00_0000u, /// 0x1C00_0000 } /** Mouse & Joystick ball event type bit-codes * * Currently, mouse input only comes from the window manager: the code is exactly M.WMMOUSE. */ enum M : uint { MOUSE = 0x8000_0000u, /// 0x8000_0000 WMMOUSE = 0x8800_0000u, /// 0x8800_0000 JOYBALL = 0x4000_0000u, /// 0x4000_0000 } /** Output queues: the core of the input configuration. * * These are all mapped with a uint key; upon any event outQueues are looked for in the * appropriate associative array with a key as follows. * * The index is split into two parts; * the first byte specifies the type of input (given by the above enums), and the last three * bytes define where the input comes from. * * For type B.SDLKEY, the last three bytes are for the SDL keysym. * For B.MOUSE, B.JOY*, A.JOY* & M.JOY*, the last three bytes are split into two sets of 12 * bits (with masks 0x00FF_F000 and 0x0000_0FFF), the higher of which specifies the device * (which mouse or joystick), and the lower of which specifies the button/axis/ball. * * For all three types of output, the outQueues are used as follows. The first value in the queue is * read, and a function is called with the event details dependant on this; most of the time an * output function is called directly. Other functions may be used, however, to allow further * functionality such as modifier keys, timed keys, and key sequences. * * The output functions all have code 0x100; these read a single item from the outQueue which * is the inputID the event outputs to (i.e. any callbacks at that ID called and status set for * that ID). * */ outQueue[][uint] button; outQueue[][uint] axis; /// ditto outQueue[][uint] relMotion; /// ditto // FIXME: char[] name; /// Name for user to save this under. uint[] inheritants; /// Other profiles to inherit. static Config[char[]] configs; /// All configs loaded by load(). private static TreeBag!(char[]) loadedFiles; // all filenames load tried to read private static Logger logger; static this() { logger = Log.getLogger ("mde.input.config.Config"); } //BEGIN File loading/saving code static this () { loadedFiles = new TreeBag!(char[]); } // Load all configs from a file. static void load (char[] filename) { if (loadedFiles.contains (filename)) return; // forget it; already done that loadedFiles.add (filename); MT.IReader file; try { // open and read header: file = confDir.makeMTReader (filename, PRIORITY.LOW_HIGH, null, true); file.dataSecCreator = delegate MT.IDataSection (MT.ID) { return new Config; }; // D2.0: enum MT.ID CONFIGS = "Configs"; const MT.ID CONFIGS = cast(MT.ID)"Configs"; // Restrict config sections if this tag exists: auto file_configs_p = CONFIGS in file.dataset.header._charAA; MT.ID[] file_configs = null; if (file_configs_p) { file_configs = cast(MT.ID[]) *file_configs_p; } if (file_configs) file.read(file_configs); // restrict to this set IF a restriction was given else file.read(); // otherwise read all } catch (MT.MTException) { logger.error ("Unable to load configs from: " ~ filename); throw new ConfigLoadException; } // Trying to directly cast dataset.sec to configs resulted in the Configs losing their data. // Also this is safer since it checks types (and must be done if configs wasn't previously empty). foreach (i, sec; file.dataset.sec) { Config c = cast(Config) sec; if (c) configs[i] = c; // Check, because we don't want null entries in configs else debug logger.warn ("Ended up with DataSection of wrong type; this should never happen."); } debug { char tmp[128] = void; logger.trace (logger.format (tmp, "Loaded {} config sections.", configs.length)); foreach (id, cfg; configs) { logger.trace ("Section " ~ id ~ ":\n\tbutton:\t\t" ~ parseFrom!(uint[][][uint])(cfg.button) ~ "\n\taxis:\t\t" ~ parseFrom!(uint[][][uint])(cfg.axis) ~ "\n\trelMotion:\t" ~ parseFrom!(uint[][][uint])(cfg.relMotion) ); } } } // D2.0: private enum QUEUE : MT.ID { BUTTON = "B", AXIS = "A", MOUSE = "M" } private struct QUEUE { static const MT.ID BUTTON = cast(MT.ID)"B", AXIS = cast(MT.ID)"A", MOUSE = cast(MT.ID)"M"; } private this() {} // Private since this class should only be created from here. void addTag (char[] tp, MT.ID id, char[] dt) { if (tp == "uint[][uint]") { if (id == QUEUE.BUTTON) button = cast(outQueue[][uint]) parseTo!(uint[][][uint]) (dt); else if (id == QUEUE.AXIS) axis = cast(outQueue[][uint]) parseTo!(uint[][][uint]) (dt); else if (id == QUEUE.MOUSE) relMotion = cast(outQueue[][uint]) parseTo!(uint[][][uint]) (dt); else logger.warn ("Unexpected tag encountered with ID " ~ cast(char[])id); } // FIXME: add support for name and inheritants. } void writeAll (ItemDelg) { // FIXME } //END File loading/saving code }