summaryrefslogtreecommitdiff
path: root/indra/llwindow
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llwindow')
-rw-r--r--indra/llwindow/CMakeLists.txt3
-rw-r--r--indra/llwindow/llgamecontrol.cpp605
-rw-r--r--indra/llwindow/llgamecontrol.h86
-rw-r--r--indra/llwindow/llkeyboard.cpp39
-rw-r--r--indra/llwindow/llkeyboardheadless.h19
-rw-r--r--indra/llwindow/llkeyboardmacosx.cpp2
-rw-r--r--indra/llwindow/llkeyboardmacosx.h14
-rw-r--r--indra/llwindow/llkeyboardwin32.cpp4
-rw-r--r--indra/llwindow/llkeyboardwin32.h19
-rw-r--r--indra/llwindow/llwindow.cpp46
-rw-r--r--indra/llwindow/llwindowsdl.h2
11 files changed, 785 insertions, 54 deletions
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index 075e17235a..e251af3e6c 100644
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -18,9 +18,11 @@ include(LLWindow)
include(UI)
include(ViewerMiscLibs)
include(GLM)
+include(SDL2)
set(llwindow_SOURCE_FILES
llcursortypes.cpp
+ llgamecontrol.cpp
llkeyboard.cpp
llkeyboardheadless.cpp
llwindowheadless.cpp
@@ -32,6 +34,7 @@ set(llwindow_HEADER_FILES
CMakeLists.txt
llcursortypes.h
+ llgamecontrol.h
llkeyboard.h
llkeyboardheadless.h
llwindowheadless.h
diff --git a/indra/llwindow/llgamecontrol.cpp b/indra/llwindow/llgamecontrol.cpp
new file mode 100644
index 0000000000..5dc01c5e54
--- /dev/null
+++ b/indra/llwindow/llgamecontrol.cpp
@@ -0,0 +1,605 @@
+/**
+ * @file llgamecontrol.h
+ * @brief GameController detection and management
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llgamecontrol.h"
+
+#include <algorithm>
+#include <chrono>
+#include <map>
+
+#include "SDL2/SDL.h"
+#include "SDL2/SDL_gamecontroller.h"
+#include "SDL2/SDL_joystick.h"
+
+constexpr size_t NUM_AXES = 6;
+
+// internal class for managing list of controllers and per-controller state
+class LLGameControllerManager
+{
+public:
+ void addController(SDL_JoystickID id, SDL_GameController* controller);
+ void removeController(SDL_JoystickID id);
+
+ void onAxis(SDL_JoystickID id, U8 axis, S16 value);
+ void onButton(SDL_JoystickID id, U8 button, bool pressed);
+
+ void onKeyButton(U8 button, bool pressed);
+ void onKeyAxis(U8 axis, U16 value);
+
+ void clearAllInput();
+ void clearAllKeys();
+ size_t getControllerIndex(SDL_JoystickID id) const;
+
+ void computeFinalState(LLGameControl::State& state);
+
+ void clear();
+
+private:
+ std::vector<SDL_JoystickID> mControllerIDs;
+ std::vector<SDL_GameController*> mControllers;
+ std::vector<LLGameControl::State> mStates;
+ LLGameControl::State mKeyboardState;
+};
+
+// local globals
+namespace
+{
+ LLGameControl* g_gameControl = nullptr;
+ LLGameControllerManager g_manager;
+
+ // The GameControlInput message is sent via UDP which is lossy.
+ // Since we send the only the list of pressed buttons the receiving
+ // side can compute the difference between subsequent states to
+ // find button-down/button-up events.
+ //
+ // To reduce the likelihood of buttons being stuck "pressed" forever
+ // on the receiving side (for lost final packet) we resend the last
+ // data state. However, to keep th ambient resend bandwidth low we
+ // expand the resend period at a geometric rate.
+ //
+ constexpr U64 MSEC_PER_NSEC = 1e6;
+ constexpr U64 FIRST_RESEND_PERIOD = 100 * MSEC_PER_NSEC;
+ constexpr U64 RESEND_EXPANSION_RATE = 10;
+ LLGameControl::State g_gameControlState;
+ U64 g_lastSend = 0;
+ U64 g_nextResendPeriod = FIRST_RESEND_PERIOD;
+
+ std::map<U16, U8> g_keyButtonMap;
+ std::map<U16, U8> g_keyAxisMapPositive;
+ std::map<U16, U8> g_keyAxisMapNegative;
+
+ bool g_includeKeyboardButtons = false;
+
+ constexpr U8 MAX_AXIS = 5;
+ constexpr U8 MAX_BUTTON = 31;
+}
+
+LLGameControl::~LLGameControl()
+{
+ terminate();
+}
+
+LLGameControl::State::State() : mButtons(0)
+{
+ mAxes.resize(NUM_AXES, 0);
+ mPrevAxes.resize(NUM_AXES, 0);
+}
+
+bool LLGameControl::State::onButton(U8 button, bool pressed)
+{
+ U32 old_buttons = mButtons;
+ if (button <= MAX_BUTTON)
+ {
+ if (pressed)
+ {
+ mButtons |= (0x01 << button);
+ }
+ else
+ {
+ mButtons &= ~(0x01 << button);
+ }
+ }
+ bool changed = (old_buttons != mButtons);
+ return changed;
+}
+
+void LLGameControllerManager::addController(SDL_JoystickID id, SDL_GameController* controller)
+{
+ if (controller)
+ {
+ size_t i = 0;
+ for (; i < mControllerIDs.size(); ++i)
+ {
+ if (id == mControllerIDs[i])
+ {
+ break;
+ }
+ }
+ if (i == mControllerIDs.size())
+ {
+ mControllerIDs.push_back(id);
+ mControllers.push_back(controller);
+ mStates.push_back(LLGameControl::State());
+ LL_DEBUGS("SDL2") << "joystick=0x" << std::hex << id << std::dec
+ << " controller=" << controller
+ << LL_ENDL;
+ }
+ }
+}
+
+void LLGameControllerManager::removeController(SDL_JoystickID id)
+{
+ size_t i = 0;
+ size_t num_controllers = mControllerIDs.size();
+ for (; i < num_controllers; ++i)
+ {
+ if (id == mControllerIDs[i])
+ {
+ LL_DEBUGS("SDL2") << "joystick=0x" << std::hex << id << std::dec
+ << " controller=" << mControllers[i]
+ << LL_ENDL;
+
+ mControllerIDs[i] = mControllerIDs[num_controllers - 1];
+ mControllers[i] = mControllers[num_controllers - 1];
+ mStates[i] = mStates[num_controllers - 1];
+
+ mControllerIDs.pop_back();
+ mControllers.pop_back();
+ mStates.pop_back();
+ break;
+ }
+ }
+}
+
+size_t LLGameControllerManager::getControllerIndex(SDL_JoystickID id) const
+{
+ constexpr size_t UNREASONABLY_HIGH_INDEX = 1e6;
+ size_t index = UNREASONABLY_HIGH_INDEX;
+ for (size_t i = 0; i < mControllers.size(); ++i)
+ {
+ if (id == mControllerIDs[i])
+ {
+ index = i;
+ break;
+ }
+ }
+ return index;
+}
+
+void LLGameControllerManager::onAxis(SDL_JoystickID id, U8 axis, S16 value)
+{
+ if (axis > MAX_AXIS)
+ {
+ return;
+ }
+ size_t index = getControllerIndex(id);
+ if (index < mControllers.size())
+ {
+ LL_DEBUGS("SDL2") << "joystick=0x" << std::hex << id << std::dec
+ << " axis=" << (S32)(axis)
+ << " value=" << (S32)(value) << LL_ENDL;
+ mStates[index].mAxes[axis] = value;
+ }
+}
+
+void LLGameControllerManager::onButton(SDL_JoystickID id, U8 button, bool pressed)
+{
+ size_t index = getControllerIndex(id);
+ if (index < mControllers.size())
+ {
+ if (mStates[index].onButton(button, pressed))
+ {
+ LL_DEBUGS("SDL2") << "joystick=0x" << std::hex << id << std::dec
+ << " button i=" << (S32)(button)
+ << " pressed=" << pressed << LL_ENDL;
+ }
+ }
+}
+
+void LLGameControllerManager::onKeyButton(U8 button, bool pressed)
+{
+ if (mKeyboardState.onButton(button, pressed))
+ {
+ LL_DEBUGS("SDL2") << " keyboard button i=" << (S32)(button) << " pressed=" << pressed << LL_ENDL;
+ }
+}
+
+void LLGameControllerManager::onKeyAxis(U8 axis, U16 value)
+{
+ if (mKeyboardState.mAxes[axis] != value)
+ {
+ mKeyboardState.mAxes[axis] = value;
+ LL_DEBUGS("SDL2") << " keyboard axis i=" << (S32)(axis) << " value=" << (S32)(value) << LL_ENDL;
+ }
+}
+
+void LLGameControllerManager::clearAllInput()
+{
+ for (auto& state : mStates)
+ {
+ state.mButtons = 0;
+ std::fill(state.mAxes.begin(), state.mAxes.end(), 0);
+ }
+ mKeyboardState.mButtons = 0;
+ std::fill(mKeyboardState.mAxes.begin(), mKeyboardState.mAxes.end(), 0);
+}
+
+void LLGameControllerManager::clearAllKeys()
+{
+ mKeyboardState.mButtons = 0;
+ std::fill(mKeyboardState.mAxes.begin(), mKeyboardState.mAxes.end(), 0);
+}
+
+void LLGameControllerManager::computeFinalState(LLGameControl::State& state)
+{
+ // clear the slate
+ std::vector<S32> axes_accumulator;
+ axes_accumulator.resize(NUM_AXES, 0);
+ U32 old_buttons = state.mButtons;
+ state.mButtons = 0;
+
+ // accumulate the controllers
+ for (const auto& s : mStates)
+ {
+ state.mButtons |= s.mButtons;
+ for (size_t i = 0; i < NUM_AXES; ++i)
+ {
+ axes_accumulator[i] += (S32)(s.mAxes[i]);
+ }
+ }
+
+ // accumulate the keyboard
+ state.mButtons |= mKeyboardState.mButtons;
+ for (size_t i = 0; i < NUM_AXES; ++i)
+ {
+ axes_accumulator[i] += (S32)(mKeyboardState.mAxes[i]);
+ }
+ if (old_buttons != state.mButtons)
+ {
+ g_nextResendPeriod = 0; // packet needs to go out ASAP
+ }
+
+ // clamp the axes
+ for (size_t i = 0; i < NUM_AXES; ++i)
+ {
+ S32 new_axis = (S16)(std::min(std::max(axes_accumulator[i], -32768), 32767));
+ // check for change
+ if (state.mAxes[i] != new_axis)
+ {
+ // When axis changes we explicitly update the corresponding prevAxis
+ // otherwise, we let prevAxis get updated in updateResendPeriod()
+ // which is explicitly called after a packet is sent. This allows
+ // unchanged axes to be included in first resend but not later ones.
+ state.mPrevAxes[i] = state.mAxes[i];
+ state.mAxes[i] = new_axis;
+ g_nextResendPeriod = 0; // packet needs to go out ASAP
+ }
+ }
+}
+
+void LLGameControllerManager::clear()
+{
+ mControllerIDs.clear();
+ mControllers.clear();
+ mStates.clear();
+}
+
+
+U64 get_now_nsec()
+{
+ std::chrono::time_point<std::chrono::steady_clock> t0;
+ return (std::chrono::steady_clock::now() - t0).count();
+}
+
+// util for dumping SDL_GameController info
+std::ostream& operator<<(std::ostream& out, SDL_GameController* c)
+{
+ if (! c)
+ {
+ return out << "nullptr";
+ }
+ out << "{";
+ out << " name='" << SDL_GameControllerName(c) << "'";
+ out << " type='" << SDL_GameControllerGetType(c) << "'";
+ out << " vendor='" << SDL_GameControllerGetVendor(c) << "'";
+ out << " product='" << SDL_GameControllerGetProduct(c) << "'";
+ out << " version='" << SDL_GameControllerGetProductVersion(c) << "'";
+ //CRASH! out << " serial='" << SDL_GameControllerGetSerial(c) << "'";
+ out << " }";
+ return out;
+}
+
+// util for dumping SDL_Joystick info
+std::ostream& operator<<(std::ostream& out, SDL_Joystick* j)
+{
+ if (! j)
+ {
+ return out << "nullptr";
+ }
+ out << "{";
+ out << " p=0x" << (void*)(j);
+ out << " name='" << SDL_JoystickName(j) << "'";
+ out << " type='" << SDL_JoystickGetType(j) << "'";
+ out << " instance='" << SDL_JoystickInstanceID(j) << "'";
+ out << " product='" << SDL_JoystickGetProduct(j) << "'";
+ out << " version='" << SDL_JoystickGetProductVersion(j) << "'";
+ out << " num_axes=" << SDL_JoystickNumAxes(j);
+ out << " num_balls=" << SDL_JoystickNumBalls(j);
+ out << " num_hats=" << SDL_JoystickNumHats(j);
+ out << " num_buttons=" << SDL_JoystickNumHats(j);
+ out << " }";
+ return out;
+}
+
+void onControllerDeviceAdded(const SDL_Event& event)
+{
+ int device_index = event.cdevice.which;
+ SDL_JoystickID id = SDL_JoystickGetDeviceInstanceID(device_index);
+ SDL_GameController* controller = SDL_GameControllerOpen(device_index);
+
+ g_manager.addController(id, controller);
+}
+
+void onControllerDeviceRemoved(const SDL_Event& event)
+{
+ SDL_JoystickID id = event.cdevice.which;
+ g_manager.removeController(id);
+}
+
+void onControllerButton(const SDL_Event& event)
+{
+ g_manager.onButton(event.cbutton.which, event.cbutton.button, event.cbutton.state == SDL_PRESSED);
+}
+
+void onControllerAxis(const SDL_Event& event)
+{
+ LL_DEBUGS("SDL2") << "joystick=0x" << std::hex << event.caxis.which << std::dec
+ << " axis=" << (S32)(event.caxis.axis)
+ << " value=" << (S32)(event.caxis.value) << LL_ENDL;
+ g_manager.onAxis(event.caxis.which, event.caxis.axis, event.caxis.value);
+}
+
+// static
+bool LLGameControl::isInitialized()
+{
+ return g_gameControl != nullptr;
+}
+
+void sdl_logger(void *userdata, int category, SDL_LogPriority priority, const char *message)
+{
+ LL_DEBUGS("SDL2") << "log='" << message << "'" << LL_ENDL;
+}
+
+// static
+void LLGameControl::init()
+{
+ if (!g_gameControl)
+ {
+ g_gameControl = LLGameControl::getInstance();
+ SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER);
+ SDL_LogSetOutputFunction(&sdl_logger, nullptr);
+ }
+}
+
+// static
+void LLGameControl::terminate()
+{
+ g_manager.clear();
+ SDL_Quit();
+}
+
+// static
+void LLGameControl::addKeyButtonMap(U16 key, U8 button)
+{
+ g_keyButtonMap[key] = button;
+}
+
+// static
+void LLGameControl::removeKeyButtonMap(U16 key)
+{
+ g_keyButtonMap.erase(key);
+}
+
+// static
+void LLGameControl::addKeyAxisMap(U16 key, U8 axis, bool positive)
+{
+ if (axis > MAX_AXIS)
+ {
+ return;
+ }
+ if (positive)
+ {
+ g_keyAxisMapPositive[key] = axis;
+ g_keyAxisMapNegative.erase(key);
+ }
+ else
+ {
+ g_keyAxisMapNegative[key] = axis;
+ g_keyAxisMapPositive.erase(key);
+ }
+}
+
+// static
+void LLGameControl::removeKeyAxisMap(U16 key)
+{
+ g_keyAxisMapPositive.erase(key);
+ g_keyAxisMapNegative.erase(key);
+}
+
+// static
+void LLGameControl::onKeyDown(U16 key, U32 mask)
+{
+ auto itr = g_keyButtonMap.find(key);
+ if (itr != g_keyButtonMap.end())
+ {
+ g_manager.onKeyButton(itr->second, true);
+ }
+ else
+ {
+ itr = g_keyAxisMapPositive.find(key);
+ if (itr != g_keyAxisMapPositive.end())
+ {
+ g_manager.onKeyAxis(itr->second, 32767);
+ }
+ else
+ {
+ itr = g_keyAxisMapNegative.find(key);
+ if (itr != g_keyAxisMapNegative.end())
+ {
+ g_manager.onKeyAxis(itr->second, -32768);
+ }
+ }
+ }
+}
+
+// static
+void LLGameControl::onKeyUp(U16 key, U32 mask)
+{
+ auto itr = g_keyButtonMap.find(key);
+ if (itr != g_keyButtonMap.end())
+ {
+ g_manager.onKeyButton(itr->second, true);
+ }
+ else
+ {
+ itr = g_keyAxisMapPositive.find(key);
+ if (itr != g_keyAxisMapPositive.end())
+ {
+ g_manager.onKeyAxis(itr->second, 0);
+ }
+ else
+ {
+ itr = g_keyAxisMapNegative.find(key);
+ if (itr != g_keyAxisMapNegative.end())
+ {
+ g_manager.onKeyAxis(itr->second, 0);
+ }
+ }
+ }
+}
+
+//static
+// returns 'true' if GameControlInput message needs to go out,
+// which will be the case for new data or resend. Call this right
+// before deciding to put a GameControlInput packet on the wire
+// or not.
+bool LLGameControl::computeFinalInputAndCheckForChanges()
+{
+ g_manager.computeFinalState(g_gameControlState);
+ return g_lastSend + g_nextResendPeriod < get_now_nsec();
+}
+
+// static
+void LLGameControl::clearAllInput()
+{
+ g_manager.clearAllInput();
+}
+
+// static
+void LLGameControl::clearAllKeys()
+{
+ g_manager.clearAllKeys();
+}
+
+// static
+void LLGameControl::processEvents(bool app_has_focus)
+{
+ SDL_Event event;
+ if (!app_has_focus)
+ {
+ // when SL window lacks focus: pump SDL events but ignore them
+ while (g_gameControl && SDL_PollEvent(&event))
+ {
+ // do nothing: SDL_PollEvent() is the operator
+ }
+ clearAllInput();
+ return;
+ }
+
+ while (g_gameControl && SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_CONTROLLERDEVICEADDED:
+ onControllerDeviceAdded(event);
+ break;
+ case SDL_CONTROLLERDEVICEREMOVED:
+ onControllerDeviceRemoved(event);
+ break;
+ case SDL_CONTROLLERBUTTONDOWN:
+ /* FALLTHROUGH */
+ case SDL_CONTROLLERBUTTONUP:
+ onControllerButton(event);
+ break;
+ case SDL_CONTROLLERAXISMOTION:
+ onControllerAxis(event);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+// static
+const LLGameControl::State& LLGameControl::getState()
+{
+ return g_gameControlState;
+}
+
+// static
+void LLGameControl::setIncludeKeyboardButtons(bool include)
+{
+ g_includeKeyboardButtons = include;
+}
+
+// static
+bool LLGameControl::getIncludeKeyboardButtons()
+{
+ return g_includeKeyboardButtons;
+}
+
+//static
+void LLGameControl::updateResendPeriod()
+{
+ // we expect this method to be called right after data is sent
+ g_lastSend = get_now_nsec();
+ if (g_nextResendPeriod == 0)
+ {
+ g_nextResendPeriod = FIRST_RESEND_PERIOD;
+ }
+ else
+ {
+ // Reset mPrevAxes only on second resend or higher
+ // because when the joysticks are being used we expect a steady stream
+ // of recorrection data rather than sparse changes.
+ //
+ // In other words: we want to include changed axes in the first resend
+ // so we only overrite g_gameControlState.mPrevAxes on higher resends.
+ g_gameControlState.mPrevAxes = g_gameControlState.mAxes;
+ g_nextResendPeriod *= RESEND_EXPANSION_RATE;
+ }
+}
+
diff --git a/indra/llwindow/llgamecontrol.h b/indra/llwindow/llgamecontrol.h
new file mode 100644
index 0000000000..fe6d6f0138
--- /dev/null
+++ b/indra/llwindow/llgamecontrol.h
@@ -0,0 +1,86 @@
+/**
+ * @file llgamecontrol.h
+ * @brief GameController detection and management
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include <vector>
+
+
+#include "llerror.h"
+#include "llsingleton.h"
+#include "stdtypes.h"
+
+
+// LLGameControl is a singleton with pure static public interface
+class LLGameControl : public LLSingleton<LLGameControl>
+{
+ LLSINGLETON_EMPTY_CTOR(LLGameControl);
+ virtual ~LLGameControl();
+ LOG_CLASS(LLGameControl);
+
+public:
+ // State is a minimal class for storing axes and buttons values
+ class State
+ {
+ public:
+ State();
+ bool onButton(U8 button, bool pressed);
+ std::vector<S16> mAxes; // [ -32768, 32767 ]
+ std::vector<S16> mPrevAxes; // value in last outgoing packet
+ U32 mButtons;
+ };
+
+ static bool isInitialized();
+ static void init();
+ static void terminate();
+
+ static void addKeyButtonMap(U16 key, U8 button);
+ static void removeKeyButtonMap(U16 key);
+ static void addKeyAxisMap(U16 key, U8 axis, bool positive);
+ static void removeKeyAxisMap(U16 key);
+
+ static void onKeyDown(U16 key, U32 mask);
+ static void onKeyUp(U16 key, U32 mask);
+
+ // returns 'true' if GameControlInput message needs to go out,
+ // which will be the case for new data or resend. Call this right
+ // before deciding to put a GameControlInput packet on the wire
+ // or not.
+ static bool computeFinalInputAndCheckForChanges();
+
+ static void clearAllInput();
+ static void clearAllKeys();
+
+ static void processEvents(bool app_has_focus = true);
+ static const State& getState();
+
+ static void setIncludeKeyboardButtons(bool include);
+ static bool getIncludeKeyboardButtons();
+
+ // call this after putting a GameControlInput packet on the wire
+ static void updateResendPeriod();
+};
+
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index a16c0a318a..a858d3b16f 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -29,6 +29,7 @@
#include "llkeyboard.h"
#include "llwindowcallbacks.h"
+#include "llgamecontrol.h"
//
// Globals
@@ -161,6 +162,7 @@ void LLKeyboard::resetKeyDownAndHandle()
mCallbacks->handleTranslatedKeyUp(i, mask);
}
}
+ LLGameControl::clearAllKeys();
}
// BUG this has to be called when an OS dialog is shown, otherwise modifier key state
@@ -275,6 +277,43 @@ bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask)
return handled;
}
+bool LLKeyboard::handleKeyDown(const U16 key, const U32 mask)
+{
+ U32 translated_mask = updateModifiers(mask);
+
+ KEY translated_key = 0;
+ bool handled = false;
+ if(translateKey(key, &translated_key))
+ {
+ handled = handleTranslatedKeyDown(translated_key, translated_mask);
+ }
+ if (!handled)
+ {
+ LLGameControl::onKeyDown(translated_key, translated_mask);
+ }
+
+ return handled;
+}
+
+
+bool LLKeyboard::handleKeyUp(const U16 key, const U32 mask)
+{
+ U32 translated_mask = updateModifiers(mask);
+
+ KEY translated_key = 0;
+ bool handled = false;
+ if(translateKey(key, &translated_key))
+ {
+ handled = handleTranslatedKeyUp(translated_key, translated_mask);
+ }
+ if (!handled)
+ {
+ LLGameControl::onKeyUp(translated_key, translated_mask);
+ }
+
+ return handled;
+}
+
void LLKeyboard::toggleInsertMode()
{
diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h
index 439abaf25b..cc31b99d3f 100644
--- a/indra/llwindow/llkeyboardheadless.h
+++ b/indra/llwindow/llkeyboardheadless.h
@@ -33,20 +33,15 @@ class LLKeyboardHeadless : public LLKeyboard
{
public:
LLKeyboardHeadless();
- /*virtual*/ ~LLKeyboardHeadless() {};
+ ~LLKeyboardHeadless() {};
-#ifndef LL_SDL
- /*virtual*/ bool handleKeyUp(const U16 key, MASK mask) { return false; }
- /*virtual*/ bool handleKeyDown(const U16 key, MASK mask) { return false; }
-#else
- /*virtual*/ bool handleKeyUp(const U32 key, MASK mask) { return false; }
- /*virtual*/ bool handleKeyDown(const U32 key, MASK mask) { return false; }
-#endif
- /*virtual*/ void resetMaskKeys();
- /*virtual*/ MASK currentMask(bool for_mouse_event);
- /*virtual*/ void scanKeyboard();
+ bool handleKeyUp(const U16 key, MASK mask) override;
+ bool handleKeyDown(const U16 key, MASK mask) override;
+ void resetMaskKeys() override;
+ MASK currentMask(bool for_mouse_event) override;
+ void scanKeyboard() override;
#ifdef LL_DARWIN
- /*virtual*/ void handleModifier(MASK mask);
+ void handleModifier(MASK mask) override;
#endif
};
diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp
index 89ff7c6d3f..f590b8db8b 100644
--- a/indra/llwindow/llkeyboardmacosx.cpp
+++ b/indra/llwindow/llkeyboardmacosx.cpp
@@ -203,7 +203,7 @@ void LLKeyboardMacOSX::handleModifier(MASK mask)
updateModifiers(mask);
}
-MASK LLKeyboardMacOSX::updateModifiers(const U32 mask)
+MASK LLKeyboardMacOSX::updateModifiers(U32 mask)
{
// translate the mask
MASK out_mask = 0;
diff --git a/indra/llwindow/llkeyboardmacosx.h b/indra/llwindow/llkeyboardmacosx.h
index 92ab5c9a85..af8a626db8 100644
--- a/indra/llwindow/llkeyboardmacosx.h
+++ b/indra/llwindow/llkeyboardmacosx.h
@@ -42,14 +42,14 @@ class LLKeyboardMacOSX : public LLKeyboard
{
public:
LLKeyboardMacOSX();
- /*virtual*/ ~LLKeyboardMacOSX() {};
+ ~LLKeyboardMacOSX() {};
- /*virtual*/ bool handleKeyUp(const U16 key, MASK mask);
- /*virtual*/ bool handleKeyDown(const U16 key, MASK mask);
- /*virtual*/ void resetMaskKeys();
- /*virtual*/ MASK currentMask(bool for_mouse_event);
- /*virtual*/ void scanKeyboard();
- /*virtual*/ void handleModifier(MASK mask);
+ bool handleKeyUp(const U16 key, MASK mask) override;
+ bool handleKeyDown(const U16 key, MASK mask) override;
+ void resetMaskKeys() override;
+ MASK currentMask(bool for_mouse_event) override;
+ void scanKeyboard() override;
+ void handleModifier(MASK mask) override;
protected:
MASK updateModifiers(const U32 mask);
diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp
index 8d6b8d9b93..7ef616a8b7 100644
--- a/indra/llwindow/llkeyboardwin32.cpp
+++ b/indra/llwindow/llkeyboardwin32.cpp
@@ -182,7 +182,7 @@ void LLKeyboardWin32::resetMaskKeys()
//}
-MASK LLKeyboardWin32::updateModifiers()
+MASK LLKeyboardWin32::updateModifiers(U32 mask)
{
//RN: this seems redundant, as we should have already received the appropriate
// messages for the modifier keys
@@ -321,4 +321,4 @@ U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key)
return inverseTranslateKey(converted_key);
}
-#endif
+#endif // LL_WINDOWS
diff --git a/indra/llwindow/llkeyboardwin32.h b/indra/llwindow/llkeyboardwin32.h
index d0dfc5cfdd..d3dc65d9aa 100644
--- a/indra/llwindow/llkeyboardwin32.h
+++ b/indra/llwindow/llkeyboardwin32.h
@@ -37,15 +37,16 @@ class LLKeyboardWin32 : public LLKeyboard
{
public:
LLKeyboardWin32();
- /*virtual*/ ~LLKeyboardWin32() {};
-
- /*virtual*/ bool handleKeyUp(const U16 key, MASK mask);
- /*virtual*/ bool handleKeyDown(const U16 key, MASK mask);
- /*virtual*/ void resetMaskKeys();
- /*virtual*/ MASK currentMask(bool for_mouse_event);
- /*virtual*/ void scanKeyboard();
- bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key);
- U16 inverseTranslateExtendedKey(const KEY translated_key);
+ ~LLKeyboardWin32() {};
+
+ bool handleKeyUp(const U16 key, MASK mask) override;
+ bool handleKeyDown(const U16 key, MASK mask) override;
+ void resetMaskKeys() override;
+ MASK currentMask(bool for_mouse_event) override;
+ void scanKeyboard() override;
+
+ bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key);
+ U16 inverseTranslateExtendedKey(const KEY translated_key);
protected:
MASK updateModifiers();
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 4016f420e8..a4b7a65cb2 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -27,14 +27,14 @@
#include "linden_common.h"
#include "llwindowheadless.h"
-#if LL_MESA_HEADLESS
-#include "llwindowmesaheadless.h"
-#elif LL_SDL
-#include "llwindowsdl.h"
-#elif LL_WINDOWS
+#if LL_WINDOWS
#include "llwindowwin32.h"
#elif LL_DARWIN
#include "llwindowmacosx.h"
+#elif LL_MESA_HEADLESS
+#include "llwindowmesaheadless.h"
+#elif LL_LINUX
+#include "llwindowsdl.h"
#endif
#include "llerror.h"
@@ -72,13 +72,13 @@ S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type)
S32 result = 0;
LL_WARNS() << "OSMessageBox: " << text << LL_ENDL;
-#if LL_MESA_HEADLESS // !!! *FIX: (?)
- return OSBTN_OK;
-#elif LL_WINDOWS
+#if LL_WINDOWS
result = OSMessageBoxWin32(text, caption, type);
#elif LL_DARWIN
result = OSMessageBoxMacOSX(text, caption, type);
-#elif LL_SDL
+#elif LL_MESA_HEADLESS // !!! *FIX: (?)
+ return OSBTN_OK;
+#elif LL_LINUX
result = OSMessageBoxSDL(text, caption, type);
#else
#error("OSMessageBox not implemented for this platform!")
@@ -263,7 +263,7 @@ std::vector<std::string> LLWindow::getDynamicFallbackFontList()
return LLWindowWin32::getDynamicFallbackFontList();
#elif LL_DARWIN
return LLWindowMacOSX::getDynamicFallbackFontList();
-#elif LL_SDL
+#elif LL_LINUX
return LLWindowSDL::getDynamicFallbackFontList();
#else
return std::vector<std::string>();
@@ -342,12 +342,12 @@ bool LLSplashScreen::isVisible()
// static
LLSplashScreen *LLSplashScreen::create()
{
-#if LL_MESA_HEADLESS || LL_SDL // !!! *FIX: (?)
- return 0;
-#elif LL_WINDOWS
+#if LL_WINDOWS
return new LLSplashScreenWin32;
#elif LL_DARWIN
return new LLSplashScreenMacOSX;
+#elif LL_MESA_HEADLESS || LL_LINUX // !!! *FIX: (?)
+ return 0;
#else
#error("LLSplashScreen not implemented on this platform!")
#endif
@@ -415,22 +415,22 @@ LLWindow* LLWindowManager::createWindow(
if (use_gl)
{
-#if LL_MESA_HEADLESS
- new_window = new LLWindowMesaHeadless(callbacks,
- title, name, x, y, width, height, flags,
- fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth);
-#elif LL_SDL
- new_window = new LLWindowSDL(callbacks,
- title, name, x, y, width, height, flags,
- fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
-#elif LL_WINDOWS
+#if LL_WINDOWS
new_window = new LLWindowWin32(callbacks,
title, name, x, y, width, height, flags,
- fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_gl_version);
+ fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_vram, max_gl_version);
#elif LL_DARWIN
new_window = new LLWindowMacOSX(callbacks,
title, name, x, y, width, height, flags,
fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+#elif LL_MESA_HEADLESS
+ new_window = new LLWindowMesaHeadless(callbacks,
+ title, name, x, y, width, height, flags,
+ fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth);
+#elif LL_LINUX
+ new_window = new LLWindowSDL(callbacks,
+ title, name, x, y, width, height, flags,
+ fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
#endif
}
else
diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h
index 7ad30d41ce..609d8a6f49 100644
--- a/indra/llwindow/llwindowsdl.h
+++ b/indra/llwindow/llwindowsdl.h
@@ -29,6 +29,7 @@
// Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class
+#if LL_LINUX
#include "llwindow.h"
#include "lltimer.h"
@@ -300,4 +301,5 @@ public:
S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type);
+#endif //LL_LINUX
#endif //LL_LLWINDOWSDL_H