2012-03-14 00:43:29 +00:00
|
|
|
/+
|
|
|
|
+ ui/inputvents.d
|
|
|
|
+
|
|
|
|
+ Copyright: 2007 Gerald Stocker
|
|
|
|
+
|
2012-03-15 06:21:12 +00:00
|
|
|
+ This file is part of twoapple-reboot.
|
2012-03-14 00:43:29 +00:00
|
|
|
+
|
2012-03-15 06:21:12 +00:00
|
|
|
+ twoapple-reboot is free software; you can redistribute it and/or modify
|
2012-03-14 00:43:29 +00:00
|
|
|
+ it under the terms of the GNU General Public License as published by
|
|
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
|
|
+ (at your option) any later version.
|
|
|
|
+
|
2012-03-15 06:21:12 +00:00
|
|
|
+ twoapple-reboot is distributed in the hope that it will be useful,
|
2012-03-14 00:43:29 +00:00
|
|
|
+ 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
|
2012-03-15 06:21:12 +00:00
|
|
|
+ along with twoapple-reboot; if not, write to the Free Software
|
2012-03-14 00:43:29 +00:00
|
|
|
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
+/
|
|
|
|
|
|
|
|
module ui.inputevents;
|
|
|
|
|
|
|
|
import std.stdio;
|
2012-03-14 12:24:35 +00:00
|
|
|
import std.conv;
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
import gtkglc.glgdktypes;
|
|
|
|
import gtk.Widget;
|
|
|
|
import gtkc.gtktypes;
|
|
|
|
import gtk.Image;
|
|
|
|
import gtk.ToggleToolButton;
|
2012-03-14 12:24:35 +00:00
|
|
|
import gtk.Main;
|
2012-03-14 00:43:29 +00:00
|
|
|
import gtk.Timeout;
|
|
|
|
|
|
|
|
import derelict.sdl.sdl;
|
|
|
|
|
|
|
|
import device.keyboard;
|
|
|
|
import device.paddle;
|
|
|
|
import device.pushbutton;
|
|
|
|
|
|
|
|
import ui.textinput;
|
|
|
|
|
|
|
|
static import host;
|
|
|
|
|
|
|
|
static this()
|
|
|
|
{
|
|
|
|
if (host.SDL)
|
|
|
|
{
|
|
|
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) == -1)
|
|
|
|
{
|
2012-03-14 12:24:35 +00:00
|
|
|
writefln("%s", to!string(SDL_GetError()));
|
2012-03-14 00:43:29 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int numJoysticks = SDL_NumJoysticks();
|
|
|
|
if (numJoysticks == 0) return;
|
|
|
|
|
|
|
|
joysticks.length = numJoysticks;
|
|
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
|
|
|
|
SDL_Joystick* device;
|
|
|
|
for (int i = 0; i < numJoysticks; ++i)
|
|
|
|
{
|
|
|
|
device = SDL_JoystickOpen(i);
|
|
|
|
if (device is null)
|
|
|
|
{
|
2012-03-14 12:24:35 +00:00
|
|
|
writefln("%s", to!string(SDL_GetError()));
|
2012-03-14 00:43:29 +00:00
|
|
|
continue;
|
|
|
|
}
|
2012-03-14 12:24:35 +00:00
|
|
|
writefln("Joystick %s: %s", i, to!string(SDL_JoystickName(i)));
|
2012-03-14 00:43:29 +00:00
|
|
|
|
|
|
|
joysticks[i] = new Joystick(device,
|
|
|
|
SDL_JoystickNumAxes(device),
|
|
|
|
SDL_JoystickNumButtons(device));
|
|
|
|
}
|
|
|
|
if (device is null)
|
|
|
|
joysticks.length = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Input input;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
Joystick[] joysticks;
|
|
|
|
|
|
|
|
class Joystick
|
|
|
|
{
|
|
|
|
bool isActive;
|
|
|
|
|
|
|
|
int deviceNum;
|
|
|
|
SDL_Joystick* device;
|
|
|
|
|
|
|
|
int[] pdlForAxis;
|
|
|
|
int[] pbForButton;
|
|
|
|
|
|
|
|
this(SDL_Joystick* dev, int numAxes, int numButtons)
|
|
|
|
{
|
|
|
|
device = dev;
|
|
|
|
pdlForAxis.length = numAxes;
|
|
|
|
pbForButton.length = numButtons;
|
|
|
|
for (int i = 0; i < numAxes; ++i)
|
|
|
|
pdlForAxis[i] = -1;
|
|
|
|
for (int i = 0; i < numButtons; ++i)
|
|
|
|
pbForButton[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Input
|
|
|
|
{
|
|
|
|
SDL_Event sEvent;
|
|
|
|
Timeout timeout;
|
|
|
|
|
|
|
|
Keyboard kbd;
|
|
|
|
Pushbuttons buttons;
|
|
|
|
Paddles paddles;
|
|
|
|
TextInput textIn;
|
|
|
|
ToggleToolButton pauseButton;
|
|
|
|
void delegate() onReset;
|
|
|
|
|
|
|
|
this()
|
|
|
|
{
|
|
|
|
pauseButton = new ToggleToolButton("gtk-media-pause");
|
|
|
|
// XXX read from config / allow changing
|
|
|
|
for (int i = 0; i < joysticks.length; ++i)
|
|
|
|
{
|
|
|
|
// By default, ignore all but the first two joysticks
|
|
|
|
if (i > 1) break;
|
|
|
|
|
|
|
|
joysticks[i].pdlForAxis[0] = i * 2;
|
|
|
|
joysticks[i].pdlForAxis[1] = i * 2 + 1;
|
|
|
|
joysticks[i].pbForButton[0] = i * 2;
|
|
|
|
joysticks[i].pbForButton[1] = 1;
|
|
|
|
|
|
|
|
// XXX hackish way of setting "pause" button
|
|
|
|
if (joysticks[i].pbForButton.length > 2)
|
2012-03-14 12:24:35 +00:00
|
|
|
joysticks[i].pbForButton[$ - 1] = -2;
|
2012-03-14 00:43:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void installButtons(Pushbuttons btns)
|
|
|
|
{
|
|
|
|
buttons = btns;
|
|
|
|
}
|
|
|
|
|
|
|
|
void installKeyboard(Keyboard keyboard)
|
|
|
|
{
|
|
|
|
kbd = keyboard;
|
|
|
|
}
|
|
|
|
|
|
|
|
void installPaddles(Paddles pdl)
|
|
|
|
{
|
|
|
|
paddles = pdl;
|
|
|
|
}
|
|
|
|
|
2012-03-14 12:24:35 +00:00
|
|
|
bool onKeyPress(GdkEventKey* evt, Widget w)
|
2012-03-14 00:43:29 +00:00
|
|
|
{
|
|
|
|
static const int KEY_PAUSE = 65299; // Pause/Break
|
|
|
|
static const int KEY_ESCAPE = 65307;
|
|
|
|
|
|
|
|
// Let someone else handle ALT-<x> presses
|
|
|
|
if ((evt.state & GdkModifierType.MOD1_MASK) != 0) return false;
|
|
|
|
|
|
|
|
if (textIn !is null)
|
|
|
|
{
|
|
|
|
if (evt.keyval == KEY_ESCAPE)
|
|
|
|
{
|
|
|
|
stopTextInput();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt.keyval == KEY_PAUSE)
|
|
|
|
{
|
|
|
|
pauseButton.setActive(!(pauseButton.getActive()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pauseButton.getActive()) return false;
|
|
|
|
|
|
|
|
bool ctrl = ((evt.state & GdkModifierType.CONTROL_MASK) != 0);
|
|
|
|
return kbd.handlePress(evt.keyval, ctrl, evt.hardwareKeycode);
|
|
|
|
}
|
|
|
|
|
2012-03-14 12:24:35 +00:00
|
|
|
bool onKeyRelease(GdkEventKey* evt, Widget w)
|
2012-03-14 00:43:29 +00:00
|
|
|
{
|
|
|
|
static const int KEY_RESET = 65481; // F12
|
|
|
|
|
|
|
|
// Let someone else handle ALT-<x> releases
|
|
|
|
if ((evt.state & GdkModifierType.MOD1_MASK) != 0) return false;
|
|
|
|
|
|
|
|
if (evt.keyval == KEY_RESET)
|
|
|
|
{
|
|
|
|
onReset();
|
|
|
|
if (pauseButton.getActive())
|
|
|
|
{
|
|
|
|
pauseButton.setActive(false);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pauseButton.getActive()) return false;
|
|
|
|
|
|
|
|
bool ctrl = ((evt.state & GdkModifierType.CONTROL_MASK) != 0);
|
|
|
|
return kbd.handleRelease(evt.keyval, ctrl, evt.hardwareKeycode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void onJoystickEvent()
|
|
|
|
{
|
|
|
|
static const float scale = 65535.0 / 2760.0;
|
|
|
|
static const int shift = 32768;
|
|
|
|
bool buttonDown = false;
|
|
|
|
switch(sEvent.type)
|
|
|
|
{
|
|
|
|
case SDL_JOYAXISMOTION:
|
|
|
|
Joystick joy = joysticks[sEvent.jaxis.which];
|
|
|
|
int axis = sEvent.jaxis.axis;
|
|
|
|
int pdl = joy.pdlForAxis[axis];
|
|
|
|
if (pdl != -1)
|
|
|
|
{
|
|
|
|
int value =
|
|
|
|
cast(int)(((sEvent.jaxis.value) + shift) / scale);
|
|
|
|
paddles.update(pdl, value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
|
|
buttonDown = true;
|
|
|
|
case SDL_JOYBUTTONUP:
|
|
|
|
Joystick joy = joysticks[sEvent.jbutton.which];
|
|
|
|
int pb = joy.pbForButton[sEvent.jbutton.button];
|
|
|
|
if ((pb == -2) && buttonDown)
|
|
|
|
pauseButton.setActive(!pauseButton.getActive());
|
|
|
|
else if (pb >= 0)
|
|
|
|
{
|
|
|
|
buttons.update(pb, buttonDown);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void startTextInput(string filename)
|
|
|
|
{
|
|
|
|
textIn = new TextInput(filename, &stopTextInput);
|
|
|
|
kbd.onReadLatch = &textIn.read;
|
|
|
|
kbd.onClearStrobe = &textIn.advancePos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stopTextInput()
|
|
|
|
{
|
|
|
|
kbd.onReadLatch = null;
|
|
|
|
kbd.onClearStrobe = null;
|
|
|
|
delete textIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void processEvents()
|
|
|
|
{
|
|
|
|
kbd.processPresses();
|
|
|
|
kbd.processReleases();
|
|
|
|
|
2012-03-14 12:24:35 +00:00
|
|
|
while(Main.eventsPending())
|
2012-03-14 00:43:29 +00:00
|
|
|
{
|
2012-03-14 12:24:35 +00:00
|
|
|
Main.iteration();
|
2012-03-14 00:43:29 +00:00
|
|
|
}
|
|
|
|
processJoystickEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool processJoystickEvents()
|
|
|
|
{
|
|
|
|
while (SDL_PollEvent(&sEvent))
|
|
|
|
{
|
|
|
|
onJoystickEvent();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|