Commit fd088d68 authored by bitplane's avatar bitplane

Extended WinNT console device to include keyboard and mouse input and respond...

Extended WinNT console device to include keyboard and mouse input and respond to windows close messages. 
Added sigterm handler and some VT100 escape codes for Unix terminals. Added simple ASCII present() method just for fun, currently untested on most platforms

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2237 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 787dc2f5
...@@ -8,22 +8,104 @@ ...@@ -8,22 +8,104 @@
#include "os.h" #include "os.h"
#ifdef _IRR_WINDOWS_API_ // to close the device on terminate signal
#define WIN32_LEAN_AND_MEAN irr::CIrrDeviceConsole *DeviceToClose;
#if !defined(_IRR_XBOX_PLATFORM_)
#include <windows.h> #ifdef _IRR_WINDOWS_NT_CONSOLE_
#endif // Callback for Windows
BOOL WINAPI ConsoleHandler(DWORD CEvent)
{
switch(CEvent)
{
case CTRL_C_EVENT:
irr::os::Printer::log("Closing console device", "CTRL+C");
break;
case CTRL_BREAK_EVENT:
irr::os::Printer::log("Closing console device", "CTRL+Break");
break;
case CTRL_CLOSE_EVENT:
irr::os::Printer::log("Closing console device", "User closed console");
break;
case CTRL_LOGOFF_EVENT:
irr::os::Printer::log("Closing console device", "User is logging off");
break;
case CTRL_SHUTDOWN_EVENT:
irr::os::Printer::log("Closing console device", "Computer shutting down");
break;
}
DeviceToClose->closeDevice();
return TRUE;
}
#else #else
#include <time.h> // sigterm handler
#include <signal.h>
void sighandler(int sig)
{
irr::core::stringc code = "Signal ";
code += sig;
code += " received";
irr::os::Printer::log("Closing console device", code.c_str());
DeviceToClose->closeDevice();
}
#endif #endif
namespace irr namespace irr
{ {
const c8 ASCIIArtChars[] = " .,'~:;!+>=icopjtJY56SB8XDQKHNWM"; //MWNHKQDX8BS65YJtjpoci=+>!;:~',. ";
const u16 ASCIIArtCharsCount = 32;
//const c8 ASCIIArtChars[] = " \xb0\xb1\xf9\xb2\xdb";
//const u16 ASCIIArtCharsCount = 5;
//! constructor //! constructor
CIrrDeviceConsole::CIrrDeviceConsole(const SIrrlichtCreationParameters& params) CIrrDeviceConsole::CIrrDeviceConsole(const SIrrlichtCreationParameters& params)
: CIrrDeviceStub(params), IsDeviceRunning(true) : CIrrDeviceStub(params), IsDeviceRunning(true), IsWindowFocused(true)
{ {
DeviceToClose = this;
#ifdef _IRR_WINDOWS_NT_CONSOLE_
MouseButtonStates = 0;
WindowsSTDIn = GetStdHandle(STD_INPUT_HANDLE);
WindowsSTDOut = GetStdHandle(STD_OUTPUT_HANDLE);
PCOORD Dimensions = 0;
if (CreationParams.Fullscreen)
{
if (SetConsoleDisplayMode(WindowsSTDOut, CONSOLE_FULLSCREEN_MODE, Dimensions))
{
CreationParams.WindowSize.Width = Dimensions->X;
CreationParams.WindowSize.Width = Dimensions->Y;
}
}
else
{
COORD ConsoleSize;
ConsoleSize.X = CreationParams.WindowSize.Width;
ConsoleSize.X = CreationParams.WindowSize.Height;
SetConsoleScreenBufferSize(WindowsSTDOut, ConsoleSize);
}
// catch windows close/break signals
SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE);
#else
// catch other signals
signal(SIGABRT, &sighandler);
signal(SIGTERM, &sighandler);
signal(SIGINT, &sighandler);
#endif
#ifdef _IRR_VT100_CONSOLE_
// reset terminal
printf("%cc", 27);
// disable line wrapping
printf("%c[7l", 27);
#endif
switch (params.DriverType) switch (params.DriverType)
{ {
case video::EDT_SOFTWARE: case video::EDT_SOFTWARE:
...@@ -51,15 +133,27 @@ CIrrDeviceConsole::CIrrDeviceConsole(const SIrrlichtCreationParameters& params) ...@@ -51,15 +133,27 @@ CIrrDeviceConsole::CIrrDeviceConsole(const SIrrlichtCreationParameters& params)
break; break;
} }
#ifdef _IRR_WINDOWS_NT_CONSOLE_
CursorControl = new CCursorControl(CreationParams.WindowSize);
#endif
if (VideoDriver) if (VideoDriver)
createGUIAndScene(); createGUIAndScene();
} }
//! destructor //! destructor
CIrrDeviceConsole::~CIrrDeviceConsole() CIrrDeviceConsole::~CIrrDeviceConsole()
{ {
// GUI and scene are dropped in the stub // GUI and scene are dropped in the stub
if (CursorControl)
{
CursorControl->drop();
CursorControl = 0;
}
#ifdef _IRR_VT100_CONSOLE_
// reset terminal
printf("%cc", 27);
#endif
} }
//! runs the device. Returns false if device wants to be deleted //! runs the device. Returns false if device wants to be deleted
...@@ -68,7 +162,109 @@ bool CIrrDeviceConsole::run() ...@@ -68,7 +162,109 @@ bool CIrrDeviceConsole::run()
// increment timer // increment timer
os::Timer::tick(); os::Timer::tick();
// todo: process keyboard input with cin/getch and catch kill signals // process Windows console input
#ifdef _IRR_WINDOWS_NT_CONSOLE_
INPUT_RECORD in;
DWORD oldMode;
DWORD count, waste;
// get old input mode
GetConsoleMode(WindowsSTDIn, &oldMode);
SetConsoleMode(WindowsSTDIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
GetNumberOfConsoleInputEvents(WindowsSTDIn, &count);
// read keyboard and mouse input
while (count)
{
ReadConsoleInput(WindowsSTDIn, &in, 1, &waste );
switch(in.EventType)
{
case KEY_EVENT:
{
SEvent e;
e.EventType = EET_KEY_INPUT_EVENT;
e.KeyInput.PressedDown = (in.Event.KeyEvent.bKeyDown == TRUE);
e.KeyInput.Control = (in.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0;
e.KeyInput.Shift = (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) != 0;
e.KeyInput.Key = EKEY_CODE(in.Event.KeyEvent.wVirtualKeyCode);
e.KeyInput.Char = in.Event.KeyEvent.uChar.UnicodeChar;
postEventFromUser(e);
break;
}
case MOUSE_EVENT:
{
SEvent e;
e.EventType = EET_MOUSE_INPUT_EVENT;
e.MouseInput.X = in.Event.MouseEvent.dwMousePosition.X;
e.MouseInput.Y = in.Event.MouseEvent.dwMousePosition.Y;
e.MouseInput.Wheel = 0.f;
e.MouseInput.ButtonStates =
( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) ? EMBSM_LEFT : 0 ) |
( (in.Event.MouseEvent.dwButtonState & RIGHTMOST_BUTTON_PRESSED) ? EMBSM_RIGHT : 0 ) |
( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) ? EMBSM_MIDDLE : 0 ) |
( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_3RD_BUTTON_PRESSED) ? EMBSM_EXTRA1 : 0 ) |
( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_4TH_BUTTON_PRESSED) ? EMBSM_EXTRA2 : 0 );
if (in.Event.MouseEvent.dwEventFlags & MOUSE_MOVED)
{
CursorControl->setPosition(core::position2di(e.MouseInput.X, e.MouseInput.Y));
// create mouse moved event
e.MouseInput.Event = EMIE_MOUSE_MOVED;
postEventFromUser(e);
}
if (in.Event.MouseEvent.dwEventFlags & MOUSE_WHEELED)
{
e.MouseInput.Event = EMIE_MOUSE_WHEEL;
e.MouseInput.Wheel = (in.Event.MouseEvent.dwButtonState & 0xFF000000) ? -1.0f : 1.0f;
postEventFromUser(e);
}
if ( (MouseButtonStates & EMBSM_LEFT) != (e.MouseInput.ButtonStates & EMBSM_LEFT) )
{
e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_LEFT) ? EMIE_LMOUSE_PRESSED_DOWN : EMIE_LMOUSE_LEFT_UP;
postEventFromUser(e);
}
if ( (MouseButtonStates & EMBSM_RIGHT) != (e.MouseInput.ButtonStates & EMBSM_RIGHT) )
{
e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_RIGHT) ? EMIE_RMOUSE_PRESSED_DOWN : EMIE_RMOUSE_LEFT_UP;
postEventFromUser(e);
}
if ( (MouseButtonStates & EMBSM_MIDDLE) != (e.MouseInput.ButtonStates & EMBSM_MIDDLE) )
{
e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_MIDDLE) ? EMIE_MMOUSE_PRESSED_DOWN : EMIE_MMOUSE_LEFT_UP;
postEventFromUser(e);
}
// save current button states
MouseButtonStates = e.MouseInput.ButtonStates;
break;
}
case WINDOW_BUFFER_SIZE_EVENT:
VideoDriver->OnResize(
core::dimension2d<u32>(in.Event.WindowBufferSizeEvent.dwSize.X,
in.Event.WindowBufferSizeEvent.dwSize.Y));
break;
case FOCUS_EVENT:
IsWindowFocused = (in.Event.FocusEvent.bSetFocus == TRUE);
break;
default:
break;
}
GetNumberOfConsoleInputEvents(WindowsSTDIn, &count);
}
// set input mode
SetConsoleMode(WindowsSTDIn, oldMode);
#else
// todo: process terminal keyboard input
#endif
return IsDeviceRunning; return IsDeviceRunning;
} }
...@@ -83,13 +279,11 @@ void CIrrDeviceConsole::yield() ...@@ -83,13 +279,11 @@ void CIrrDeviceConsole::yield()
struct timespec ts = {0,0}; struct timespec ts = {0,0};
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
#endif #endif
} }
//! Pause execution and let other processes to run for a specified amount of time. //! Pause execution and let other processes to run for a specified amount of time.
void CIrrDeviceConsole::sleep(u32 timeMs, bool pauseTimer) void CIrrDeviceConsole::sleep(u32 timeMs, bool pauseTimer)
{ {
const bool wasStopped = Timer ? Timer->isStopped() : true; const bool wasStopped = Timer ? Timer->isStopped() : true;
#ifdef _IRR_WINDOWS_API_ #ifdef _IRR_WINDOWS_API_
...@@ -107,13 +301,15 @@ void CIrrDeviceConsole::sleep(u32 timeMs, bool pauseTimer) ...@@ -107,13 +301,15 @@ void CIrrDeviceConsole::sleep(u32 timeMs, bool pauseTimer)
if (pauseTimer && !wasStopped) if (pauseTimer && !wasStopped)
Timer->start(); Timer->start();
} }
//! sets the caption of the window //! sets the caption of the window
void CIrrDeviceConsole::setWindowCaption(const wchar_t* text) void CIrrDeviceConsole::setWindowCaption(const wchar_t* text)
{ {
// do nothing - there is no caption #ifdef _IRR_WINDOWS_NT_CONSOLE_
core::stringc txt(text);
SetConsoleTitle(txt.c_str());
#endif
} }
//! returns if window is active. if not, nothing need to be drawn //! returns if window is active. if not, nothing need to be drawn
...@@ -126,8 +322,7 @@ bool CIrrDeviceConsole::isWindowActive() const ...@@ -126,8 +322,7 @@ bool CIrrDeviceConsole::isWindowActive() const
//! returns if window has focus //! returns if window has focus
bool CIrrDeviceConsole::isWindowFocused() const bool CIrrDeviceConsole::isWindowFocused() const
{ {
// no way to tell, so we always assume it is return IsWindowFocused;
return true;
} }
//! returns if window is minimized //! returns if window is minimized
...@@ -137,17 +332,36 @@ bool CIrrDeviceConsole::isWindowMinimized() const ...@@ -137,17 +332,36 @@ bool CIrrDeviceConsole::isWindowMinimized() const
} }
//! presents a surface in the client area //! presents a surface in the client area
//! returns false on failure
bool CIrrDeviceConsole::present(video::IImage* surface, void* windowId, core::rect<s32>* src) bool CIrrDeviceConsole::present(video::IImage* surface, void* windowId, core::rect<s32>* src)
{ {
// always fails! if (surface)
return false; {
OutputLine.reserve(surface->getDimension().Width + 1);
for (u32 y=0; y < surface->getDimension().Height; ++y)
{
setTextCursorPos(0,y);
for (u32 x=0; x< surface->getDimension().Width; ++x)
{
// get average pixel
u32 avg = surface->getPixel(x,y).getAverage() * (ASCIIArtCharsCount-1);
avg /= 255;
OutputLine += ASCIIArtChars[avg];
}
printf("%s", OutputLine.c_str());
OutputLine = "";
}
}
return true;
} }
//! notifies the device that it should close itself //! notifies the device that it should close itself
void CIrrDeviceConsole::closeDevice() void CIrrDeviceConsole::closeDevice()
{ {
// // return false next time we run()
IsDeviceRunning = false;
} }
//! Sets if the window should be resizeable in windowed mode. //! Sets if the window should be resizeable in windowed mode.
...@@ -156,6 +370,21 @@ void CIrrDeviceConsole::setResizeAble(bool resize) ...@@ -156,6 +370,21 @@ void CIrrDeviceConsole::setResizeAble(bool resize)
// do nothing // do nothing
} }
void CIrrDeviceConsole::setTextCursorPos(s16 x, s16 y)
{
#ifdef _IRR_WINDOWS_NT_CONSOLE_
// move WinNT cursor
COORD Position;
Position.X = x;
Position.Y = y;
SetConsoleCursorPosition(WindowsSTDOut, Position);
#elif _IRR_VT100_CONSOLE_
// send escape code
printf("%c[%d;%dH", 27, y, x);
#else
// not implemented
#endif
}
extern "C" IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx( extern "C" IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx(
const SIrrlichtCreationParameters& parameters) const SIrrlichtCreationParameters& parameters)
......
...@@ -13,6 +13,24 @@ ...@@ -13,6 +13,24 @@
#include "CIrrDeviceStub.h" #include "CIrrDeviceStub.h"
#include "IImagePresenter.h" #include "IImagePresenter.h"
//#undef _IRR_WINDOWS_API_
#ifdef _IRR_WINDOWS_API_
#define WIN32_LEAN_AND_MEAN
#if !defined(_IRR_XBOX_PLATFORM_)
#include <windows.h>
#endif
#if(_WIN32_WINNT >= 0x0500)
#define _IRR_WINDOWS_NT_CONSOLE_
#endif
#else
#include <time.h>
#endif
// for now we assume all other terminal types are VT100
#ifndef _IRR_WINDOWS_NT_CONSOLE_
#define _IRR_VT100_CONSOLE_
#endif
namespace irr namespace irr
{ {
...@@ -57,9 +75,139 @@ namespace irr ...@@ -57,9 +75,139 @@ namespace irr
//! Sets if the window should be resizeable in windowed mode. //! Sets if the window should be resizeable in windowed mode.
virtual void setResizeAble(bool resize=false); virtual void setResizeAble(bool resize=false);
//! Implementation of the win32 cursor control
class CCursorControl : public gui::ICursorControl
{
public:
CCursorControl(const core::dimension2d<u32>& wsize)
: WindowSize(wsize), InvWindowSize(0.0f, 0.0f), IsVisible(true), UseReferenceRect(false)
{
if (WindowSize.Width!=0)
InvWindowSize.Width = 1.0f / WindowSize.Width;
if (WindowSize.Height!=0)
InvWindowSize.Height = 1.0f / WindowSize.Height;
}
//! Changes the visible state of the mouse cursor.
virtual void setVisible(bool visible)
{
if(visible != IsVisible)
{
IsVisible = visible;
setPosition(CursorPos.X, CursorPos.Y);
}
}
//! Returns if the cursor is currently visible.
virtual bool isVisible() const
{
return IsVisible;
}
//! Sets the new position of the cursor.
virtual void setPosition(const core::position2d<f32> &pos)
{
setPosition(pos.X, pos.Y);
}
//! Sets the new position of the cursor.
virtual void setPosition(f32 x, f32 y)
{
if (!UseReferenceRect)
setPosition((s32)(x*WindowSize.Width), (s32)(y*WindowSize.Height));
else
setPosition((s32)(x*ReferenceRect.getWidth()), (s32)(y*ReferenceRect.getHeight()));
}
//! Sets the new position of the cursor.
virtual void setPosition(const core::position2d<s32> &pos)
{
setPosition(pos.X, pos.Y);
}
//! Sets the new position of the cursor.
virtual void setPosition(s32 x, s32 y)
{
setInternalCursorPosition(core::position2di(x,y));
}
//! Returns the current position of the mouse cursor.
virtual core::position2d<s32> getPosition()
{
return CursorPos;
}
//! Returns the current position of the mouse cursor.
virtual core::position2d<f32> getRelativePosition()
{
if (!UseReferenceRect)
{
return core::position2d<f32>(CursorPos.X * InvWindowSize.Width,
CursorPos.Y * InvWindowSize.Height);
}
return core::position2d<f32>(CursorPos.X / (f32)ReferenceRect.getWidth(),
CursorPos.Y / (f32)ReferenceRect.getHeight());
}
//! Sets an absolute reference rect for calculating the cursor position.
virtual void setReferenceRect(core::rect<s32>* rect=0)
{
if (rect)
{
ReferenceRect = *rect;
UseReferenceRect = true;
// prevent division through zero and uneven sizes
if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2)
ReferenceRect.LowerRightCorner.Y += 1;
if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2)
ReferenceRect.LowerRightCorner.X += 1;
}
else
UseReferenceRect = false;
}
//! Updates the internal cursor position
void setInternalCursorPosition(const core::position2di &pos)
{
CursorPos = pos;
if (UseReferenceRect)
CursorPos -= ReferenceRect.UpperLeftCorner;
}
private:
core::position2d<s32> CursorPos;
core::dimension2d<u32> WindowSize;
core::dimension2d<f32> InvWindowSize;
bool IsVisible,
UseReferenceRect;
core::rect<s32> ReferenceRect;
};
private: private:
bool IsDeviceRunning;
void setTextCursorPos(s16 x, s16 y);
void setMouseCursorPos(s32 x, s32 y);
core::position2di getMouseCursorPos();
bool IsDeviceRunning,
IsWindowFocused;
core::stringc OutputLine;
#ifdef _IRR_WINDOWS_NT_CONSOLE_
HANDLE WindowsSTDIn, WindowsSTDOut;
u32 MouseButtonStates;
#endif
}; };
} // end namespace irr } // end namespace irr
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment