Move more platform code to UiContext

This commit is contained in:
Ted John 2017-03-25 17:42:14 +00:00 committed by Gymnasiast
parent 5885cb646f
commit f736e8ff96
18 changed files with 845 additions and 502 deletions

View File

@ -0,0 +1,300 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include <openrct2/common.h>
#include <SDL.h>
#include <openrct2/core/Math.hpp>
#include <openrct2/core/Memory.hpp>
#include <openrct2/core/String.hpp>
#include <openrct2/localisation/localisation.h>
#include "TextComposition.h"
extern "C"
{
#include <openrct2/interface/console.h>
#include <openrct2/interface/window.h>
}
#ifdef __MACOSX__
// macOS uses COMMAND rather than CTRL for many keyboard shortcuts
#define KEYBOARD_PRIMARY_MODIFIER KMOD_GUI
#else
#define KEYBOARD_PRIMARY_MODIFIER KMOD_CTRL
#endif
using namespace OpenRCT2;
using namespace OpenRCT2::Ui;
bool TextComposition::IsActive()
{
return SDL_IsTextInputActive() && _session.Buffer != nullptr;
}
const TextInputSession * TextComposition::Start(utf8 * buffer, size_t bufferSize)
{
Guard::ArgumentNotNull(buffer);
// TODO This doesn't work, and position could be improved to where text entry is
SDL_Rect rect = { 10, 10, 100, 100 };
SDL_SetTextInputRect(&rect);
SDL_StartTextInput();
_session.Buffer = buffer;
_session.BufferSize = bufferSize - 1;
_session.Size = strlen(buffer);
_session.SelectionStart = _session.Size;
_session.SelectionSize = 0;
RecalculateLength();
return &_session;
}
void TextComposition::Stop()
{
SDL_StopTextInput();
_session.Buffer = nullptr;
_imeActive = false;
}
void TextComposition::HandleMessage(const SDL_Event * e)
{
switch (e->type) {
case SDL_TEXTEDITING:
// When inputting Korean characters, `edit.length` is always zero
String::Set(_imeBuffer, sizeof(_imeBuffer), e->edit.text);
_imeStart = e->edit.start;
_imeLength = e->edit.length;
_imeActive = ((e->edit.length != 0 || String::SizeOf(e->edit.text) != 0) && _imeBuffer[0] != '\0');
break;
case SDL_TEXTINPUT:
// will receive an `SDL_TEXTINPUT` event when a composition is committed
_imeActive = false;
if (_session.Buffer != nullptr)
{
// HACK ` will close console, so don't input any text
if (e->text.text[0] == '`' && gConsoleOpen) {
break;
}
utf8 * newText = String::Duplicate(e->text.text);
utf8_remove_formatting(newText, false);
Insert(newText);
Memory::Free(newText);
console_refresh_caret();
window_update_textbox();
}
break;
case SDL_KEYDOWN:
{
if (_imeActive)
{
break;
}
uint16 modifier = e->key.keysym.mod;
SDL_Keycode key = e->key.keysym.sym;
if (key == SDLK_KP_ENTER)
{
// Map Keypad enter to regular enter.
key = SDLK_RETURN;
}
// _lastKeyPressed = e.key.keysym.sym;
// _keysPressed[e.key.keysym.scancode] = 1;
// Text input
if (_session.Buffer == nullptr)
{
break;
}
// Clear the input on <CTRL>Backspace (Windows/Linux) or <MOD>Backspace (macOS)
if (key == SDLK_BACKSPACE && (modifier & KEYBOARD_PRIMARY_MODIFIER))
{
Clear();
console_refresh_caret();
window_update_textbox();
}
switch (key) {
case SDLK_BACKSPACE:
// If backspace and we have input text with a cursor position none zero
if (_session.SelectionStart > 0)
{
size_t endOffset = _session.SelectionStart;
CursorLeft();
_session.SelectionSize = endOffset - _session.SelectionStart;
Delete();
console_refresh_caret();
window_update_textbox();
}
break;
case SDLK_HOME:
CursorHome();
console_refresh_caret();
break;
case SDLK_END:
CursorEnd();
console_refresh_caret();
break;
case SDLK_DELETE:
{
size_t startOffset = _session.SelectionStart;
CursorRight();
_session.SelectionSize = _session.SelectionStart - startOffset;
_session.SelectionStart = startOffset;
Delete();
console_refresh_caret();
window_update_textbox();
break;
}
case SDLK_RETURN:
window_cancel_textbox();
break;
case SDLK_LEFT:
CursorLeft();
console_refresh_caret();
break;
case SDLK_RIGHT:
CursorRight();
console_refresh_caret();
break;
case SDLK_v:
if ((modifier & KEYBOARD_PRIMARY_MODIFIER) && SDL_HasClipboardText())
{
utf8 * text = SDL_GetClipboardText();
utf8_remove_formatting(text, false);
Insert(text);
SDL_free(text);
window_update_textbox();
}
break;
}
}
}
}
void TextComposition::CursorHome()
{
_session.SelectionStart = 0;
}
void TextComposition::CursorEnd()
{
_session.SelectionStart = _session.SelectionSize;
}
void TextComposition::CursorLeft()
{
size_t selectionOffset = _session.SelectionStart;
if (selectionOffset > 0)
{
const utf8 * ch = _session.Buffer + selectionOffset;
do
{
ch--;
selectionOffset--;
}
while (!utf8_is_codepoint_start(ch) && selectionOffset > 0);
_session.SelectionStart = selectionOffset;
}
}
void TextComposition::CursorRight()
{
size_t selectionOffset = _session.SelectionStart;
size_t selectionMaxOffset = _session.Size;
if (selectionOffset < selectionMaxOffset)
{
const utf8 * ch = _session.Buffer + _session.SelectionStart;
do
{
ch++;
selectionOffset++;
}
while (!utf8_is_codepoint_start(ch) && selectionOffset < selectionMaxOffset);
_session.SelectionSize = Math::Max<size_t>(0, _session.SelectionSize - (selectionOffset - _session.SelectionStart));
_session.SelectionStart = selectionOffset;
}
}
void TextComposition::Insert(const utf8 * text)
{
const utf8 * ch = text;
uint32 codepoint;
while ((codepoint = utf8_get_next(ch, &ch)) != 0)
{
InsertCodepoint(codepoint);
}
}
void TextComposition::InsertCodepoint(codepoint_t codepoint)
{
size_t codepointLength = utf8_get_codepoint_length(codepoint);
size_t remainingSize = _session.BufferSize - _session.Size;
if (codepointLength <= remainingSize)
{
utf8 * buffer = (utf8 *)_session.Buffer;
utf8 * insertPtr = buffer + _session.SelectionStart;
if (_session.SelectionStart < _session.Size)
{
// Shift bytes (including null terminator) right to make room for new codepoint
utf8 * targetShiftPtr = insertPtr + codepointLength;
size_t shiftSize = _session.Size - _session.SelectionStart + 1;
memmove(targetShiftPtr, insertPtr, shiftSize);
}
else
{
// Character is appended onto the end, so set byte after it to null terminator
buffer[_session.Size + codepointLength] = 0;
}
utf8_write_codepoint(insertPtr, codepoint);
_session.SelectionStart += codepointLength;
_session.Size += codepointLength;
_session.Length++;
}
}
void TextComposition::Clear()
{
utf8 * buffer = (utf8 *)_session.Buffer;
buffer[0] = 0;
_session.Size = 0;
_session.Length = 0;
_session.SelectionStart = 0;
_session.SelectionSize = 0;
}
void TextComposition::Delete()
{
utf8 * buffer = (utf8 *)_session.Buffer;
utf8 * targetShiftPtr = buffer + _session.SelectionStart;
utf8 * sourceShiftPtr = targetShiftPtr + _session.SelectionSize;
size_t shiftSize = _session.SelectionSize - _session.SelectionStart - _session.SelectionSize + 1;
memmove(targetShiftPtr, sourceShiftPtr, shiftSize);
_session.SelectionSize = 0;
RecalculateLength();
}
void TextComposition::RecalculateLength()
{
_session.Size = String::SizeOf(_session.Buffer);
_session.Length = String::LengthOf(_session.Buffer);
}

View File

@ -0,0 +1,57 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include <openrct2/common.h>
#include <openrct2/ui/UiContext.h>
union SDL_Event;
namespace OpenRCT2
{
namespace Ui
{
/**
* Represents a
*/
class TextComposition
{
private:
TextInputSession _session = { 0 };
bool _imeActive = false;
sint32 _imeStart = 0;
sint32 _imeLength = 0;
utf8 _imeBuffer[32] = { 0 };
public:
bool IsActive();
const TextInputSession * TextComposition::Start(utf8 * buffer, size_t bufferSize);
void Stop();
void HandleMessage(const SDL_Event * e);
private:
void CursorHome();
void CursorEnd();
void CursorLeft();
void CursorRight();
void Insert(const utf8 * text);
void InsertCodepoint(codepoint_t codepoint);
void Clear();
void Delete();
void RecalculateLength();
};
}
}

View File

@ -18,6 +18,7 @@
#include <memory>
#include <vector>
#include <SDL.h>
#include <openrct2/audio/AudioMixer.h>
#include <openrct2/config/Config.h>
#include <openrct2/Context.h>
#include <openrct2/drawing/IDrawingEngine.h>
@ -26,15 +27,31 @@
#include <openrct2/Version.h>
#include "CursorRepository.h"
#include "drawing/engines/DrawingEngines.h"
#include "TextComposition.h"
#include "UiContext.h"
extern "C"
{
#include <openrct2/interface/console.h>
#include <openrct2/input.h>
}
using namespace OpenRCT2;
using namespace OpenRCT2::Drawing;
using namespace OpenRCT2::Ui;
#ifdef __MACOSX__
// macOS uses COMMAND rather than CTRL for many keyboard shortcuts
#define KEYBOARD_PRIMARY_MODIFIER KMOD_GUI
#else
#define KEYBOARD_PRIMARY_MODIFIER KMOD_CTRL
#endif
class UiContext : public IUiContext
{
private:
constexpr static uint32 TOUCH_DOUBLE_TIMEOUT = 300;
IPlatformUiContext * const _platformUiContext;
CursorRepository _cursorRepository;
@ -48,6 +65,15 @@ private:
bool _steamOverlayActive = false;
// Input
TextComposition _textComposition;
CursorState _cursorState;
uint32 _lastKeyPressed;
const uint8 * _keysState;
uint8 * _keysPressed;
uint32 _lastGestureTimestamp;
float _gestureRadius;
public:
UiContext(IPlatformUiContext * platformUiContext)
: _platformUiContext(platformUiContext)
@ -60,16 +86,6 @@ public:
}
// Window
CURSOR_ID GetCursor() override
{
return _cursorRepository.GetCurrentCursor();
}
void SetCursor(CURSOR_ID cursor) override
{
_cursorRepository.SetCurrentCursor(cursor);
}
void * GetWindow() override
{
return _window;
@ -122,6 +138,52 @@ public:
return _fsResolutions;
}
bool IsSteamOverlayActive() override
{
return _steamOverlayActive;
}
// Input
const CursorState * GetCursorState() override
{
return &_cursorState;
}
const uint8 * GetKeysState() override
{
return _keysState;
}
const uint8 * GetKeysPressed() override
{
return _keysPressed;
}
CURSOR_ID GetCursor() override
{
return _cursorRepository.GetCurrentCursor();
}
void SetCursor(CURSOR_ID cursor) override
{
_cursorRepository.SetCurrentCursor(cursor);
}
void SetCursorVisible(bool value) override
{
SDL_ShowCursor(value ? SDL_ENABLE : SDL_DISABLE);
}
void GetCursorPosition(sint32 * x, sint32 * y) override
{
SDL_GetMouseState(x, y);
}
void SetCursorPosition(sint32 x, sint32 y) override
{
SDL_WarpMouseInWindow(nullptr, x, y);
}
// Drawing
IDrawingEngine * CreateDrawingEngine(DRAWING_ENGINE_TYPE type) override
{
@ -140,9 +202,215 @@ public:
}
// Text input
bool IsTextInputActive() override { return false; }
const TextInputSession * StartTextInput(utf8 * buffer, sint32 bufferSize) override { return nullptr; }
void StopTextInput() override { }
bool IsTextInputActive() override
{
return _textComposition.IsActive();
}
const TextInputSession * StartTextInput(utf8 * buffer, size_t bufferSize) override
{
return _textComposition.Start(buffer, bufferSize);
}
void StopTextInput() override
{
_textComposition.Stop();
}
void ProcessMessages()
{
_lastKeyPressed = 0;
_cursorState.left &= ~CURSOR_CHANGED;
_cursorState.middle &= ~CURSOR_CHANGED;
_cursorState.right &= ~CURSOR_CHANGED;
_cursorState.old = 0;
_cursorState.touch = false;
SDL_Event e;
while (SDL_PollEvent(&e))
{
switch (e.type) {
case SDL_QUIT:
rct2_quit();
break;
case SDL_WINDOWEVENT:
// HACK: Fix #2158, OpenRCT2 does not draw if it does not think that the window is
// visible - due a bug in SDL 2.0.3 this hack is required if the
// window is maximised, minimised and then restored again.
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
{
if (SDL_GetWindowFlags(_window) & SDL_WINDOW_MAXIMIZED)
{
SDL_RestoreWindow(_window);
SDL_MaximizeWindow(_window);
}
if ((SDL_GetWindowFlags(_window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
{
SDL_RestoreWindow(_window);
SDL_SetWindowFullscreen(_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
}
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
OnResize(e.window.data1, e.window.data2);
}
if (gConfigSound.audio_focus && gConfigSound.sound_enabled)
{
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
{
Mixer_SetVolume(1);
}
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
{
Mixer_SetVolume(0);
}
}
break;
case SDL_MOUSEMOTION:
_cursorState.x = (sint32)(e.motion.x / gConfigGeneral.window_scale);
_cursorState.y = (sint32)(e.motion.y / gConfigGeneral.window_scale);
break;
case SDL_MOUSEWHEEL:
if (gConsoleOpen)
{
console_scroll(e.wheel.y);
break;
}
_cursorState.wheel += e.wheel.y * 128;
break;
case SDL_MOUSEBUTTONDOWN:
{
sint32 x = (sint32)(e.button.x / gConfigGeneral.window_scale);
sint32 y = (sint32)(e.button.y / gConfigGeneral.window_scale);
switch (e.button.button) {
case SDL_BUTTON_LEFT:
store_mouse_input(MOUSE_STATE_LEFT_PRESS, x, y);
_cursorState.left = CURSOR_PRESSED;
_cursorState.old = 1;
break;
case SDL_BUTTON_MIDDLE:
_cursorState.middle = CURSOR_PRESSED;
break;
case SDL_BUTTON_RIGHT:
store_mouse_input(MOUSE_STATE_RIGHT_PRESS, x, y);
_cursorState.right = CURSOR_PRESSED;
_cursorState.old = 2;
break;
}
break;
}
case SDL_MOUSEBUTTONUP:
{
sint32 x = (sint32)(e.button.x / gConfigGeneral.window_scale);
sint32 y = (sint32)(e.button.y / gConfigGeneral.window_scale);
switch (e.button.button) {
case SDL_BUTTON_LEFT:
store_mouse_input(MOUSE_STATE_LEFT_RELEASE, x, y);
_cursorState.left = CURSOR_RELEASED;
_cursorState.old = 3;
break;
case SDL_BUTTON_MIDDLE:
_cursorState.middle = CURSOR_RELEASED;
break;
case SDL_BUTTON_RIGHT:
store_mouse_input(MOUSE_STATE_RIGHT_RELEASE, x, y);
_cursorState.right = CURSOR_RELEASED;
_cursorState.old = 4;
break;
}
break;
}
// Apple sends touchscreen events for trackpads, so ignore these events on macOS
#ifndef __MACOSX__
case SDL_FINGERMOTION:
_cursorState.x = (sint32)(e.tfinger.x * gScreenWidth);
_cursorState.y = (sint32)(e.tfinger.y * gScreenHeight);
break;
case SDL_FINGERDOWN:
{
sint32 x = (sint32)(e.tfinger.x * gScreenWidth);
sint32 y = (sint32)(e.tfinger.y * gScreenHeight);
_cursorState.touchIsDouble = (!_cursorState.touchIsDouble &&
e.tfinger.timestamp - _cursorState.touchDownTimestamp < TOUCH_DOUBLE_TIMEOUT);
if (_cursorState.touchIsDouble)
{
store_mouse_input(MOUSE_STATE_RIGHT_PRESS, x, y);
_cursorState.right = CURSOR_PRESSED;
_cursorState.old = 2;
}
else
{
store_mouse_input(MOUSE_STATE_LEFT_PRESS, x, y);
_cursorState.left = CURSOR_PRESSED;
_cursorState.old = 1;
}
_cursorState.touch = true;
_cursorState.touchDownTimestamp = e.tfinger.timestamp;
break;
}
case SDL_FINGERUP:
{
sint32 x = (sint32)(e.tfinger.x * gScreenWidth);
sint32 y = (sint32)(e.tfinger.y * gScreenHeight);
if (_cursorState.touchIsDouble)
{
store_mouse_input(MOUSE_STATE_RIGHT_RELEASE, x, y);
_cursorState.left = CURSOR_RELEASED;
_cursorState.old = 4;
}
else {
store_mouse_input(MOUSE_STATE_LEFT_RELEASE, x, y);
_cursorState.left = CURSOR_RELEASED;
_cursorState.old = 3;
}
_cursorState.touch = true;
break;
}
#endif
case SDL_KEYDOWN:
_textComposition.HandleMessage(&e);
break;
case SDL_MULTIGESTURE:
if (e.mgesture.numFingers == 2)
{
if (e.mgesture.timestamp > _lastGestureTimestamp + 1000)
{
_gestureRadius = 0;
}
_lastGestureTimestamp = e.mgesture.timestamp;
_gestureRadius += e.mgesture.dDist;
// Zoom gesture
constexpr sint32 tolerance = 128;
sint32 gesturePixels = (sint32)(_gestureRadius * gScreenWidth);
if (abs(gesturePixels) > tolerance)
{
_gestureRadius = 0;
main_window_zoom(gesturePixels > 0, true);
}
}
break;
case SDL_TEXTEDITING:
_textComposition.HandleMessage(&e);
break;
case SDL_TEXTINPUT:
_textComposition.HandleMessage(&e);
break;
default:
break;
}
}
_cursorState.any = _cursorState.left | _cursorState.middle | _cursorState.right;
// Updates the state of the keys
sint32 numKeys = 256;
_keysState = SDL_GetKeyboardState(&numKeys);
}
private:
void CreateWindow()

View File

@ -15,6 +15,8 @@
#pragma endregion
#include <openrct2/config/Config.h>
#include <openrct2/Context.h>
#include <openrct2/ui/UiContext.h>
#include <openrct2/core/Guard.hpp>
#include <openrct2/core/Math.hpp>
#include <openrct2/core/Memory.hpp>
@ -37,6 +39,7 @@ extern "C"
#include <openrct2/drawing/lightfx.h>
}
using namespace OpenRCT2;
using namespace OpenRCT2::Drawing;
class SoftwareDrawingEngine;
@ -730,14 +733,15 @@ private:
}
SDL_RenderCopy(_sdlRenderer, _screenTexture, nullptr, nullptr);
if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause)
bool isSteamOverlayActive = GetContext()->GetUiContext()->IsSteamOverlayActive();
if (isSteamOverlayActive && gConfigGeneral.steam_overlay_pause)
{
OverlayPreRenderCheck();
}
SDL_RenderPresent(_sdlRenderer);
if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause)
if (isSteamOverlayActive && gConfigGeneral.steam_overlay_pause)
{
OverlayPostRenderCheck();
}

View File

@ -35,6 +35,7 @@
<ClCompile Include="drawing\engines\opengl\SwapFramebuffer.cpp" />
<ClCompile Include="drawing\engines\opengl\TextureCache.cpp" />
<ClCompile Include="drawing\engines\SoftwareDrawingEngine.cpp" />
<ClCompile Include="TextComposition.cpp" />
<ClCompile Include="Ui.cpp" />
<ClCompile Include="UiContext.cpp" />
<ClCompile Include="UiContext.Win32.cpp" />
@ -53,6 +54,7 @@
<ClInclude Include="drawing\engines\opengl\OpenGLShaderProgram.h" />
<ClInclude Include="drawing\engines\opengl\SwapFramebuffer.h" />
<ClInclude Include="drawing\engines\opengl\TextureCache.h" />
<ClInclude Include="TextComposition.h" />
<ClInclude Include="UiContext.h" />
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@ -15,6 +15,7 @@
#pragma endregion
#include <exception>
#include "config/Config.h"
#include "Context.h"
#include "OpenRCT2.h"
#include "ui/UiContext.h"
@ -88,4 +89,63 @@ extern "C"
{
GetContext()->GetUiContext()->SetCursor((CURSOR_ID)cursor);
}
void context_hide_cursor()
{
GetContext()->GetUiContext()->SetCursorVisible(false);
}
void context_show_cursor()
{
GetContext()->GetUiContext()->SetCursorVisible(true);
}
void context_get_cursor_position(sint32 * x, sint32 * y)
{
GetContext()->GetUiContext()->GetCursorPosition(x, y);
}
void context_get_cursor_position_scaled(sint32 * x, sint32 * y)
{
context_get_cursor_position(x, y);
// Compensate for window scaling.
*x = (sint32)ceilf(*x / gConfigGeneral.window_scale);
*y = (sint32)ceilf(*y / gConfigGeneral.window_scale);
}
void context_set_cursor_position(sint32 x, sint32 y)
{
GetContext()->GetUiContext()->SetCursorPosition(x, y);
}
const CursorState * context_get_cursor_state()
{
return GetContext()->GetUiContext()->GetCursorState();
}
const uint8 * context_get_keys_state()
{
return GetContext()->GetUiContext()->GetKeysState();
}
const uint8 * context_get_keys_pressed()
{
return GetContext()->GetUiContext()->GetKeysPressed();
}
void context_start_text_input(utf8 * buffer, size_t maxLength)
{
GetContext()->GetUiContext()->StartTextInput(buffer, maxLength);
}
void context_stop_text_input()
{
GetContext()->GetUiContext()->StopTextInput();
}
bool context_is_input_active()
{
return GetContext()->GetUiContext()->IsTextInputActive();
}
}

View File

@ -18,6 +18,25 @@
#include "common.h"
typedef struct CursorState
{
sint32 x, y;
uint8 left, middle, right, any;
sint32 wheel;
sint32 old;
bool touch, touchIsDouble;
uint32 touchDownTimestamp;
} CursorState;
enum
{
CURSOR_UP = 0,
CURSOR_DOWN = 1,
CURSOR_CHANGED = 2,
CURSOR_RELEASED = CURSOR_UP | CURSOR_CHANGED,
CURSOR_PRESSED = CURSOR_DOWN | CURSOR_CHANGED,
};
#ifdef __cplusplus
namespace OpenRCT2
@ -45,11 +64,23 @@ namespace OpenRCT2
#endif // __cplusplus
#if __cplusplus
#ifdef __cplusplus
extern "C"
{
#endif
void context_setcurrentcursor(sint32 cursor);
#if __cplusplus
void context_hide_cursor();
void context_show_cursor();
void context_get_cursor_position(sint32 * x, sint32 * y);
void context_get_cursor_position_scaled(sint32 * x, sint32 * y);
void context_set_cursor_position(sint32 x, sint32 y);
const CursorState * context_get_cursor_state();
const uint8 * context_get_keys_state();
const uint8 * context_get_keys_pressed();
void context_start_text_input(utf8 * buffer, size_t maxLength);
void context_stop_text_input();
bool context_is_input_active();
#ifdef __cplusplus
}
#endif

View File

@ -16,6 +16,8 @@
#include <memory>
#include <string>
#include "Context.h"
#include "ui/UiContext.h"
#include "core/Console.hpp"
#include "core/File.h"
#include "core/FileStream.hpp"
@ -463,7 +465,7 @@ namespace OpenRCT2
{
_lastTick = currentTick;
}
platform_process_messages();
GetContext()->GetUiContext()->ProcessMessages();
rct2_update();
if (!_isWindowMinimised)
{
@ -486,7 +488,7 @@ namespace OpenRCT2
_uncapTick = currentTick - UPDATE_TIME_MS - 1;
}
platform_process_messages();
GetContext()->GetUiContext()->ProcessMessages();
while (_uncapTick <= currentTick && currentTick - _uncapTick > UPDATE_TIME_MS)
{

View File

@ -690,3 +690,19 @@ void Mixer_SetVolume(float volume)
gMixer->SetVolume(volume);
}
}
sint32 DStoMixerVolume(sint32 volume)
{
return (sint32)(SDL_MIX_MAXVOLUME * (SDL_pow(10, (float)volume / 2000)));
}
float DStoMixerPan(sint32 pan)
{
return (((float)pan + -DSBPAN_LEFT) / DSBPAN_RIGHT) / 2;
}
double DStoMixerRate(sint32 frequency)
{
return (double)frequency / 22050;
}

View File

@ -19,17 +19,6 @@
#include "../common.h"
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
#include "../platform/platform.h"
#ifdef __cplusplus
}
#endif // __cplusplus
#define MIXER_LOOP_NONE 0
#define MIXER_LOOP_INFINITE -1
@ -89,9 +78,9 @@ void Mixer_Channel_SetGroup(void* channel, sint32 group);
void* Mixer_Play_Music(sint32 pathId, sint32 loop, sint32 streaming);
void Mixer_SetVolume(float volume);
static inline sint32 DStoMixerVolume(sint32 volume) { return (sint32)(SDL_MIX_MAXVOLUME * (SDL_pow(10, (float)volume / 2000))); }
static inline float DStoMixerPan(sint32 pan) { return (((float)pan + -DSBPAN_LEFT) / DSBPAN_RIGHT) / 2; }
static inline double DStoMixerRate(sint32 frequency) { return (double)frequency / 22050; }
sint32 DStoMixerVolume(sint32 volume);
float DStoMixerPan(sint32 pan);
double DStoMixerRate(sint32 frequency);
#ifdef __cplusplus
}

View File

@ -159,8 +159,9 @@ static sint32 game_get_next_input(sint32 *x, sint32 *y)
{
rct_mouse_data *input = get_mouse_input();
if (input == NULL) {
*x = gCursorState.x;
*y = gCursorState.y;
const CursorState * cursorState = context_get_cursor_state();
*x = cursorState->x;
*y = cursorState->y;
return 0;
} else {
*x = input->x;
@ -200,7 +201,7 @@ static void input_scroll_drag_begin(sint32 x, sint32 y, rct_window* w, rct_widge
_ticksSinceDragStart = 0;
_dragScrollIndex = window_get_scroll_data_index(w, widgetIndex);
platform_hide_cursor();
context_hide_cursor();
}
/**
@ -241,7 +242,7 @@ static void input_scroll_drag_continue(sint32 x, sint32 y, rct_window* w)
sint32 fixedCursorPositionX = (sint32) ceilf(gInputDragLastX * gConfigGeneral.window_scale);
sint32 fixedCursorPositionY = (sint32) ceilf(gInputDragLastY * gConfigGeneral.window_scale);
platform_set_cursor_position(fixedCursorPositionX, fixedCursorPositionY);
context_set_cursor_position(fixedCursorPositionX, fixedCursorPositionY);
}
/**
@ -252,7 +253,7 @@ static void input_scroll_right(sint32 x, sint32 y, sint32 state)
{
rct_window* w = window_find_by_number(_dragWidget.window_classification, _dragWidget.window_number);
if (w == NULL) {
platform_show_cursor();
context_show_cursor();
_inputState = INPUT_STATE_RESET;
return;
}
@ -267,7 +268,7 @@ static void input_scroll_right(sint32 x, sint32 y, sint32 state)
break;
case MOUSE_STATE_RIGHT_RELEASE:
_inputState = INPUT_STATE_RESET;
platform_show_cursor();
context_show_cursor();
break;
}
}
@ -502,8 +503,8 @@ static void input_viewport_drag_begin(rct_window *w, sint32 x, sint32 y)
_dragWidget.window_classification = w->classification;
_dragWidget.window_number = w->number;
_ticksSinceDragStart = 0;
platform_get_cursor_position(&gInputDragLastX, &gInputDragLastY);
platform_hide_cursor();
context_get_cursor_position(&gInputDragLastX, &gInputDragLastY);
context_hide_cursor();
// gInputFlags |= INPUT_FLAG_5;
}
@ -514,7 +515,7 @@ static void input_viewport_drag_continue()
rct_window *w;
rct_viewport *viewport;
platform_get_cursor_position(&newDragX, &newDragY);
context_get_cursor_position(&newDragX, &newDragY);
dx = newDragX - gInputDragLastX;
dy = newDragY - gInputDragLastY;
@ -530,7 +531,7 @@ static void input_viewport_drag_continue()
viewport = w->viewport;
_ticksSinceDragStart += gTicksSinceLastUpdate;
if (viewport == NULL) {
platform_show_cursor();
context_show_cursor();
_inputState = INPUT_STATE_RESET;
} else if (dx != 0 || dy != 0) {
if (!(w->flags & WF_NO_SCROLLING)) {
@ -552,13 +553,13 @@ static void input_viewport_drag_continue()
}
}
platform_set_cursor_position(gInputDragLastX, gInputDragLastY);
context_set_cursor_position(gInputDragLastX, gInputDragLastY);
}
static void input_viewport_drag_end()
{
_inputState = INPUT_STATE_RESET;
platform_show_cursor();
context_show_cursor();
}
#pragma endregion
@ -1411,14 +1412,15 @@ void title_handle_keyboard_input()
if (!gConsoleOpen) {
// Handle modifier keys and key scrolling
gInputPlaceObjectModifier = PLACE_OBJECT_MODIFIER_NONE;
if (gKeysState[SDL_SCANCODE_LSHIFT] || gKeysState[SDL_SCANCODE_RSHIFT])
const uint8 * keysState = context_get_keys_state();
if (keysState[SDL_SCANCODE_LSHIFT] || keysState[SDL_SCANCODE_RSHIFT])
gInputPlaceObjectModifier |= PLACE_OBJECT_MODIFIER_SHIFT_Z;
if (gKeysState[SDL_SCANCODE_LCTRL] || gKeysState[SDL_SCANCODE_RCTRL])
if (keysState[SDL_SCANCODE_LCTRL] || keysState[SDL_SCANCODE_RCTRL])
gInputPlaceObjectModifier |= PLACE_OBJECT_MODIFIER_COPY_Z;
if (gKeysState[SDL_SCANCODE_LALT] || gKeysState[SDL_SCANCODE_RALT])
if (keysState[SDL_SCANCODE_LALT] || keysState[SDL_SCANCODE_RALT])
gInputPlaceObjectModifier |= 4;
#ifdef __MACOSX__
if (gKeysState[SDL_SCANCODE_LGUI] || gKeysState[SDL_SCANCODE_RGUI]) {
if (keysState[SDL_SCANCODE_LGUI] || keysState[SDL_SCANCODE_RGUI]) {
gInputPlaceObjectModifier |= 8;
}
#endif
@ -1430,7 +1432,7 @@ void title_handle_keyboard_input()
// Reserve backtick for console
if (key == SDL_SCANCODE_GRAVE) {
if ((gConfigGeneral.debugging_tools && !platform_is_input_active()) || gConsoleOpen) {
if ((gConfigGeneral.debugging_tools && !context_is_input_active()) || gConsoleOpen) {
window_cancel_textbox();
console_toggle();
}
@ -1476,17 +1478,18 @@ void game_handle_keyboard_input()
// Handle modifier keys and key scrolling
gInputPlaceObjectModifier = PLACE_OBJECT_MODIFIER_NONE;
if (gKeysState[SDL_SCANCODE_LSHIFT] || gKeysState[SDL_SCANCODE_RSHIFT]) {
const uint8 * keysState = context_get_keys_state();
if (keysState[SDL_SCANCODE_LSHIFT] || keysState[SDL_SCANCODE_RSHIFT]) {
gInputPlaceObjectModifier |= PLACE_OBJECT_MODIFIER_SHIFT_Z;
}
if (gKeysState[SDL_SCANCODE_LCTRL] || gKeysState[SDL_SCANCODE_RCTRL]) {
if (keysState[SDL_SCANCODE_LCTRL] || keysState[SDL_SCANCODE_RCTRL]) {
gInputPlaceObjectModifier |= PLACE_OBJECT_MODIFIER_COPY_Z;
}
if (gKeysState[SDL_SCANCODE_LALT] || gKeysState[SDL_SCANCODE_RALT]) {
if (keysState[SDL_SCANCODE_LALT] || keysState[SDL_SCANCODE_RALT]) {
gInputPlaceObjectModifier |= 4;
}
#ifdef __MACOSX__
if (gKeysState[SDL_SCANCODE_LGUI] || gKeysState[SDL_SCANCODE_RGUI]) {
if (keysState[SDL_SCANCODE_LGUI] || keysState[SDL_SCANCODE_RGUI]) {
gInputPlaceObjectModifier |= 8;
}
#endif
@ -1501,7 +1504,7 @@ void game_handle_keyboard_input()
// Reserve backtick for console
if (key == SDL_SCANCODE_GRAVE) {
if ((gConfigGeneral.debugging_tools && !platform_is_input_active()) || gConsoleOpen) {
if ((gConfigGeneral.debugging_tools && !context_is_input_active()) || gConsoleOpen) {
window_cancel_textbox();
console_toggle();
}
@ -1536,10 +1539,10 @@ void game_handle_keyboard_input()
*/
sint32 get_next_key()
{
sint32 i;
for (i = 0; i < 221; i++) {
if (gKeysPressed[i]) {
gKeysPressed[i] = 0;
uint8 * keysPressed = (uint8 *)context_get_keys_pressed();
for (sint32 i = 0; i < 221; i++) {
if (keysPressed[i]) {
keysPressed[i] = 0;
return i;
}
}
@ -1617,15 +1620,16 @@ void game_handle_edge_scroll()
scrollY = 0;
// Scroll left / right
if (gCursorState.x == 0)
const CursorState * cursorState = context_get_cursor_state();
if (cursorState->x == 0)
scrollX = -1;
else if (gCursorState.x >= gScreenWidth - 1)
else if (cursorState->x >= gScreenWidth - 1)
scrollX = 1;
// Scroll up / down
if (gCursorState.y == 0)
if (cursorState->y == 0)
scrollY = -1;
else if (gCursorState.y >= gScreenHeight - 1)
else if (cursorState->y >= gScreenHeight - 1)
scrollY = 1;
// Scroll viewport
@ -1661,25 +1665,26 @@ void game_handle_key_scroll()
scrollX = 0;
scrollY = 0;
const uint8 * keysState = context_get_keys_state();
for (sint32 shortcutId = SHORTCUT_SCROLL_MAP_UP; shortcutId <= SHORTCUT_SCROLL_MAP_RIGHT; shortcutId++) {
uint16 shortcutKey = gShortcutKeys[shortcutId];
uint8 scancode = shortcutKey & 0xFF;
if (shortcutKey == 0xFFFF) continue;
if (!gKeysState[scancode]) continue;
if (!keysState[scancode]) continue;
if (shortcutKey & SHIFT) {
if (!gKeysState[SDL_SCANCODE_LSHIFT] && !gKeysState[SDL_SCANCODE_RSHIFT]) continue;
if (!keysState[SDL_SCANCODE_LSHIFT] && !keysState[SDL_SCANCODE_RSHIFT]) continue;
}
if (shortcutKey & CTRL) {
if (!gKeysState[SDL_SCANCODE_LCTRL] && !gKeysState[SDL_SCANCODE_RCTRL]) continue;
if (!keysState[SDL_SCANCODE_LCTRL] && !keysState[SDL_SCANCODE_RCTRL]) continue;
}
if (shortcutKey & ALT) {
if (!gKeysState[SDL_SCANCODE_LALT] && !gKeysState[SDL_SCANCODE_RALT]) continue;
if (!keysState[SDL_SCANCODE_LALT] && !keysState[SDL_SCANCODE_RALT]) continue;
}
#ifdef __MACOSX__
if (shortcutKey & CMD) {
if (!gKeysState[SDL_SCANCODE_LGUI] && !gKeysState[SDL_SCANCODE_RGUI]) continue;
if (!keysState[SDL_SCANCODE_LGUI] && !keysState[SDL_SCANCODE_RGUI]) continue;
}
#endif

View File

@ -16,6 +16,7 @@
#include "../audio/audio.h"
#include "../audio/AudioMixer.h"
#include "../Context.h"
#include "../interface/themes.h"
#include "../localisation/localisation.h"
#include "../network/network.h"
@ -44,13 +45,13 @@ static void chat_clear_input();
void chat_open()
{
gChatOpen = true;
platform_start_text_input(_chatCurrentLine, sizeof(_chatCurrentLine));
context_start_text_input(_chatCurrentLine, sizeof(_chatCurrentLine));
}
void chat_close()
{
gChatOpen = false;
platform_stop_text_input();
context_stop_text_input();
}
void chat_toggle()

View File

@ -18,6 +18,7 @@
#include <SDL_scancode.h>
#include "../config/Config.h"
#include "../Context.h"
#include "../drawing/drawing.h"
#include "../game.h"
#include "../input.h"
@ -91,14 +92,14 @@ void console_open()
_consoleScrollPos = 0;
console_refresh_caret();
console_update_scroll();
platform_start_text_input(_consoleCurrentLine, sizeof(_consoleCurrentLine));
context_start_text_input(_consoleCurrentLine, sizeof(_consoleCurrentLine));
}
void console_close()
{
gConsoleOpen = false;
console_invalidate();
platform_stop_text_input();
context_stop_text_input();
}
void console_toggle()
@ -412,7 +413,7 @@ static void console_clear_input()
{
_consoleCurrentLine[0] = 0;
if (gConsoleOpen) {
platform_start_text_input(_consoleCurrentLine, sizeof(_consoleCurrentLine));
context_start_text_input(_consoleCurrentLine, sizeof(_consoleCurrentLine));
}
}

View File

@ -15,6 +15,7 @@
#pragma endregion
#include "../audio/audio.h"
#include "../Context.h"
#include "../core/Guard.hpp"
#include "../drawing/drawing.h"
#include "../editor.h"
@ -295,7 +296,7 @@ static bool window_other_wheel_input(rct_window *w, rct_widgetindex widgetIndex,
static void window_all_wheel_input()
{
// Get wheel value
sint32 raw = gCursorState.wheel;
sint32 raw = context_get_cursor_state()->wheel;
sint32 wheel = 0;
while (1) {
raw -= 120;
@ -311,14 +312,17 @@ static void window_all_wheel_input()
wheel += 17;
}
raw -= 120;
gCursorState.wheel = raw;
// TODO do something about this hack
CursorState * cursorState = (CursorState *)context_get_cursor_state();
cursorState->wheel = raw;
if (wheel == 0)
return;
// Check window cursor is over
if (!(input_test_flag(INPUT_FLAG_5))) {
rct_window *w = window_find_from_point(gCursorState.x, gCursorState.y);
rct_window *w = window_find_from_point(cursorState->x, cursorState->y);
if (w != NULL) {
// Check if main window
if (w->classification == WC_MAIN_WINDOW || w->classification == WC_VIEWPORT) {
@ -327,7 +331,7 @@ static void window_all_wheel_input()
}
// Check scroll view, cursor is over
rct_widgetindex widgetIndex = window_find_widget_from_point(w, gCursorState.x, gCursorState.y);
rct_widgetindex widgetIndex = window_find_widget_from_point(w, cursorState->x, cursorState->y);
if (widgetIndex != -1) {
rct_widget *widget = &w->widgets[widgetIndex];
if (widget->type == WWT_SCROLL) {
@ -1471,7 +1475,7 @@ void window_viewport_get_map_coords_by_cursor(rct_window *w, sint16 *map_x, sint
{
// Get mouse position to offset against.
sint32 mouse_x, mouse_y;
platform_get_cursor_position_scaled(&mouse_x, &mouse_y);
context_get_cursor_position_scaled(&mouse_x, &mouse_y);
// Compute map coordinate by mouse position.
get_map_coordinates_from_pos(mouse_x, mouse_y, VIEWPORT_INTERACTION_MASK_NONE, map_x, map_y, NULL, NULL, NULL);
@ -1499,7 +1503,7 @@ void window_viewport_centre_tile_around_cursor(rct_window *w, sint16 map_x, sint
// Get mouse position to offset against.
sint32 mouse_x, mouse_y;
platform_get_cursor_position_scaled(&mouse_x, &mouse_y);
context_get_cursor_position_scaled(&mouse_x, &mouse_y);
// Rebase mouse position onto centre of window, and compensate for zoom level.
sint32 rebased_x = ((w->width >> 1) - mouse_x) * (1 << w->viewport->zoom),
@ -2507,7 +2511,7 @@ void window_start_textbox(rct_window *call_w, rct_widgetindex call_widget, rct_s
// from crashing the game.
gTextBoxInput[maxLength - 1] = '\0';
platform_start_text_input(gTextBoxInput, maxLength);
context_start_text_input(gTextBoxInput, maxLength);
}
void window_cancel_textbox()
@ -2520,7 +2524,7 @@ void window_cancel_textbox()
window_event_textinput_call(w, gCurrentTextBox.widget_index, NULL);
gCurrentTextBox.window.classification = WC_NULL;
gCurrentTextBox.window.number = 0;
platform_stop_text_input();
context_stop_text_input();
gUsingWidgetTextBox = false;
widget_invalidate(w, gCurrentTextBox.widget_index);
gCurrentTextBox.widget_index = WWT_LAST;

View File

@ -16,6 +16,7 @@
#include "audio/audio.h"
#include "audio/AudioMixer.h"
#include "Context.h"
#include "drawing/drawing.h"
#include "intro.h"
#include "rct2.h"
@ -221,7 +222,7 @@ void intro_draw(rct_drawpixelinfo *dpi)
static void screen_intro_process_mouse_input()
{
if (gCursorState.any == CURSOR_PRESSED) {
if (context_get_cursor_state()->any == CURSOR_PRESSED) {
screen_intro_skip_part();
}
}
@ -232,8 +233,12 @@ static void screen_intro_process_mouse_input()
*/
static void screen_intro_process_keyboard_input()
{
if (gLastKeyPressed != 0) {
screen_intro_skip_part();
const uint8 * keys = context_get_keys_state();
for (int i = 0; i < 256; i++) {
if (keys[i] != 0) {
screen_intro_skip_part();
break;
}
}
}

View File

@ -86,23 +86,6 @@ typedef struct rct2_time {
uint8 second;
} rct2_time;
typedef struct openrct2_cursor {
sint32 x, y;
uint8 left, middle, right, any;
sint32 wheel;
sint32 old;
bool touch, touchIsDouble;
uint32 touchDownTimestamp;
} openrct2_cursor;
enum {
CURSOR_UP = 0,
CURSOR_DOWN = 1,
CURSOR_CHANGED = 2,
CURSOR_RELEASED = CURSOR_UP | CURSOR_CHANGED,
CURSOR_PRESSED = CURSOR_DOWN | CURSOR_CHANGED,
};
typedef enum {FD_OPEN, FD_SAVE} filedialog_type;
typedef struct file_dialog_desc {
@ -116,44 +99,18 @@ typedef struct file_dialog_desc {
} filters[8];
} file_dialog_desc;
extern openrct2_cursor gCursorState;
extern const uint8 *gKeysState;
extern uint8 *gKeysPressed;
extern uint32 gLastKeyPressed;
extern textinputbuffer gTextInput;
extern bool gTextInputCompositionActive;
extern utf8 gTextInputComposition[32];
extern sint32 gTextInputCompositionStart;
extern sint32 gTextInputCompositionLength;
extern sint32 gResolutionsAllowAnyAspectRatio;
extern sint32 gNumResolutions;
extern resolution_t *gResolutions;
extern SDL_Window *gWindow;
extern SDL_Color gPalette[256];
extern bool gSteamOverlayActive;
// Platform shared definitions
void platform_update_fullscreen_resolutions();
void platform_get_closest_resolution(sint32 inWidth, sint32 inHeight, sint32 *outWidth, sint32 *outHeight);
void platform_init();
void platform_draw();
void platform_draw_require_end();
void platform_free();
void platform_trigger_resize();
void platform_update_palette(const uint8 *colours, sint32 start_index, sint32 num_colours);
void platform_set_fullscreen_mode(sint32 mode);
void platform_toggle_windowed_mode();
void platform_set_cursor(uint8 cursor);
void platform_refresh_video();
void platform_process_messages();
sint32 platform_scancode_to_rct_keycode(sint32 sdl_key);
void platform_start_text_input(utf8 *buffer, sint32 max_length);
void platform_stop_text_input();
bool platform_is_input_active();
void platform_get_date_utc(rct2_date *out_date);
void platform_get_time_utc(rct2_time *out_time);
void platform_get_date_local(rct2_date *out_date);
@ -183,11 +140,6 @@ sint32 platform_get_drives();
bool platform_file_copy(const utf8 *srcPath, const utf8 *dstPath, bool overwrite);
bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath);
bool platform_file_delete(const utf8 *path);
void platform_hide_cursor();
void platform_show_cursor();
void platform_get_cursor_position(sint32 *x, sint32 *y);
void platform_get_cursor_position_scaled(sint32 *x, sint32 *y);
void platform_set_cursor_position(sint32 x, sint32 y);
uint32 platform_get_ticks();
void platform_sleep(uint32 ms);
void platform_resolve_user_data_path();

View File

@ -49,21 +49,6 @@
typedef void(*update_palette_func)(const uint8*, sint32, sint32);
openrct2_cursor gCursorState;
const uint8 *gKeysState;
uint8 *gKeysPressed;
uint32 gLastKeyPressed;
textinputbuffer gTextInput;
bool gTextInputCompositionActive;
utf8 gTextInputComposition[32];
sint32 gTextInputCompositionStart;
sint32 gTextInputCompositionLength;
sint32 gNumResolutions = 0;
resolution_t *gResolutions = NULL;
sint32 gResolutionsAllowAnyAspectRatio = 0;
SDL_Window *gWindow = NULL;
SDL_Renderer *gRenderer = NULL;
SDL_Texture *gBufferTexture = NULL;
@ -147,277 +132,6 @@ void platform_update_palette(const uint8* colours, sint32 start_index, sint32 nu
}
}
void platform_process_messages()
{
SDL_Event e;
gLastKeyPressed = 0;
// gCursorState.wheel = 0;
gCursorState.left &= ~CURSOR_CHANGED;
gCursorState.middle &= ~CURSOR_CHANGED;
gCursorState.right &= ~CURSOR_CHANGED;
gCursorState.old = 0;
gCursorState.touch = false;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT:
// rct2_finish();
rct2_quit();
break;
case SDL_WINDOWEVENT:
// HACK: Fix #2158, OpenRCT2 does not draw if it does not think that the window is
// visible - due a bug in SDL2.0.3 this hack is required if the
// window is maximised, minimised and then restored again.
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
if (SDL_GetWindowFlags(gWindow) & SDL_WINDOW_MAXIMIZED) {
SDL_RestoreWindow(gWindow);
SDL_MaximizeWindow(gWindow);
}
if ((SDL_GetWindowFlags(gWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
SDL_RestoreWindow(gWindow);
SDL_SetWindowFullscreen(gWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
}
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
platform_resize(e.window.data1, e.window.data2);
if (gConfigSound.audio_focus && gConfigSound.sound_enabled) {
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
Mixer_SetVolume(1);
}
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
Mixer_SetVolume(0);
}
}
break;
case SDL_MOUSEMOTION:
gCursorState.x = (sint32)(e.motion.x / gConfigGeneral.window_scale);
gCursorState.y = (sint32)(e.motion.y / gConfigGeneral.window_scale);
break;
case SDL_MOUSEWHEEL:
if (gConsoleOpen) {
console_scroll(e.wheel.y);
break;
}
gCursorState.wheel += e.wheel.y * 128;
break;
case SDL_MOUSEBUTTONDOWN:
{
sint32 x = (sint32)(e.button.x / gConfigGeneral.window_scale);
sint32 y = (sint32)(e.button.y / gConfigGeneral.window_scale);
switch (e.button.button) {
case SDL_BUTTON_LEFT:
store_mouse_input(MOUSE_STATE_LEFT_PRESS, x, y);
gCursorState.left = CURSOR_PRESSED;
gCursorState.old = 1;
break;
case SDL_BUTTON_MIDDLE:
gCursorState.middle = CURSOR_PRESSED;
break;
case SDL_BUTTON_RIGHT:
store_mouse_input(MOUSE_STATE_RIGHT_PRESS, x, y);
gCursorState.right = CURSOR_PRESSED;
gCursorState.old = 2;
break;
}
break;
}
case SDL_MOUSEBUTTONUP:
{
sint32 x = (sint32)(e.button.x / gConfigGeneral.window_scale);
sint32 y = (sint32)(e.button.y / gConfigGeneral.window_scale);
switch (e.button.button) {
case SDL_BUTTON_LEFT:
store_mouse_input(MOUSE_STATE_LEFT_RELEASE, x, y);
gCursorState.left = CURSOR_RELEASED;
gCursorState.old = 3;
break;
case SDL_BUTTON_MIDDLE:
gCursorState.middle = CURSOR_RELEASED;
break;
case SDL_BUTTON_RIGHT:
store_mouse_input(MOUSE_STATE_RIGHT_RELEASE, x, y);
gCursorState.right = CURSOR_RELEASED;
gCursorState.old = 4;
break;
}
break;
}
// Apple sends touchscreen events for trackpads, so ignore these events on macOS
#ifndef __MACOSX__
case SDL_FINGERMOTION:
gCursorState.x = (sint32)(e.tfinger.x * gScreenWidth);
gCursorState.y = (sint32)(e.tfinger.y * gScreenHeight);
break;
case SDL_FINGERDOWN:
{
sint32 x = (sint32)(e.tfinger.x * gScreenWidth);
sint32 y = (sint32)(e.tfinger.y * gScreenHeight);
gCursorState.touchIsDouble = (!gCursorState.touchIsDouble
&& e.tfinger.timestamp - gCursorState.touchDownTimestamp < TOUCH_DOUBLE_TIMEOUT);
if (gCursorState.touchIsDouble) {
store_mouse_input(MOUSE_STATE_RIGHT_PRESS, x, y);
gCursorState.right = CURSOR_PRESSED;
gCursorState.old = 2;
} else {
store_mouse_input(MOUSE_STATE_LEFT_PRESS, x, y);
gCursorState.left = CURSOR_PRESSED;
gCursorState.old = 1;
}
gCursorState.touch = true;
gCursorState.touchDownTimestamp = e.tfinger.timestamp;
break;
}
case SDL_FINGERUP:
{
sint32 x = (sint32)(e.tfinger.x * gScreenWidth);
sint32 y = (sint32)(e.tfinger.y * gScreenHeight);
if (gCursorState.touchIsDouble) {
store_mouse_input(MOUSE_STATE_RIGHT_RELEASE, x, y);
gCursorState.left = CURSOR_RELEASED;
gCursorState.old = 4;
} else {
store_mouse_input(MOUSE_STATE_LEFT_RELEASE, x, y);
gCursorState.left = CURSOR_RELEASED;
gCursorState.old = 3;
}
gCursorState.touch = true;
break;
}
#endif
case SDL_KEYDOWN:
if (gTextInputCompositionActive) break;
if (e.key.keysym.sym == SDLK_KP_ENTER){
// Map Keypad enter to regular enter.
e.key.keysym.scancode = SDL_SCANCODE_RETURN;
}
gLastKeyPressed = e.key.keysym.sym;
gKeysPressed[e.key.keysym.scancode] = 1;
// Text input
if (gTextInput.buffer == NULL) break;
// Clear the input on <CTRL>Backspace (Windows/Linux) or <MOD>Backspace (macOS)
if (e.key.keysym.sym == SDLK_BACKSPACE && (e.key.keysym.mod & KEYBOARD_PRIMARY_MODIFIER)) {
textinputbuffer_clear(&gTextInput);
console_refresh_caret();
window_update_textbox();
}
// If backspace and we have input text with a cursor position none zero
if (e.key.keysym.sym == SDLK_BACKSPACE) {
if (gTextInput.selection_offset > 0) {
size_t endOffset = gTextInput.selection_offset;
textinputbuffer_cursor_left(&gTextInput);
gTextInput.selection_size = endOffset - gTextInput.selection_offset;
textinputbuffer_remove_selected(&gTextInput);
console_refresh_caret();
window_update_textbox();
}
}
if (e.key.keysym.sym == SDLK_HOME) {
textinputbuffer_cursor_home(&gTextInput);
console_refresh_caret();
}
if (e.key.keysym.sym == SDLK_END) {
textinputbuffer_cursor_end(&gTextInput);
console_refresh_caret();
}
if (e.key.keysym.sym == SDLK_DELETE) {
size_t startOffset = gTextInput.selection_offset;
textinputbuffer_cursor_right(&gTextInput);
gTextInput.selection_size = gTextInput.selection_offset - startOffset;
gTextInput.selection_offset = startOffset;
textinputbuffer_remove_selected(&gTextInput);
console_refresh_caret();
window_update_textbox();
}
if (e.key.keysym.sym == SDLK_RETURN) {
window_cancel_textbox();
}
if (e.key.keysym.sym == SDLK_LEFT) {
textinputbuffer_cursor_left(&gTextInput);
console_refresh_caret();
}
else if (e.key.keysym.sym == SDLK_RIGHT) {
textinputbuffer_cursor_right(&gTextInput);
console_refresh_caret();
}
else if (e.key.keysym.sym == SDLK_v && (SDL_GetModState() & KEYBOARD_PRIMARY_MODIFIER)) {
if (SDL_HasClipboardText()) {
utf8* text = SDL_GetClipboardText();
utf8_remove_formatting(text, false);
textinputbuffer_insert(&gTextInput, text);
SDL_free(text);
window_update_textbox();
}
}
break;
case SDL_MULTIGESTURE:
if (e.mgesture.numFingers == 2) {
if (e.mgesture.timestamp > _lastGestureTimestamp + 1000)
_gestureRadius = 0;
_lastGestureTimestamp = e.mgesture.timestamp;
_gestureRadius += e.mgesture.dDist;
// Zoom gesture
const sint32 tolerance = 128;
sint32 gesturePixels = (sint32)(_gestureRadius * gScreenWidth);
if (abs(gesturePixels) > tolerance) {
_gestureRadius = 0;
main_window_zoom(gesturePixels > 0, true);
}
}
break;
case SDL_TEXTEDITING:
// When inputting Korean characters, `e.edit.length` is always Zero.
safe_strcpy(gTextInputComposition, e.edit.text, sizeof(gTextInputComposition));
gTextInputCompositionStart = e.edit.start;
gTextInputCompositionLength = e.edit.length;
gTextInputCompositionActive = ((e.edit.length != 0 || strlen(e.edit.text) != 0) && gTextInputComposition[0] != 0);
break;
case SDL_TEXTINPUT:
// will receive an `SDL_TEXTINPUT` event when a composition is committed.
// so, set gTextInputCompositionActive to false.
gTextInputCompositionActive = false;
if (gTextInput.buffer == NULL) break;
// HACK ` will close console, so don't input any text
if (e.text.text[0] == '`' && gConsoleOpen) {
break;
}
utf8* newText = e.text.text;
utf8_remove_formatting(newText, false);
textinputbuffer_insert(&gTextInput, newText);
console_refresh_caret();
window_update_textbox();
break;
default:
break;
}
}
gCursorState.any = gCursorState.left | gCursorState.middle | gCursorState.right;
// Updates the state of the keys
sint32 numKeys = 256;
gKeysState = SDL_GetKeyboardState(&numKeys);
}
void platform_init()
{
gKeysPressed = malloc(sizeof(uint8) * 256);
@ -450,56 +164,6 @@ void platform_free()
free(gKeysPressed);
}
void platform_start_text_input(utf8* buffer, sint32 max_length)
{
// TODO This doesn't work, and position could be improved to where text entry is
SDL_Rect rect = { 10, 10, 100, 100 };
SDL_SetTextInputRect(&rect);
SDL_StartTextInput();
textinputbuffer_init(&gTextInput, buffer, max_length);
}
bool platform_is_input_active()
{
return SDL_IsTextInputActive() && gTextInput.buffer != NULL;
}
void platform_stop_text_input()
{
SDL_StopTextInput();
gTextInput.buffer = NULL;
gTextInputCompositionActive = false;
}
void platform_set_fullscreen_mode(sint32 mode)
{
sint32 width, height;
mode = _fullscreen_modes[mode];
// HACK Changing window size when in fullscreen usually has no effect
if (mode == SDL_WINDOW_FULLSCREEN)
SDL_SetWindowFullscreen(gWindow, 0);
// Set window size
if (mode == SDL_WINDOW_FULLSCREEN) {
platform_update_fullscreen_resolutions();
platform_get_closest_resolution(gConfigGeneral.fullscreen_width, gConfigGeneral.fullscreen_height, &width, &height);
SDL_SetWindowSize(gWindow, width, height);
} else if (mode == 0) {
SDL_SetWindowSize(gWindow, gConfigGeneral.window_width, gConfigGeneral.window_height);
}
if (SDL_SetWindowFullscreen(gWindow, mode)) {
log_fatal("SDL_SetWindowFullscreen %s", SDL_GetError());
exit(1);
// TODO try another display mode rather than just exiting the game
}
}
void platform_toggle_windowed_mode()
{
sint32 targetMode = gConfigGeneral.fullscreen_mode == 0 ? 2 : 0;
@ -519,35 +183,6 @@ void platform_refresh_video()
gfx_invalidate_screen();
}
void platform_hide_cursor()
{
SDL_ShowCursor(SDL_DISABLE);
}
void platform_show_cursor()
{
SDL_ShowCursor(SDL_ENABLE);
}
void platform_get_cursor_position(sint32 *x, sint32 *y)
{
SDL_GetMouseState(x, y);
}
void platform_get_cursor_position_scaled(sint32 *x, sint32 *y)
{
platform_get_cursor_position(x, y);
// Compensate for window scaling.
*x = (sint32) ceilf(*x / gConfigGeneral.window_scale);
*y = (sint32) ceilf(*y / gConfigGeneral.window_scale);
}
void platform_set_cursor_position(sint32 x, sint32 y)
{
SDL_WarpMouseInWindow(NULL, x, y);
}
uint32 platform_get_ticks()
{
#ifdef _WIN32

View File

@ -20,6 +20,8 @@
#include "../common.h"
#include "../interface/Cursors.h"
struct CursorState;
namespace OpenRCT2
{
namespace Drawing
@ -42,7 +44,7 @@ namespace OpenRCT2
const utf8 * Buffer; // UTF-8 stream
size_t BufferSize; // Maximum number of bytes (excluding null terminator)
size_t Size; // Number of bytes (excluding null terminator)
uint32 Length; // Number of codepoints
size_t Length; // Number of codepoints
size_t SelectionStart; // Selection start, in bytes
size_t SelectionSize; // Selection length in bytes
};
@ -83,21 +85,30 @@ namespace OpenRCT2
virtual ~IUiContext() = default;
// Window
virtual CURSOR_ID GetCursor() abstract;
virtual void SetCursor(CURSOR_ID cursor) abstract;
virtual void * GetWindow() abstract;
virtual sint32 GetWidth() abstract;
virtual sint32 GetHeight() abstract;
virtual void SetFullscreenMode(FULLSCREEN_MODE mode) abstract;
virtual std::vector<Resolution> GetFullscreenResolutions() abstract;
virtual bool IsSteamOverlayActive() abstract;
virtual void ProcessMessages() abstract;
// Input
virtual const CursorState * GetCursorState() abstract;
virtual CURSOR_ID GetCursor() abstract;
virtual void SetCursor(CURSOR_ID cursor) abstract;
virtual void SetCursorVisible(bool value) abstract;
virtual void GetCursorPosition(sint32 * x, sint32 * y) abstract;
virtual void SetCursorPosition(sint32 x, sint32 y) abstract;
virtual const uint8 * GetKeysState() abstract;
virtual const uint8 * GetKeysPressed() abstract;
// Drawing
virtual Drawing::IDrawingEngine * CreateDrawingEngine(Drawing::DRAWING_ENGINE_TYPE type) abstract;
// Text input
virtual bool IsTextInputActive() abstract;
virtual const TextInputSession * StartTextInput(utf8 * buffer, sint32 bufferSize) abstract;
virtual const TextInputSession * StartTextInput(utf8 * buffer, size_t bufferSize) abstract;
virtual void StopTextInput() abstract;
};
}