diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e8b4cc8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,101 @@ +cmake_minimum_required(VERSION 3.0) +project(libBoo) + +if (NOT MSVC) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() + +if(WIN32) + list(APPEND PLAT_SRCS + lib/win/ApplicationWin32.cpp + lib/win/WindowWin32.cpp + lib/win/GraphicsContextWin32.cpp + lib/inputdev/HIDListenerWinUSB.cpp + lib/inputdev/HIDDeviceWinUSB.cpp) +elseif(APPLE) + list(APPEND PLAT_SRCS + lib/mac/ApplicationCocoa.mm + lib/mac/WindowCocoa.mm + lib/mac/GLViewCocoa.mm + lib/mac/GraphicsContextCocoa.cpp + lib/inputdev/HIDListenerIOKit.cpp + lib/inputdev/HIDDeviceIOKit.cpp) +else() + list(APPEND PLAT_SRCS + lib/x11/ApplicationUnix.cpp + lib/x11/ApplicationXCB.hpp + lib/x11/ApplicationWayland.hpp + lib/x11/WindowXCB.cpp + lib/x11/WindowWayland.cpp + lib/x11/GraphicsContextXCB.cpp + lib/x11/GraphicsContextWayland.cpp + lib/inputdev/HIDListenerUdev.cpp + lib/inputdev/HIDDeviceUdev.cpp) + + find_package(PkgConfig) + if(PKG_CONFIG_FOUND) + pkg_check_modules(dbus_pkg QUIET libdbus dbus-1) + endif() + + find_path(DBUS_INCLUDE_DIR + NAMES + dbus/dbus.h + HINTS + ${dbus_pkg_INCLUDE_DIRS} + PATH_SUFFIXES + include/ + include/dbus-1.0/ + dbus-1.0/) + + find_path(DBUS_ARCH_INCLUDE_DIR + NAMES + dbus/dbus-arch-deps.h + HINTS + ${dbus_pkg_INCLUDE_DIRS} + PATHS + # TODO use CMAKE_SYSTEM_PROCESSOR or similar? + /usr/lib/dbus-1.0/include + PATH_SUFFIXES + dbus-1.0/include/) + + find_library(DBUS_LIBRARY + NAMES + dbus dbus-1 + HINTS + ${dbus_pkg_LIBRARY_DIRS} + PATH_SUFFIXES + lib + lib32 + lib64) + + if(DBUS_INCLUDE_DIR-NOTFOUND) + message(FATAL_ERROR "Unix build of libBoo requires dbus") + endif() + + include_directories(${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR}) + list(APPEND BOO_SYS_LIBS xcb xcb-glx xcb-xinput xcb-xkb xcb-keysyms xkbcommon xkbcommon-x11 ${DBUS_LIBRARY} udev pthread) + +endif() + +set(BOO_SYS_LIBS ${BOO_SYS_LIBS} CACHE PATH "Boo System Libraries" FORCE) + +include_directories(include) + +add_library(Boo + lib/inputdev/CafeProPad.cpp include/boo/inputdev/CafeProPad.hpp + lib/inputdev/RevolutionPad.cpp include/boo/inputdev/RevolutionPad.hpp + lib/inputdev/DolphinSmashAdapter.cpp include/boo/inputdev/DolphinSmashAdapter.hpp + lib/inputdev/DualshockPad.cpp include/boo/inputdev/DualshockPad.hpp + lib/inputdev/GenericPad.cpp include/boo/inputdev/GenericPad.hpp + lib/inputdev/DeviceBase.cpp include/boo/inputdev/DeviceBase.hpp + lib/inputdev/DeviceSignature.cpp include/boo/inputdev/DeviceSignature.hpp + include/boo/inputdev/IHIDListener.hpp + lib/inputdev/IHIDDevice.hpp + include/boo/IGraphicsContext.hpp + include/boo/IWindow.hpp + include/boo/IApplication.hpp + include/boo/boo.hpp + InputDeviceClasses.cpp + ${PLAT_SRCS}) + +add_subdirectory(test) diff --git a/InputDeviceClasses.cpp b/InputDeviceClasses.cpp index fb9a10c..420468f 100644 --- a/InputDeviceClasses.cpp +++ b/InputDeviceClasses.cpp @@ -1,14 +1,14 @@ -#include "inputdev/SDeviceSignature.hpp" -#include "inputdev/CDolphinSmashAdapter.hpp" -#include "inputdev/CDualshockPad.hpp" +#include "boo/inputdev/DeviceSignature.hpp" +#include "boo/inputdev/DolphinSmashAdapter.hpp" +#include "boo/inputdev/DualshockPad.hpp" namespace boo { -const SDeviceSignature BOO_DEVICE_SIGS[] = +const DeviceSignature BOO_DEVICE_SIGS[] = { - DEVICE_SIG(CDolphinSmashAdapter, 0x57e, 0x337), - DEVICE_SIG(CDualshockController, 0x54c, 0x268), + DEVICE_SIG(DolphinSmashAdapter, 0x57e, 0x337), + DEVICE_SIG(DualshockPad, 0x54c, 0x268), DEVICE_SIG_SENTINEL() }; diff --git a/include/CInputDeferredRelay.hpp b/include/CInputDeferredRelay.hpp deleted file mode 100644 index 524261c..0000000 --- a/include/CInputDeferredRelay.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CINPUTDEFERREDRELAY_HPP -#define CINPUTDEFERREDRELAY_HPP - -#include "IInputWaiter.hpp" - -namespace boo -{ - -} - -#endif // CINPUTDEFERREDRELAY_HPP diff --git a/include/CInputRelay.hpp b/include/CInputRelay.hpp deleted file mode 100644 index 03eacbe..0000000 --- a/include/CInputRelay.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CINPUTRELAY_HPP -#define CINPUTRELAY_HPP - -#include "IInputWaiter.hpp" - -namespace boo -{ - -class CInputRelay : IInputWaiter -{ - -}; - -} - -#endif // CINPUTRELAY_HPP diff --git a/include/CQtOpenGLWindow.hpp b/include/CQtOpenGLWindow.hpp deleted file mode 100644 index 650513c..0000000 --- a/include/CQtOpenGLWindow.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef CQTOPENGLWINDOW_HPP -#define CQTOPENGLWINDOW_HPP - -#include -#include -#include - -class CQtOpenGLWindow : public QWindow, ISurface -{ - Q_OBJECT -public: - explicit CQtOpenGLWindow(QWindow *parent = 0); - CQtOpenGLWindow(); - - virtual void render(); - - virtual void initialize(); - - - public slots: - void renderLater(); - void renderNow(); - -protected: - bool event(QEvent *event) Q_DECL_OVERRIDE; - - void exposeEvent(QExposeEvent *event) Q_DECL_OVERRIDE; - -private: - bool m_update_pending; - bool m_animating; - - QOpenGLContext *m_context; -}; - -#endif // CQTOPENGLWINDOW_HPP diff --git a/include/CSurface.hpp b/include/CSurface.hpp deleted file mode 100644 index a1916a8..0000000 --- a/include/CSurface.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef CSURFACE_HPP -#define CSURFACE_HPP - -#include "ISurface.hpp" - -namespace boo -{ - -ISurface* CSurfaceNewWindow(); -ISurface* CSurfaceNewQWidget(); - -} - -#endif // CSURFACE_HPP diff --git a/include/IGraphicsContext.hpp b/include/IGraphicsContext.hpp deleted file mode 100644 index 6764d3c..0000000 --- a/include/IGraphicsContext.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef IGRAPHICSCONTEXT_HPP -#define IGRAPHICSCONTEXT_HPP - -#include - -namespace boo -{ - -class IGraphicsContext -{ -public: - virtual ~IGraphicsContext() {} - - virtual void setMinVersion (const int& min)=0; - virtual void setMajorVersion(const int& maj)=0; - virtual bool create()=0; - virtual const std::string version() const=0; - virtual const std::string name() const=0; - virtual int depthSize() const=0; - virtual int redDepth() const=0; - virtual int greenDepth() const=0; - virtual int blueDepth() const=0; -}; - -} - -#endif // IGRAPHICSCONTEXT_HPP diff --git a/include/IInputWaiter.hpp b/include/IInputWaiter.hpp deleted file mode 100644 index 552a2d8..0000000 --- a/include/IInputWaiter.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef IINPUTWAITER_HPP -#define IINPUTWAITER_HPP - -namespace boo -{ - -class IInputWaiter -{ - -}; - -} - -#endif // IINPUTWAITER_HPP diff --git a/include/IRetraceWaiter.hpp b/include/IRetraceWaiter.hpp deleted file mode 100644 index aacd34f..0000000 --- a/include/IRetraceWaiter.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef IRETRACEWAITER_HPP -#define IRETRACEWAITER_HPP - -namespace boo -{ - -class IRetraceWaiter -{ - -}; - -} - -#endif // IRETRACEWAITER_HPP diff --git a/include/ISurface.hpp b/include/ISurface.hpp deleted file mode 100644 index 6f2f13d..0000000 --- a/include/ISurface.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ISURFACE_HPP -#define ISURFACE_HPP - -namespace boo -{ - -class ISurface -{ -public: - -}; - -} - -#endif // CSURFACE_HPP diff --git a/include/boo.hpp b/include/boo.hpp deleted file mode 100644 index 626f5d7..0000000 --- a/include/boo.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef BOO_HPP -#define BOO_HPP - -#if defined(_WIN32) -#include "win/CWGLContext.hpp" -namespace boo {typedef CWGLContext CGraphicsContext;} - -#elif defined(__APPLE__) -#include "mac/CCGLContext.hpp" -namespace boo {typedef CCGLContext CGraphicsContext;} - -#elif defined(__GNUC__) || defined(__clang__) -#include "x11/CGLXContext.hpp" -namespace boo {typedef CGLXContext CGraphicsContext;} - -#endif - -#include "IGraphicsContext.hpp" -#include "inputdev/CDeviceFinder.hpp" -#include "inputdev/CDolphinSmashAdapter.hpp" -#include "inputdev/CDualshockPad.hpp" - -#endif // BOO_HPP diff --git a/include/boo/IApplication.hpp b/include/boo/IApplication.hpp new file mode 100644 index 0000000..fc88800 --- /dev/null +++ b/include/boo/IApplication.hpp @@ -0,0 +1,87 @@ +#ifndef IRUNLOOP_HPP +#define IRUNLOOP_HPP + +#include +#include +#include + +#include "IWindow.hpp" +#include "inputdev/DeviceFinder.hpp" + +namespace boo +{ +class IApplication; + +struct IApplicationCallback +{ + virtual void appLaunched(IApplication* app) {(void)app;} + virtual void appQuitting(IApplication* app) {(void)app;} + virtual void appFilesOpen(IApplication* app, const std::vector& paths) {(void)app;(void)paths;} +}; + +class IApplication +{ + friend class WindowCocoa; + friend class WindowWayland; + friend class WindowXCB; + friend class WindowWin32; + virtual void _deletedWindow(IWindow* window)=0; +public: + virtual ~IApplication() {} + + enum EPlatformType + { + PLAT_AUTO = 0, + PLAT_WAYLAND = 1, + PLAT_XCB = 2, + PLAT_ANDROID = 3, + PLAT_COCOA = 4, + PLAT_COCOA_TOUCH = 5, + PLAT_WIN32 = 6, + PLAT_WINRT = 7, + PLAT_REVOLUTION = 8, + PLAT_CAFE = 9 + }; + virtual EPlatformType getPlatformType() const=0; + + virtual void run()=0; + virtual void quit()=0; + virtual const std::string& getUniqueName() const=0; + virtual const std::string& getFriendlyName() const=0; + virtual const std::string& getProcessName() const=0; + virtual const std::vector& getArgs() const=0; + + /* Constructors/initializers for sub-objects */ + virtual IWindow* newWindow(const std::string& title)=0; + +}; + +std::unique_ptr +ApplicationBootstrap(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const std::string& uniqueName, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args, + bool singleInstance=true); +extern IApplication* APP; + +static inline std::unique_ptr +ApplicationBootstrap(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const std::string& uniqueName, + const std::string& friendlyName, + int argc, const char** argv, + bool singleInstance=true) +{ + if (APP) + return std::unique_ptr(); + std::vector args; + for (int i=1 ; i + +namespace boo +{ + +class IWindowCallback +{ +public: + enum EMouseButton + { + BUTTON_NONE = 0, + BUTTON_PRIMARY = 1, + BUTTON_SECONDARY = 2, + BUTTON_MIDDLE = 3, + BUTTON_AUX1 = 4, + BUTTON_AUX2 = 5 + }; + + struct SWindowCoord + { + unsigned pixel[2]; + unsigned virtualPixel[2]; + float norm[2]; + }; + + struct STouchCoord + { + double coord[2]; + }; + + struct SScrollDelta + { + double delta[2]; + bool isFine; /* Use system-scale fine-scroll (for scrollable-trackpads) */ + }; + + enum ESpecialKey + { + KEY_NONE = 0, + KEY_F1 = 1, + KEY_F2 = 2, + KEY_F3 = 3, + KEY_F4 = 4, + KEY_F5 = 5, + KEY_F6 = 6, + KEY_F7 = 7, + KEY_F8 = 8, + KEY_F9 = 9, + KEY_F10 = 10, + KEY_F11 = 11, + KEY_F12 = 12, + KEY_ESC = 13, + KEY_ENTER = 14, + KEY_BACKSPACE = 15, + KEY_INSERT = 16, + KEY_DELETE = 17, + KEY_HOME = 18, + KEY_END = 19, + KEY_PGUP = 20, + KEY_PGDOWN = 21, + KEY_LEFT = 22, + KEY_RIGHT = 23, + KEY_UP = 24, + KEY_DOWN = 25 + }; + + enum EModifierKey + { + MKEY_NONE = 0, + MKEY_CTRL = 1<<0, + MKEY_ALT = 1<<2, + MKEY_SHIFT = 1<<3, + MKEY_COMMAND = 1<<4 + }; + + virtual void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + {(void)coord;(void)button;(void)mods;} + virtual void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + {(void)coord;(void)button;(void)mods;} + virtual void mouseMove(const SWindowCoord& coord) + {(void)coord;} + virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) + {(void)coord;(void)scroll;} + + virtual void touchDown(const STouchCoord& coord, uintptr_t tid) + {(void)coord;(void)tid;} + virtual void touchUp(const STouchCoord& coord, uintptr_t tid) + {(void)coord;(void)tid;} + virtual void touchMove(const STouchCoord& coord, uintptr_t tid) + {(void)coord;(void)tid;} + + virtual void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) + {(void)charCode;(void)mods;(void)isRepeat;} + virtual void charKeyUp(unsigned long charCode, EModifierKey mods) + {(void)charCode;(void)mods;} + virtual void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) + {(void)key;(void)mods;(void)isRepeat;} + virtual void specialKeyUp(ESpecialKey key, EModifierKey mods) + {(void)key;(void)mods;} + virtual void modKeyDown(EModifierKey mod, bool isRepeat) + {(void)mod;(void)isRepeat;} + virtual void modKeyUp(EModifierKey mod) {(void)mod;} + +}; + +class IWindow +{ +public: + + virtual ~IWindow() {} + + virtual void setCallback(IWindowCallback* cb)=0; + + virtual void showWindow()=0; + virtual void hideWindow()=0; + + virtual std::string getTitle()=0; + virtual void setTitle(const std::string& title)=0; + + virtual void setWindowFrameDefault()=0; + virtual void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const=0; + virtual void setWindowFrame(float x, float y, float w, float h)=0; + virtual float getVirtualPixelFactor() const=0; + + virtual bool isFullscreen() const=0; + virtual void setFullscreen(bool fs)=0; + + virtual uintptr_t getPlatformHandle() const=0; + virtual void _incomingEvent(void* event) {(void)event;} + + enum ETouchType + { + TOUCH_NONE = 0, + TOUCH_DISPLAY = 1, + TOUCH_TRACKPAD = 2 + }; + virtual ETouchType getTouchType() const=0; + +}; + +} + +#endif // IWINDOW_HPP diff --git a/include/boo/boo.hpp b/include/boo/boo.hpp new file mode 100644 index 0000000..cd245a1 --- /dev/null +++ b/include/boo/boo.hpp @@ -0,0 +1,10 @@ +#ifndef BOO_HPP +#define BOO_HPP + +#include "IApplication.hpp" +#include "IWindow.hpp" +#include "inputdev/DeviceFinder.hpp" +#include "inputdev/DolphinSmashAdapter.hpp" +#include "inputdev/DualshockPad.hpp" + +#endif // BOO_HPP diff --git a/include/inputdev/CCafeProPad.hpp b/include/boo/inputdev/CafeProPad.hpp similarity index 100% rename from include/inputdev/CCafeProPad.hpp rename to include/boo/inputdev/CafeProPad.hpp diff --git a/include/inputdev/CDeviceBase.hpp b/include/boo/inputdev/DeviceBase.hpp similarity index 61% rename from include/inputdev/CDeviceBase.hpp rename to include/boo/inputdev/DeviceBase.hpp index fe81c69..75431c3 100644 --- a/include/inputdev/CDeviceBase.hpp +++ b/include/boo/inputdev/DeviceBase.hpp @@ -8,27 +8,27 @@ namespace boo { -class CDeviceBase +class DeviceBase { - friend class CDeviceToken; - friend class CHIDDeviceIOKit; - friend class CHIDDeviceUdev; - friend class CHIDDeviceWinUSB; + friend class DeviceToken; + friend class HIDDeviceIOKit; + friend class HIDDeviceUdev; + friend class HIDDeviceWinUSB; - class CDeviceToken* m_token; + class DeviceToken* m_token; class IHIDDevice* m_hidDev; void _deviceDisconnected(); public: - CDeviceBase(CDeviceToken* token); - virtual ~CDeviceBase(); + DeviceBase(DeviceToken* token); + virtual ~DeviceBase(); void closeDevice(); virtual void deviceDisconnected()=0; virtual void deviceError(const char* error, ...); /* Low-Level API */ - bool sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length); - size_t receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length); + bool sendUSBInterruptTransfer(const uint8_t* data, size_t length); + size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length); virtual void initialCycle() {} virtual void transferCycle() {} virtual void finalCycle() {} diff --git a/include/inputdev/CDeviceFinder.hpp b/include/boo/inputdev/DeviceFinder.hpp similarity index 77% rename from include/inputdev/CDeviceFinder.hpp rename to include/boo/inputdev/DeviceFinder.hpp index ec68a78..e114fb1 100644 --- a/include/inputdev/CDeviceFinder.hpp +++ b/include/boo/inputdev/DeviceFinder.hpp @@ -1,13 +1,14 @@ #ifndef CDEVICEFINDER_HPP #define CDEVICEFINDER_HPP -#include +#include +#include #include -#include -#include "CDeviceToken.hpp" +#include "DeviceToken.hpp" #include "IHIDListener.hpp" -#include "SDeviceSignature.hpp" +#include "DeviceSignature.hpp" #include +#include #ifdef _WIN32 #define _WIN32_LEAN_AND_MEAN 1 @@ -18,20 +19,20 @@ namespace boo { -static class CDeviceFinder* skDevFinder = NULL; +static class DeviceFinder* skDevFinder = NULL; -class CDeviceFinder +class DeviceFinder { public: - friend class CHIDListenerIOKit; - friend class CHIDListenerUdev; - friend class CHIDListenerWinUSB; - static inline CDeviceFinder* instance() {return skDevFinder;} + friend class HIDListenerIOKit; + friend class HIDListenerUdev; + friend class HIDListenerWinUSB; + static inline DeviceFinder* instance() {return skDevFinder;} private: /* Types this finder is interested in (immutable) */ - SDeviceSignature::TDeviceSignatureSet m_types; + DeviceSignature::TDeviceSignatureSet m_types; /* Platform-specific USB event registration * (for auto-scanning, NULL if not registered) */ @@ -50,9 +51,9 @@ private: return true; return false; } - inline bool _insertToken(CDeviceToken&& token) + inline bool _insertToken(DeviceToken&& token) { - if (SDeviceSignature::DeviceMatchToken(token, m_types)) { + if (DeviceSignature::DeviceMatchToken(token, m_types)) { m_tokensLock.lock(); TInsertedDeviceToken inseredTok = m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token))); @@ -67,8 +68,8 @@ private: auto preCheck = m_tokens.find(path); if (preCheck != m_tokens.end()) { - CDeviceToken& tok = preCheck->second; - CDeviceBase* dev = tok.m_connectedDev; + DeviceToken& tok = preCheck->second; + DeviceBase* dev = tok.m_connectedDev; tok._deviceClose(); deviceDisconnected(tok, dev); m_tokensLock.lock(); @@ -81,9 +82,9 @@ public: class CDeviceTokensHandle { - CDeviceFinder& m_finder; + DeviceFinder& m_finder; public: - inline CDeviceTokensHandle(CDeviceFinder& finder) : m_finder(finder) + inline CDeviceTokensHandle(DeviceFinder& finder) : m_finder(finder) {m_finder.m_tokensLock.lock();} inline ~CDeviceTokensHandle() {m_finder.m_tokensLock.unlock();} inline TDeviceTokens::iterator begin() {return m_finder.m_tokens.begin();} @@ -91,24 +92,27 @@ public: }; /* Application must specify its interested device-types */ - CDeviceFinder(std::vector types) + DeviceFinder(std::unordered_set types) : m_listener(NULL) { if (skDevFinder) - throw std::runtime_error("only one instance of CDeviceFinder may be constructed"); - skDevFinder = this; - for (const char* typeName : types) { - const SDeviceSignature* sigIter = BOO_DEVICE_SIGS; + fprintf(stderr, "only one instance of CDeviceFinder may be constructed"); + abort(); + } + skDevFinder = this; + for (const std::type_index& typeIdx : types) + { + const DeviceSignature* sigIter = BOO_DEVICE_SIGS; while (sigIter->m_name) { - if (!strcmp(sigIter->m_name, typeName)) + if (sigIter->m_typeIdx == typeIdx) m_types.push_back(sigIter); ++sigIter; } } } - ~CDeviceFinder() + ~DeviceFinder() { if (m_listener) m_listener->stopScanning(); @@ -117,7 +121,7 @@ public: } /* Get interested device-type mask */ - inline const SDeviceSignature::TDeviceSignatureSet& getTypes() const {return m_types;} + inline const DeviceSignature::TDeviceSignatureSet& getTypes() const {return m_types;} /* Iterable set of tokens */ inline CDeviceTokensHandle getTokens() {return CDeviceTokensHandle(*this);} @@ -150,8 +154,8 @@ public: return false; } - virtual void deviceConnected(CDeviceToken&) {} - virtual void deviceDisconnected(CDeviceToken&, CDeviceBase*) {} + virtual void deviceConnected(DeviceToken&) {} + virtual void deviceDisconnected(DeviceToken&, DeviceBase*) {} #if _WIN32 /* Windows-specific WM_DEVICECHANGED handler */ diff --git a/include/boo/inputdev/DeviceSignature.hpp b/include/boo/inputdev/DeviceSignature.hpp new file mode 100644 index 0000000..e92a6d9 --- /dev/null +++ b/include/boo/inputdev/DeviceSignature.hpp @@ -0,0 +1,38 @@ +#ifndef SDeviceSignature_HPP +#define SDeviceSignature_HPP + +#include +#include +#include + +namespace boo +{ + +class DeviceToken; +class DeviceBase; + +struct DeviceSignature +{ + typedef std::vector TDeviceSignatureSet; + typedef std::function TFactoryLambda; + const char* m_name; + std::type_index m_typeIdx; + unsigned m_vid, m_pid; + TFactoryLambda m_factory; + DeviceSignature() : m_name(NULL), m_typeIdx(typeid(DeviceSignature)) {} /* Sentinel constructor */ + DeviceSignature(const char* name, std::type_index&& typeIdx, unsigned vid, unsigned pid, TFactoryLambda&& factory) + : m_name(name), m_typeIdx(typeIdx), m_vid(vid), m_pid(pid), m_factory(factory) {} + static bool DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet); + static DeviceBase* DeviceNew(DeviceToken& token); +}; + +#define DEVICE_SIG(name, vid, pid) \ + DeviceSignature(#name, typeid(name), vid, pid, [](DeviceToken* tok) -> DeviceBase* {return new name(tok);}) +#define DEVICE_SIG_SENTINEL() DeviceSignature() + +extern const DeviceSignature BOO_DEVICE_SIGS[]; + +} + +#endif // SDeviceSignature_HPP + diff --git a/include/inputdev/CDeviceToken.hpp b/include/boo/inputdev/DeviceToken.hpp similarity index 74% rename from include/inputdev/CDeviceToken.hpp rename to include/boo/inputdev/DeviceToken.hpp index 2908130..4098930 100644 --- a/include/inputdev/CDeviceToken.hpp +++ b/include/boo/inputdev/DeviceToken.hpp @@ -2,13 +2,13 @@ #define CDEVICETOKEN #include -#include "CDeviceBase.hpp" -#include "SDeviceSignature.hpp" +#include "DeviceBase.hpp" +#include "DeviceSignature.hpp" namespace boo { -class CDeviceToken +class DeviceToken { public: enum TDeviceType @@ -27,10 +27,10 @@ private: std::string m_productName; std::string m_devPath; - friend class CDeviceBase; - CDeviceBase* m_connectedDev; + friend class DeviceBase; + DeviceBase* m_connectedDev; - friend class CDeviceFinder; + friend class DeviceFinder; inline void _deviceClose() { if (m_connectedDev) @@ -40,8 +40,8 @@ private: public: - CDeviceToken(const CDeviceToken&) = delete; - CDeviceToken(const CDeviceToken&& other) + DeviceToken(const DeviceToken&) = delete; + DeviceToken(const DeviceToken&& other) : m_devType(other.m_devType), m_vendorId(other.m_vendorId), m_productId(other.m_productId), @@ -50,7 +50,7 @@ public: m_devPath(other.m_devPath), m_connectedDev(other.m_connectedDev) {} - inline CDeviceToken(enum TDeviceType devType, unsigned vid, unsigned pid, const char* vname, const char* pname, const char* path) + inline DeviceToken(enum TDeviceType devType, unsigned vid, unsigned pid, const char* vname, const char* pname, const char* path) : m_devType(devType), m_vendorId(vid), m_productId(pid), @@ -70,16 +70,16 @@ public: inline const std::string& getProductName() const {return m_productName;} inline const std::string& getDevicePath() const {return m_devPath;} inline bool isDeviceOpen() const {return (m_connectedDev != NULL);} - inline CDeviceBase* openAndGetDevice() + inline DeviceBase* openAndGetDevice() { if (!m_connectedDev) - m_connectedDev = SDeviceSignature::DeviceNew(*this); + m_connectedDev = DeviceSignature::DeviceNew(*this); return m_connectedDev; } - inline bool operator ==(const CDeviceToken& rhs) const + inline bool operator ==(const DeviceToken& rhs) const {return m_devPath == rhs.m_devPath;} - inline bool operator <(const CDeviceToken& rhs) const + inline bool operator <(const DeviceToken& rhs) const {return m_devPath < rhs.m_devPath;} }; diff --git a/include/inputdev/CDolphinSmashAdapter.hpp b/include/boo/inputdev/DolphinSmashAdapter.hpp similarity index 80% rename from include/inputdev/CDolphinSmashAdapter.hpp rename to include/boo/inputdev/DolphinSmashAdapter.hpp index adba95e..24a618b 100644 --- a/include/inputdev/CDolphinSmashAdapter.hpp +++ b/include/boo/inputdev/DolphinSmashAdapter.hpp @@ -2,7 +2,7 @@ #define CDOLPHINSMASHADAPTER_HPP #include -#include "CDeviceBase.hpp" +#include "DeviceBase.hpp" namespace boo { @@ -29,7 +29,8 @@ enum EDolphinControllerButtons DOL_DOWN = 1<<14, DOL_UP = 1<<15 }; -struct SDolphinControllerState + +struct DolphinControllerState { uint8_t m_leftStick[2]; uint8_t m_rightStick[2]; @@ -39,13 +40,13 @@ struct SDolphinControllerState struct IDolphinSmashAdapterCallback { - virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {} - virtual void controllerDisconnected(unsigned idx, EDolphinControllerType type) {} + virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)type;} + virtual void controllerDisconnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)type;} virtual void controllerUpdate(unsigned idx, EDolphinControllerType type, - const SDolphinControllerState& state) {} + const DolphinControllerState& state) {(void)idx;(void)type;(void)state;} }; -class CDolphinSmashAdapter final : public CDeviceBase +class DolphinSmashAdapter final : public DeviceBase { IDolphinSmashAdapterCallback* m_callback; uint8_t m_knownControllers; @@ -56,8 +57,8 @@ class CDolphinSmashAdapter final : public CDeviceBase void transferCycle(); void finalCycle(); public: - CDolphinSmashAdapter(CDeviceToken* token); - ~CDolphinSmashAdapter(); + DolphinSmashAdapter(DeviceToken* token); + ~DolphinSmashAdapter(); inline void setCallback(IDolphinSmashAdapterCallback* cb) {m_callback = cb; m_knownControllers = 0;} diff --git a/include/inputdev/CDualshockPad.hpp b/include/boo/inputdev/DualshockPad.hpp similarity index 82% rename from include/inputdev/CDualshockPad.hpp rename to include/boo/inputdev/DualshockPad.hpp index e4d4107..7116211 100644 --- a/include/inputdev/CDualshockPad.hpp +++ b/include/boo/inputdev/DualshockPad.hpp @@ -1,13 +1,12 @@ #ifndef CDUALSHOCKPAD_HPP #define CDUALSHOCKPAD_HPP #include -#include "CDeviceBase.hpp" +#include "DeviceBase.hpp" namespace boo { - -struct SDualshockLED +struct DualshockLED { uint8_t timeEnabled; uint8_t dutyLength; @@ -16,7 +15,7 @@ struct SDualshockLED uint8_t dutyOn; }; -struct SDualshockRumble +struct DualshockRumble { uint8_t rightDuration; bool rightOn; @@ -24,23 +23,23 @@ struct SDualshockRumble uint8_t leftForce; }; -union SDualshockOutReport +union DualshockOutReport { struct { uint8_t reportId; - SDualshockRumble rumble; + DualshockRumble rumble; uint8_t gyro1; uint8_t gyro2; uint8_t padding[2]; uint8_t leds; - SDualshockLED led[4]; - SDualshockLED reserved; + DualshockLED led[4]; + DualshockLED reserved; }; uint8_t buf[36]; }; -enum EDualshockControllerButtons +enum EDualshockPadButtons { DS3_SELECT = 1<< 0, DS3_L3 = 1<< 1, @@ -75,7 +74,7 @@ enum EDualshockLED DS3_LED_4 = 1<<4 }; -struct SDualshockControllerState +struct DualshockPadState { uint8_t m_reportType; uint8_t m_reserved1; @@ -110,33 +109,33 @@ struct SDualshockControllerState float gyroZ; }; -class CDualshockController; -struct IDualshockControllerCallback +class DualshockPad; +struct IDualshockPadCallback { - CDualshockController* ctrl = nullptr; + DualshockPad* ctrl = nullptr; virtual void controllerDisconnected() {} - virtual void controllerUpdate(const SDualshockControllerState&) {} + virtual void controllerUpdate(const DualshockPadState&) {} }; -class CDualshockController final : public CDeviceBase +class DualshockPad final : public DeviceBase { - IDualshockControllerCallback* m_callback; + IDualshockPadCallback* m_callback; uint8_t m_rumbleRequest; uint8_t m_rumbleState; uint8_t m_rumbleDuration[2]; uint8_t m_rumbleIntensity[2]; uint8_t m_led; - SDualshockOutReport m_report; + DualshockOutReport m_report; uint8_t m_btAddress[6]; void deviceDisconnected(); void initialCycle(); void transferCycle(); void finalCycle(); public: - CDualshockController(CDeviceToken* token); - ~CDualshockController(); + DualshockPad(DeviceToken* token); + ~DualshockPad(); - inline void setCallback(IDualshockControllerCallback* cb) + inline void setCallback(IDualshockPadCallback* cb) { m_callback = cb; if (m_callback) m_callback->ctrl = this; } inline void startRumble(int motor, uint8_t duration = 254, uint8_t intensity=255) diff --git a/include/inputdev/CGenericPad.hpp b/include/boo/inputdev/GenericPad.hpp similarity index 52% rename from include/inputdev/CGenericPad.hpp rename to include/boo/inputdev/GenericPad.hpp index 2444c3b..11f9850 100644 --- a/include/inputdev/CGenericPad.hpp +++ b/include/boo/inputdev/GenericPad.hpp @@ -1,16 +1,16 @@ #ifndef CGENERICPAD_HPP #define CGENERICPAD_HPP -#include "CDeviceBase.hpp" +#include "DeviceBase.hpp" namespace boo { -class CGenericPad final : public CDeviceBase +class GenericPad final : public DeviceBase { public: - CGenericPad(CDeviceToken* token); - ~CGenericPad(); + GenericPad(DeviceToken* token); + ~GenericPad(); void deviceDisconnected(); }; diff --git a/include/inputdev/IHIDListener.hpp b/include/boo/inputdev/IHIDListener.hpp similarity index 79% rename from include/inputdev/IHIDListener.hpp rename to include/boo/inputdev/IHIDListener.hpp index a1a26ce..3f949da 100644 --- a/include/inputdev/IHIDListener.hpp +++ b/include/boo/inputdev/IHIDListener.hpp @@ -3,14 +3,14 @@ #include #include -#include "CDeviceToken.hpp" +#include "DeviceToken.hpp" namespace boo { -typedef std::unordered_map TDeviceTokens; +typedef std::unordered_map TDeviceTokens; typedef std::pair TInsertedDeviceToken; -class CDeviceFinder; +class DeviceFinder; class IHIDListener { @@ -33,7 +33,7 @@ public: }; /* Platform-specific constructor */ -IHIDListener* IHIDListenerNew(CDeviceFinder& finder); +IHIDListener* IHIDListenerNew(DeviceFinder& finder); } diff --git a/include/inputdev/CRevolutionPad.hpp b/include/boo/inputdev/RevolutionPad.hpp similarity index 100% rename from include/inputdev/CRevolutionPad.hpp rename to include/boo/inputdev/RevolutionPad.hpp diff --git a/include/inputdev/SDeviceSignature.hpp b/include/inputdev/SDeviceSignature.hpp deleted file mode 100644 index 80708b9..0000000 --- a/include/inputdev/SDeviceSignature.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SDeviceSignature_HPP -#define SDeviceSignature_HPP - -#include -#include - -namespace boo -{ - -class CDeviceToken; -class CDeviceBase; - -struct SDeviceSignature -{ - typedef std::vector TDeviceSignatureSet; - typedef std::function TFactoryLambda; - const char* m_name; - unsigned m_vid, m_pid; - TFactoryLambda m_factory; - SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */ - SDeviceSignature(const char* name, unsigned vid, unsigned pid, TFactoryLambda&& factory) - : m_name(name), m_vid(vid), m_pid(pid), m_factory(factory) {} - static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet); - static CDeviceBase* DeviceNew(CDeviceToken& token); -}; - -#define DEVICE_SIG(name, vid, pid) \ - SDeviceSignature(#name, vid, pid, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);}) -#define DEVICE_SIG_SENTINEL() SDeviceSignature() - -extern const SDeviceSignature BOO_DEVICE_SIGS[]; - -} - -#endif // SDeviceSignature_HPP - diff --git a/include/mac/CCGLContext.hpp b/include/mac/CCGLContext.hpp deleted file mode 100644 index 5a66f40..0000000 --- a/include/mac/CCGLContext.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef CCGLCONTEXT_HPP -#define CCGLCONTEXT_HPP - -#ifdef __APPLE__ -#include "IGraphicsContext.hpp" -#include - -namespace boo -{ - -class CCGLContext final : public IGraphicsContext -{ -public: - CCGLContext(); - virtual ~CCGLContext(); - - bool create(); - void setMinVersion (const int& min) override; - void setMajorVersion(const int& maj) override; - const std::string version() const override; - const std::string name() const override; - int depthSize() const override; - int redDepth() const override; - int greenDepth() const override; - int blueDepth() const override; -private: - int m_minVersion; - int m_majVersion; -}; - -} - -#endif // __APPLE__ -#endif // CCGLCONTEXT_HPP diff --git a/include/win/CWGLContext.hpp b/include/win/CWGLContext.hpp deleted file mode 100644 index ea40ff7..0000000 --- a/include/win/CWGLContext.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CWGLCONTEXT_HPP -#define CWGLCONTEXT_HPP - -#ifdef _WIN32 - -#include "IGraphicsContext.hpp" - -namespace boo -{ - -class CWGLContext : public IGraphicsContext -{ - -}; - -} - -#endif // _WIN32 -#endif // CWGLCONTEXT_HPP diff --git a/include/x11/CGLXContext.hpp b/include/x11/CGLXContext.hpp deleted file mode 100644 index 809101a..0000000 --- a/include/x11/CGLXContext.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef CGLXCONTEXT_HPP -#define CGLXCONTEXT_HPP - -#if !defined(__APPLE__) && (defined(__linux__) || defined(BSD)) -#include -#include "IGraphicsContext.hpp" - -namespace boo -{ - -class CGLXContext final : public IGraphicsContext -{ -public: - CGLXContext(); - virtual ~CGLXContext() {} - - bool create(); - void setMajorVersion(const int& maj) override; - void setMinVersion(const int& min) override; - const std::string version() const override; - const std::string name() const override; - int depthSize() const override; - int redDepth() const override; - int greenDepth() const override; - int blueDepth() const override; -private: - int m_majVersion; - int m_minVersion; - - Display* m_display; -}; - -} - -#endif // !defined(__APPLE__) && (defined(__linux__) || defined(BSD)) -#endif // CGLXCONTEXT_HPP diff --git a/lib/inputdev/CafeProPad.cpp b/lib/inputdev/CafeProPad.cpp new file mode 100644 index 0000000..78cce8d --- /dev/null +++ b/lib/inputdev/CafeProPad.cpp @@ -0,0 +1 @@ +#include "boo/inputdev/CafeProPad.hpp" diff --git a/lib/inputdev/DeviceBase.cpp b/lib/inputdev/DeviceBase.cpp new file mode 100644 index 0000000..9cb314c --- /dev/null +++ b/lib/inputdev/DeviceBase.cpp @@ -0,0 +1,73 @@ +#include "boo/inputdev/DeviceBase.hpp" +#include "boo/inputdev/DeviceToken.hpp" +#include "IHIDDevice.hpp" +#include + +namespace boo +{ + +DeviceBase::DeviceBase(DeviceToken* token) +: m_token(token), m_hidDev(NULL) +{ +} + +DeviceBase::~DeviceBase() +{ + delete m_hidDev; +} + +void DeviceBase::_deviceDisconnected() +{ + deviceDisconnected(); + m_token = NULL; + if (m_hidDev) + { + m_hidDev->_deviceDisconnected(); + delete m_hidDev; + m_hidDev = NULL; + } +} + +void DeviceBase::closeDevice() +{ + if (m_token) + m_token->_deviceClose(); +} + +void DeviceBase::deviceError(const char* error, ...) +{ + va_list vl; + va_start(vl, error); + vfprintf(stderr, error, vl); + va_end(vl); +} + +bool DeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length) +{ + if (m_hidDev) + return m_hidDev->_sendUSBInterruptTransfer(data, length); + return false; +} + +size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length) +{ + if (m_hidDev) + return m_hidDev->_receiveUSBInterruptTransfer(data, length); + return false; +} + +bool DeviceBase::sendHIDReport(const uint8_t* data, size_t length, uint16_t message) +{ + if (m_hidDev) + return m_hidDev->_sendHIDReport(data, length, message); + return false; +} + +size_t DeviceBase::receiveReport(uint8_t* data, size_t length, uint16_t message) +{ + if (m_hidDev) + return m_hidDev->_recieveReport(data, length, message); + return false; +} + +} diff --git a/src/inputdev/SDeviceSignature.cpp b/lib/inputdev/DeviceSignature.cpp similarity index 60% rename from src/inputdev/SDeviceSignature.cpp rename to lib/inputdev/DeviceSignature.cpp index ced5ffe..156567f 100644 --- a/src/inputdev/SDeviceSignature.cpp +++ b/lib/inputdev/DeviceSignature.cpp @@ -1,19 +1,19 @@ -#include "inputdev/SDeviceSignature.hpp" -#include "inputdev/CDeviceToken.hpp" -#include "inputdev/CGenericPad.hpp" +#include "boo/inputdev/DeviceSignature.hpp" +#include "boo/inputdev/DeviceToken.hpp" +#include "boo/inputdev/GenericPad.hpp" #include "IHIDDevice.hpp" namespace boo { -extern const SDeviceSignature BOO_DEVICE_SIGS[]; +extern const DeviceSignature BOO_DEVICE_SIGS[]; -bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet) +bool DeviceSignature::DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet) { - if (token.getDeviceType() == CDeviceToken::DEVTYPE_GENERICHID) + if (token.getDeviceType() == DeviceToken::DEVTYPE_GENERICHID) return true; - for (const SDeviceSignature* sig : sigSet) + for (const DeviceSignature* sig : sigSet) { if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId()) return true; @@ -21,15 +21,15 @@ bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDevice return false; } -IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp); -CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token) +IHIDDevice* IHIDDeviceNew(DeviceToken& token, DeviceBase& devImp); +DeviceBase* DeviceSignature::DeviceNew(DeviceToken& token) { - CDeviceBase* retval = NULL; + DeviceBase* retval = NULL; /* Early-return for generic HID devices */ - if (token.getDeviceType() == CDeviceToken::DEVTYPE_GENERICHID) + if (token.getDeviceType() == DeviceToken::DEVTYPE_GENERICHID) { - retval = new CGenericPad(&token); + retval = new GenericPad(&token); if (!retval) return NULL; @@ -44,8 +44,8 @@ CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token) } /* Otherwise perform signature-matching to find the appropriate device-factory */ - const SDeviceSignature* foundSig = NULL; - const SDeviceSignature* sigIter = BOO_DEVICE_SIGS; + const DeviceSignature* foundSig = NULL; + const DeviceSignature* sigIter = BOO_DEVICE_SIGS; unsigned targetVid = token.getVendorId(); unsigned targetPid = token.getProductId(); while (sigIter->m_name) diff --git a/src/inputdev/CDolphinSmashAdapter.cpp b/lib/inputdev/DolphinSmashAdapter.cpp similarity index 75% rename from src/inputdev/CDolphinSmashAdapter.cpp rename to lib/inputdev/DolphinSmashAdapter.cpp index f93e173..1822b6f 100644 --- a/src/inputdev/CDolphinSmashAdapter.cpp +++ b/lib/inputdev/DolphinSmashAdapter.cpp @@ -1,4 +1,4 @@ -#include "inputdev/CDolphinSmashAdapter.hpp" +#include "boo/inputdev/DolphinSmashAdapter.hpp" #include #include @@ -9,8 +9,8 @@ namespace boo * Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c */ -CDolphinSmashAdapter::CDolphinSmashAdapter(CDeviceToken* token) -: CDeviceBase(token), +DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token) +: DeviceBase(token), m_callback(NULL), m_knownControllers(0), m_rumbleRequest(0), @@ -18,7 +18,7 @@ CDolphinSmashAdapter::CDolphinSmashAdapter(CDeviceToken* token) { } -CDolphinSmashAdapter::~CDolphinSmashAdapter() +DolphinSmashAdapter::~DolphinSmashAdapter() { } @@ -36,9 +36,9 @@ static inline EDolphinControllerType parseType(unsigned char status) } static inline EDolphinControllerType -parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble) +parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble) { - memset(stateOut, 0, sizeof(SDolphinControllerState)); + memset(stateOut, 0, sizeof(DolphinControllerState)); unsigned char status = payload[0]; EDolphinControllerType type = parseType(status); @@ -56,16 +56,16 @@ parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble) return type; } -void CDolphinSmashAdapter::initialCycle() +void DolphinSmashAdapter::initialCycle() { uint8_t handshakePayload[] = {0x13}; - sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload)); + sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload)); } -void CDolphinSmashAdapter::transferCycle() +void DolphinSmashAdapter::transferCycle() { uint8_t payload[37]; - size_t recvSz = receiveUSBInterruptTransfer(0, payload, sizeof(payload)); + size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload)); if (recvSz != 37 || payload[0] != 0x21) return; //printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]); @@ -78,7 +78,7 @@ void CDolphinSmashAdapter::transferCycle() uint8_t rumbleMask = 0; for (int i=0 ; i<4 ; i++, controller += 9) { - SDolphinControllerState state; + DolphinControllerState state; bool rumble = false; EDolphinControllerType type = parseState(&state, controller, rumble); if (type && !(m_knownControllers & 1< #include #include @@ -38,8 +38,8 @@ static const uint8_t defaultReport[35] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; -CDualshockController::CDualshockController(CDeviceToken* token) - : CDeviceBase(token), +DualshockPad::DualshockPad(DeviceToken* token) + : DeviceBase(token), m_callback(nullptr), m_rumbleRequest(0), m_rumbleState(0) @@ -47,18 +47,18 @@ CDualshockController::CDualshockController(CDeviceToken* token) memcpy(m_report.buf, defaultReport, 35); } -CDualshockController::~CDualshockController() +DualshockPad::~DualshockPad() { } -void CDualshockController::deviceDisconnected() +void DualshockPad::deviceDisconnected() { if (m_callback) m_callback->controllerDisconnected(); } -void CDualshockController::initialCycle() +void DualshockPad::initialCycle() { uint8_t setupCommand[4] = {0x42, 0x0c, 0x00, 0x00}; //Tells controller to start sending changes on in pipe if (!sendHIDReport(setupCommand, sizeof(setupCommand), 0x03F4)) @@ -72,14 +72,12 @@ void CDualshockController::initialCycle() m_btAddress[5 - i] = btAddr[i + 2]; // Copy into buffer reversed, so it is LSB first } -void CDualshockController::transferCycle() +void DualshockPad::transferCycle() { - SDualshockControllerState state; - size_t recvSz = receiveUSBInterruptTransfer(0, (uint8_t*)&state, 49); + DualshockControllerState state; + size_t recvSz = receiveUSBInterruptTransfer((uint8_t*)&state, 49); if (recvSz != 49) return; - printf("\x1B[2J\x1B[H"); - hexdump(&state, 49); for (int i = 0; i < 3; i++) state.m_accelerometer[i] = be16toh(state.m_accelerometer[i]); @@ -132,7 +130,7 @@ void CDualshockController::transferCycle() } -void CDualshockController::finalCycle() +void DualshockPad::finalCycle() { } diff --git a/lib/inputdev/GenericPad.cpp b/lib/inputdev/GenericPad.cpp new file mode 100644 index 0000000..f4839b0 --- /dev/null +++ b/lib/inputdev/GenericPad.cpp @@ -0,0 +1,23 @@ +#include "boo/inputdev/GenericPad.hpp" +#include "boo/inputdev/DeviceToken.hpp" + +namespace boo +{ + +GenericPad::GenericPad(DeviceToken* token) + : DeviceBase(token) +{ + +} + +GenericPad::~GenericPad() +{ + +} + +void GenericPad::deviceDisconnected() +{ + +} + +} diff --git a/src/inputdev/CHIDDeviceIOKit.cpp b/lib/inputdev/HIDDeviceIOKit.cpp similarity index 98% rename from src/inputdev/CHIDDeviceIOKit.cpp rename to lib/inputdev/HIDDeviceIOKit.cpp index cf2b314..a089bf6 100644 --- a/src/inputdev/CHIDDeviceIOKit.cpp +++ b/lib/inputdev/HIDDeviceIOKit.cpp @@ -24,7 +24,7 @@ class CHIDDeviceIOKit final : public IHIDDevice std::condition_variable m_initCond; std::thread* m_thread; - bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) + bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { if (m_usbIntf) { @@ -34,7 +34,7 @@ class CHIDDeviceIOKit final : public IHIDDevice return false; } - size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) + size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { if (m_usbIntf) { diff --git a/src/inputdev/CHIDDeviceUdev.cpp b/lib/inputdev/HIDDeviceUdev.cpp similarity index 84% rename from src/inputdev/CHIDDeviceUdev.cpp rename to lib/inputdev/HIDDeviceUdev.cpp index 4ba3e20..02c4c27 100644 --- a/src/inputdev/CHIDDeviceUdev.cpp +++ b/lib/inputdev/HIDDeviceUdev.cpp @@ -1,10 +1,11 @@ #include "IHIDDevice.hpp" -#include "inputdev/CDeviceToken.hpp" -#include "inputdev/CDeviceBase.hpp" +#include "boo/inputdev/DeviceToken.hpp" +#include "boo/inputdev/DeviceBase.hpp" #include #include #include +#include #include #include #include @@ -23,10 +24,10 @@ udev* GetUdev(); * Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html */ -class CHIDDeviceUdev final : public IHIDDevice +class HIDDeviceUdev final : public IHIDDevice { - CDeviceToken& m_token; - CDeviceBase& m_devImp; + DeviceToken& m_token; + DeviceBase& m_devImp; int m_devFd = 0; unsigned m_usbIntfInPipe = 0; @@ -38,7 +39,7 @@ class CHIDDeviceUdev final : public IHIDDevice std::condition_variable m_initCond; std::thread* m_thread; - bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) + bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { if (m_devFd) { @@ -57,7 +58,7 @@ class CHIDDeviceUdev final : public IHIDDevice return false; } - size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) + size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { if (m_devFd) { @@ -73,7 +74,7 @@ class CHIDDeviceUdev final : public IHIDDevice return 0; } - static void _threadProcUSBLL(CHIDDeviceUdev* device) + static void _threadProcUSBLL(HIDDeviceUdev* device) { unsigned i; char errStr[256]; @@ -93,22 +94,22 @@ class CHIDDeviceUdev final : public IHIDDevice udev_device_unref(udevDev); return; } - usb_device_descriptor devDesc = {0}; + usb_device_descriptor devDesc = {}; read(device->m_devFd, &devDesc, 1); read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1); if (devDesc.bNumConfigurations) { - usb_config_descriptor confDesc = {0}; + usb_config_descriptor confDesc = {}; read(device->m_devFd, &confDesc, 1); read(device->m_devFd, &confDesc.bDescriptorType, confDesc.bLength-1); if (confDesc.bNumInterfaces) { - usb_interface_descriptor intfDesc = {0}; + usb_interface_descriptor intfDesc = {}; read(device->m_devFd, &intfDesc, 1); read(device->m_devFd, &intfDesc.bDescriptorType, intfDesc.bLength-1); for (i=0 ; im_devFd, &endpDesc, 1); read(device->m_devFd, &endpDesc.bDescriptorType, endpDesc.bLength-1); if ((endpDesc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) @@ -148,7 +149,7 @@ class CHIDDeviceUdev final : public IHIDDevice } - static void _threadProcBTLL(CHIDDeviceUdev* device) + static void _threadProcBTLL(HIDDeviceUdev* device) { std::unique_lock lk(device->m_initMutex); udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str()); @@ -167,7 +168,7 @@ class CHIDDeviceUdev final : public IHIDDevice udev_device_unref(udevDev); } - static void _threadProcHID(CHIDDeviceUdev* device) + static void _threadProcHID(HIDDeviceUdev* device) { std::unique_lock lk(device->m_initMutex); udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str()); @@ -234,26 +235,29 @@ class CHIDDeviceUdev final : public IHIDDevice public: - CHIDDeviceUdev(CDeviceToken& token, CDeviceBase& devImp) - : m_token(token), - m_devImp(devImp), - m_devPath(token.getDevicePath()) + HIDDeviceUdev(DeviceToken& token, DeviceBase& devImp) + : m_token(token), + m_devImp(devImp), + m_devPath(token.getDevicePath()) { devImp.m_hidDev = this; std::unique_lock lk(m_initMutex); - CDeviceToken::TDeviceType dType = token.getDeviceType(); - if (dType == CDeviceToken::DEVTYPE_USB) + DeviceToken::TDeviceType dType = token.getDeviceType(); + if (dType == DeviceToken::DEVTYPE_USB) m_thread = new std::thread(_threadProcUSBLL, this); - else if (dType == CDeviceToken::DEVTYPE_BLUETOOTH) + else if (dType == DeviceToken::DEVTYPE_BLUETOOTH) m_thread = new std::thread(_threadProcBTLL, this); - else if (dType == CDeviceToken::DEVTYPE_GENERICHID) + else if (dType == DeviceToken::DEVTYPE_GENERICHID) m_thread = new std::thread(_threadProcHID, this); else - throw std::runtime_error("invalid token supplied to device constructor"); + { + fprintf(stderr, "invalid token supplied to device constructor"); + abort(); + } m_initCond.wait(lk); } - ~CHIDDeviceUdev() + ~HIDDeviceUdev() { m_runningTransferLoop = false; m_thread->join(); @@ -263,9 +267,9 @@ public: }; -IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp) +IHIDDevice* IHIDDeviceNew(DeviceToken& token, DeviceBase& devImp) { - return new CHIDDeviceUdev(token, devImp); + return new HIDDeviceUdev(token, devImp); } } diff --git a/src/inputdev/CHIDDeviceWinUSB.cpp b/lib/inputdev/HIDDeviceWinUSB.cpp similarity index 97% rename from src/inputdev/CHIDDeviceWinUSB.cpp rename to lib/inputdev/HIDDeviceWinUSB.cpp index 8149103..04fb8e0 100644 --- a/src/inputdev/CHIDDeviceWinUSB.cpp +++ b/lib/inputdev/HIDDeviceWinUSB.cpp @@ -33,7 +33,7 @@ class CHIDDeviceWinUSB final : public IHIDDevice std::condition_variable m_initCond; std::thread* m_thread; - bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) + bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { if (m_usbHandle) { @@ -47,7 +47,7 @@ class CHIDDeviceWinUSB final : public IHIDDevice return false; } - size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) + size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { if (m_usbHandle) { diff --git a/src/inputdev/CHIDListenerIOKit.cpp b/lib/inputdev/HIDListenerIOKit.cpp similarity index 100% rename from src/inputdev/CHIDListenerIOKit.cpp rename to lib/inputdev/HIDListenerIOKit.cpp diff --git a/src/inputdev/CHIDListenerUdev.cpp b/lib/inputdev/HIDListenerUdev.cpp similarity index 85% rename from src/inputdev/CHIDListenerUdev.cpp rename to lib/inputdev/HIDListenerUdev.cpp index 5db05f5..8c858a1 100644 --- a/src/inputdev/CHIDListenerUdev.cpp +++ b/lib/inputdev/HIDListenerUdev.cpp @@ -1,7 +1,9 @@ -#include "inputdev/IHIDListener.hpp" -#include "inputdev/CDeviceFinder.hpp" +#include "boo/inputdev/IHIDListener.hpp" +#include "boo/inputdev/DeviceFinder.hpp" #include #include +#include +#include #include namespace boo @@ -15,16 +17,16 @@ udev* GetUdev() return UDEV_INST; } -class CHIDListenerUdev final : public IHIDListener +class HIDListenerUdev final : public IHIDListener { - CDeviceFinder& m_finder; + DeviceFinder& m_finder; udev_monitor* m_udevMon; std::thread* m_udevThread; bool m_udevRunning; bool m_scanningEnabled; - static void deviceConnected(CHIDListenerUdev* listener, + static void deviceConnected(HIDListenerUdev* listener, udev_device* device) { if (!listener->m_scanningEnabled) @@ -32,11 +34,11 @@ class CHIDListenerUdev final : public IHIDListener /* Filter to USB/BT */ const char* dt = udev_device_get_devtype(device); - CDeviceToken::TDeviceType type; + DeviceToken::TDeviceType type; if (!strcmp(dt, "usb_device")) - type = CDeviceToken::DEVTYPE_USB; + type = DeviceToken::DEVTYPE_USB; else if (!strcmp(dt, "bluetooth_device")) - type = CDeviceToken::DEVTYPE_BLUETOOTH; + type = DeviceToken::DEVTYPE_BLUETOOTH; else return; @@ -47,7 +49,7 @@ class CHIDListenerUdev final : public IHIDListener int vid = 0, pid = 0; udev_list_entry* attrs = udev_device_get_properties_list_entry(device); -#if 1 +#if 0 udev_list_entry* att = NULL; udev_list_entry_foreach(att, attrs) { @@ -76,13 +78,13 @@ class CHIDListenerUdev final : public IHIDListener if (producte) product = udev_list_entry_get_value(producte); - if (!listener->m_finder._insertToken(CDeviceToken(type, vid, pid, manuf, product, devPath))) + if (!listener->m_finder._insertToken(DeviceToken(type, vid, pid, manuf, product, devPath))) { /* Matched-insertion failed; see if generic HID interface is available */ udev_list_entry* devInterfaces = NULL; - if (type == CDeviceToken::DEVTYPE_USB) + if (type == DeviceToken::DEVTYPE_USB) devInterfaces = udev_list_entry_get_by_name(attrs, "ID_USB_INTERFACES"); - else if (type == CDeviceToken::DEVTYPE_BLUETOOTH) + else if (type == DeviceToken::DEVTYPE_BLUETOOTH) devInterfaces = udev_list_entry_get_by_name(attrs, "ID_BLUETOOTH_INTERFACES"); if (devInterfaces) { @@ -100,7 +102,7 @@ class CHIDListenerUdev final : public IHIDListener { const char* hidPath = udev_list_entry_get_name(hidEnt); if (!listener->m_finder._hasToken(hidPath)) - listener->m_finder._insertToken(CDeviceToken(CDeviceToken::DEVTYPE_GENERICHID, + listener->m_finder._insertToken(DeviceToken(DeviceToken::DEVTYPE_GENERICHID, vid, pid, manuf, product, hidPath)); } udev_enumerate_unref(hidEnum); @@ -109,14 +111,14 @@ class CHIDListenerUdev final : public IHIDListener } } - static void deviceDisconnected(CHIDListenerUdev* listener, + static void deviceDisconnected(HIDListenerUdev* listener, udev_device* device) { const char* devPath = udev_device_get_syspath(device); listener->m_finder._removeToken(devPath); } - static void _udevProc(CHIDListenerUdev* listener) + static void _udevProc(HIDListenerUdev* listener) { udev_monitor_enable_receiving(listener->m_udevMon); int fd = udev_monitor_get_fd(listener->m_udevMon); @@ -140,14 +142,17 @@ class CHIDListenerUdev final : public IHIDListener } public: - CHIDListenerUdev(CDeviceFinder& finder) + HIDListenerUdev(DeviceFinder& finder) : m_finder(finder) { /* Setup hotplug events */ m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev"); if (!m_udevMon) - throw std::runtime_error("unable to init udev_monitor"); + { + fprintf(stderr, "unable to init udev_monitor"); + abort(); + } udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "usb", "usb_device"); udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "bluetooth", "bluetooth_device"); udev_monitor_filter_update(m_udevMon); @@ -163,9 +168,10 @@ public: } - ~CHIDListenerUdev() + ~HIDListenerUdev() { m_udevRunning = false; + pthread_kill(m_udevThread->native_handle(), SIGINT); m_udevThread->join(); delete m_udevThread; udev_monitor_unref(m_udevMon); @@ -208,9 +214,9 @@ public: }; -IHIDListener* IHIDListenerNew(CDeviceFinder& finder) +IHIDListener* IHIDListenerNew(DeviceFinder& finder) { - return new CHIDListenerUdev(finder); + return new HIDListenerUdev(finder); } } diff --git a/src/inputdev/CHIDListenerWinUSB.cpp b/lib/inputdev/HIDListenerWinUSB.cpp similarity index 100% rename from src/inputdev/CHIDListenerWinUSB.cpp rename to lib/inputdev/HIDListenerWinUSB.cpp diff --git a/src/inputdev/IHIDDevice.hpp b/lib/inputdev/IHIDDevice.hpp similarity index 59% rename from src/inputdev/IHIDDevice.hpp rename to lib/inputdev/IHIDDevice.hpp index 54beef2..a394341 100644 --- a/src/inputdev/IHIDDevice.hpp +++ b/lib/inputdev/IHIDDevice.hpp @@ -1,17 +1,17 @@ #ifndef IHIDDEVICE_HPP #define IHIDDEVICE_HPP -#include "inputdev/CDeviceToken.hpp" +#include "boo/inputdev/DeviceToken.hpp" namespace boo { class IHIDDevice { - friend class CDeviceBase; + friend class DeviceBase; virtual void _deviceDisconnected()=0; - virtual bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)=0; - virtual size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0; + virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)=0; + virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)=0; virtual bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message)=0; virtual size_t _recieveReport(const uint8_t* data, size_t length, uint16_t message){} public: diff --git a/lib/inputdev/RevolutionPad.cpp b/lib/inputdev/RevolutionPad.cpp new file mode 100644 index 0000000..8d8d4c9 --- /dev/null +++ b/lib/inputdev/RevolutionPad.cpp @@ -0,0 +1 @@ +#include "boo/inputdev/RevolutionPad.hpp" diff --git a/lib/mac/ApplicationCocoa.mm b/lib/mac/ApplicationCocoa.mm new file mode 100644 index 0000000..9ebaa86 --- /dev/null +++ b/lib/mac/ApplicationCocoa.mm @@ -0,0 +1,182 @@ +#include + +#include "IApplication.hpp" + +@interface AppDelegate : NSObject +{ + boo::IApplicationCallback* callback; + @public + NSPanel* aboutPanel; +} +- (id)initWithCallback:(boo::IApplicationCallback*)cb; +@end + +@implementation AppDelegate +- (id)initWithCallback:(boo::IApplicationCallback*)cb +{ + self = [super init]; + callback = cb; + return self; +} +- (void)applicationDidFinishLaunching:(NSNotification*)notification +{ + (void)notification; + callback->appLaunched(boo::IApplicationInstance()); +} +- (void)applicationWillTerminate:(NSNotification*)notification +{ + (void)notification; + callback->appQuitting(boo::IApplicationInstance()); +} +- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename +{ + (void)sender; + return callback->appFileOpen(boo::IApplicationInstance(), [filename UTF8String]); +} +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { + (void)sender; + return YES; +} +- (IBAction)aboutApp:(id)sender +{ + (void)sender; + NSRect screenFrame = [[aboutPanel screen] frame]; + CGFloat xPos = NSWidth(screenFrame)/2 - 300/2; + CGFloat yPos = NSHeight(screenFrame)/2 - 220/2; + NSRect aboutCr = NSMakeRect(xPos, yPos, 300, 220); + [aboutPanel setFrame:aboutCr display:NO]; + [aboutPanel makeKeyAndOrderFront:self]; +} +- (IBAction)toggleFs:(id)sender +{ + (void)sender; + [[NSApp keyWindow] toggleFullScreen:nil]; +} +- (IBAction)quitApp:(id)sender +{ + (void)sender; + [NSApp terminate:nil]; +} +@end + +namespace boo +{ + +IWindow* _CWindowCocoaNew(const std::string& title); + +class CApplicationCocoa final : public IApplication +{ + IApplicationCallback& m_callback; + const std::string m_friendlyName; + const std::string m_pname; + const std::vector m_args; + + NSPanel* aboutPanel; + + void _deletedWindow(IWindow* window) + { + (void)window; + } + +public: + CApplicationCocoa(IApplicationCallback& callback, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args) + : m_callback(callback), + m_friendlyName(friendlyName), + m_pname(pname), + m_args(args) + {} + + EPlatformType getPlatformType() const + { + return PLAT_COCOA; + } + + void run() + { + @autoreleasepool + { + NSApplication* app = [NSApplication sharedApplication]; + [app setActivationPolicy:NSApplicationActivationPolicyRegular]; + + /* Delegate (OS X callbacks) */ + AppDelegate* appDelegate = [[AppDelegate alloc] initWithCallback:&m_callback]; + [app setDelegate:appDelegate]; + + /* App menu */ + NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"]; + NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease]]; + [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease] + action:@selector(aboutApp:) + keyEquivalent:@""]; + NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen" + action:@selector(toggleFs:) + keyEquivalent:@"f"]; + [fsItem setKeyEquivalentModifierMask:NSCommandKeyMask]; + [rwkMenu addItem:[NSMenuItem separatorItem]]; + NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()] autorelease] + action:@selector(quitApp:) + keyEquivalent:@"q"]; + [quit_item setKeyEquivalentModifierMask:NSCommandKeyMask]; + [[appMenu addItemWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease] + action:nil keyEquivalent:@""] setSubmenu:rwkMenu]; + [[NSApplication sharedApplication] setMainMenu:appMenu]; + + /* About panel */ + NSRect aboutCr = NSMakeRect(0, 0, 300, 220); + aboutPanel = [[NSPanel alloc] initWithContentRect:aboutCr + styleMask:NSUtilityWindowMask|NSTitledWindowMask|NSClosableWindowMask + backing:NSBackingStoreBuffered defer:YES]; + [aboutPanel setTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease]]; + NSText* aboutText = [[NSText alloc] initWithFrame:aboutCr]; + [aboutText setEditable:NO]; + [aboutText setAlignment:NSCenterTextAlignment]; + [aboutText setString:@"\nRWK Authors\n\nJackoalan\nAntidote\n"]; + [aboutPanel setContentView:aboutText]; + appDelegate->aboutPanel = aboutPanel; + + [app run]; + } + } + + void quit() + { + [NSApp terminate:nil]; + } + + const std::string& getProcessName() const + { + return m_pname; + } + + const std::vector& getArgs() const + { + return m_args; + } + + IWindow* newWindow(const std::string& title) + { + return _CWindowCocoaNew(title); + } +}; + +IApplication* APP = NULL; +IApplication* IApplicationBootstrap(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args) +{ + if (!APP) + { + if (platform != IApplication::PLAT_COCOA && + platform != IApplication::PLAT_AUTO) + return NULL; + APP = new CApplicationCocoa(cb, friendlyName, pname, args); + } + return APP; +} + +} diff --git a/src/mac/CCGLCocoaView.mm b/lib/mac/GLViewCocoa.mm similarity index 100% rename from src/mac/CCGLCocoaView.mm rename to lib/mac/GLViewCocoa.mm diff --git a/lib/mac/GraphicsContextCocoa.mm b/lib/mac/GraphicsContextCocoa.mm new file mode 100644 index 0000000..ef61ad1 --- /dev/null +++ b/lib/mac/GraphicsContextCocoa.mm @@ -0,0 +1,639 @@ +#import +#include +#include +#include "windowsys/IGraphicsContext.hpp" +#include "windowsys/IWindow.hpp" + +/* AppKit applies OpenGL much differently than other platforms + * the NSOpenGLView class composes together all necessary + * OGL context members and provides the necessary event hooks + * for KB/Mouse/Touch events + */ + +static const NSOpenGLPixelFormatAttribute PF_RGBA8_ATTRS[] = +{ + NSOpenGLPFAAccelerated, + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, +}; + +static const NSOpenGLPixelFormatAttribute PF_RGBA8_Z24_ATTRS[] = +{ + NSOpenGLPFAAccelerated, + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 24, +}; + +static const NSOpenGLPixelFormatAttribute PF_RGBAF32_ATTRS[] = +{ + NSOpenGLPFAAccelerated, + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorFloat, + NSOpenGLPFAColorSize, 96, + NSOpenGLPFAAlphaSize, 32, +}; + +static const NSOpenGLPixelFormatAttribute PF_RGBAF32_Z24_ATTRS[] = +{ + NSOpenGLPFAAccelerated, + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorFloat, + NSOpenGLPFAColorSize, 96, + NSOpenGLPFAAlphaSize, 32, + NSOpenGLPFADepthSize, 24, +}; + +static const NSOpenGLPixelFormatAttribute* PF_TABLE[] = +{ + NULL, + PF_RGBA8_ATTRS, + PF_RGBA8_Z24_ATTRS, + PF_RGBAF32_ATTRS, + PF_RGBAF32_Z24_ATTRS +}; + +namespace boo {class CGraphicsContextCocoa;} +@interface CGraphicsContextCocoaInternal : NSOpenGLView +{ + NSUInteger lastModifiers; + boo::CGraphicsContextCocoa* booContext; +} +- (id)initWithBooContext:(boo::CGraphicsContextCocoa*)bctx; +@end + +namespace boo +{ + +class CGraphicsContextCocoa final : public IGraphicsContext +{ + + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; + CGraphicsContextCocoaInternal* m_nsContext; + NSOpenGLContext* m_nsShareContext; + +public: + IWindowCallback* m_callback; + + CGraphicsContextCocoa(EGraphicsAPI api, IWindow* parentWindow) + : m_api(api), + m_pf(PF_RGBA8), + m_parentWindow(parentWindow), + m_nsContext(NULL), + m_nsShareContext(NULL), + m_callback(NULL) + {} + + ~CGraphicsContextCocoa() + { + [m_nsContext release]; + [m_nsShareContext release]; + } + + void _setCallback(IWindowCallback* cb) + { + m_callback = cb; + } + + EGraphicsAPI getAPI() const + { + return m_api; + } + + EPixelFormat getPixelFormat() const + { + return m_pf; + } + + void setPixelFormat(EPixelFormat pf) + { + if (pf > PF_RGBAF32_Z24) + return; + m_pf = pf; + } + + void initializeContext() + { + if (m_nsShareContext) + return; + m_nsContext = [[CGraphicsContextCocoaInternal alloc] initWithBooContext:this]; + [(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext]; + } + + IGraphicsContext* makeShareContext() const + { + NSOpenGLContext* nsctx; + if (m_nsContext) + { + nsctx = [[NSOpenGLContext alloc] initWithFormat:[m_nsContext pixelFormat] + shareContext:[m_nsContext openGLContext]]; + } + else if (m_nsShareContext) + { + nsctx = [[NSOpenGLContext alloc] initWithFormat:[m_nsShareContext pixelFormat] + shareContext:m_nsShareContext]; + } + else + return NULL; + if (!nsctx) + return NULL; + CGraphicsContextCocoa* newCtx = new CGraphicsContextCocoa(m_api, NULL); + newCtx->m_nsShareContext = nsctx; + return newCtx; + } + + void makeCurrent() + { + if (m_nsContext) + [[m_nsContext openGLContext] makeCurrentContext]; + else if (m_nsShareContext) + [m_nsShareContext makeCurrentContext]; + } + + void clearCurrent() + { + [NSOpenGLContext clearCurrentContext]; + } + + void swapBuffer() + { + [[m_nsContext openGLContext] flushBuffer]; + } + +}; + +IGraphicsContext* _CGraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow) +{ + if (api != IGraphicsContext::API_OPENGL_3_3 && api != IGraphicsContext::API_OPENGL_4_2) + return NULL; + + /* Create temporary context to query GL version */ + NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_RGBA8_ATTRS]; + if (!nspf) + return NULL; + NSOpenGLContext* nsctx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:nil]; + [nspf release]; + if (!nsctx) + return NULL; + [nsctx makeCurrentContext]; + const char* glVersion = (char*)glGetString(GL_VERSION); + unsigned major = 0; + unsigned minor = 0; + if (glVersion) + { + major = glVersion[0] - '0'; + minor = glVersion[2] - '0'; + } + [NSOpenGLContext clearCurrentContext]; + [nsctx release]; + if (!glVersion) + return NULL; + + if (major > 4 || (major == 4 && minor >= 2)) + api = IGraphicsContext::API_OPENGL_4_2; + else if (major == 3 && minor >= 3) + if (api == IGraphicsContext::API_OPENGL_4_2) + return NULL; + + return new CGraphicsContextCocoa(api, parentWindow); +} + +} + +@implementation CGraphicsContextCocoaInternal +- (id)initWithBooContext:(boo::CGraphicsContextCocoa*)bctx +{ + lastModifiers = 0; + booContext = bctx; + boo::IGraphicsContext::EPixelFormat pf = bctx->getPixelFormat(); + NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[pf]]; + self = [self initWithFrame:NSMakeRect(0, 0, 100, 100) pixelFormat:nspf]; + [nspf release]; + return self; +} + +- (BOOL)acceptsTouchEvents +{ + return YES; +} + +static inline boo::IWindowCallback::EModifierKey getMod(NSEventModifierFlags flags) +{ + int ret = boo::IWindowCallback::MKEY_NONE; + if (flags & NSControlKeyMask) + ret |= boo::IWindowCallback::MKEY_CTRL; + if (flags & NSAlternateKeyMask) + ret |= boo::IWindowCallback::MKEY_ALT; + if (flags & NSShiftKeyMask) + ret |= boo::IWindowCallback::MKEY_SHIFT; + if (flags & NSCommandKeyMask) + ret |= boo::IWindowCallback::MKEY_COMMAND; + return static_cast(ret); +} + +static inline boo::IWindowCallback::EMouseButton getButton(NSEvent* event) +{ + NSInteger buttonNumber = event.buttonNumber; + if (buttonNumber == 3) + return boo::IWindowCallback::BUTTON_MIDDLE; + else if (buttonNumber == 4) + return boo::IWindowCallback::BUTTON_AUX1; + else if (buttonNumber == 5) + return boo::IWindowCallback::BUTTON_AUX2; + return boo::IWindowCallback::BUTTON_NONE; +} + +- (void)mouseDown:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + float pixelFactor = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + boo::IWindowCallback::SWindowCoord coord = + { + {(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)}, + {(unsigned)liw.x, (unsigned)liw.y}, + {(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)} + }; + booContext->m_callback->mouseDown(coord, boo::IWindowCallback::BUTTON_PRIMARY, + getMod([theEvent modifierFlags])); +} + +- (void)mouseUp:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + float pixelFactor = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + boo::IWindowCallback::SWindowCoord coord = + { + {(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)}, + {(unsigned)liw.x, (unsigned)liw.y}, + {(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)} + }; + booContext->m_callback->mouseUp(coord, boo::IWindowCallback::BUTTON_PRIMARY, + getMod([theEvent modifierFlags])); +} + +- (void)rightMouseDown:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + float pixelFactor = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + boo::IWindowCallback::SWindowCoord coord = + { + {(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)}, + {(unsigned)liw.x, (unsigned)liw.y}, + {(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)} + }; + booContext->m_callback->mouseDown(coord, boo::IWindowCallback::BUTTON_SECONDARY, + getMod([theEvent modifierFlags])); +} + +- (void)rightMouseUp:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + float pixelFactor = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + boo::IWindowCallback::SWindowCoord coord = + { + {(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)}, + {(unsigned)liw.x, (unsigned)liw.y}, + {(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)} + }; + booContext->m_callback->mouseUp(coord, boo::IWindowCallback::BUTTON_SECONDARY, + getMod([theEvent modifierFlags])); +} + +- (void)otherMouseDown:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + boo::IWindowCallback::EMouseButton button = getButton(theEvent); + if (!button) + return; + NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + float pixelFactor = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + boo::IWindowCallback::SWindowCoord coord = + { + {(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)}, + {(unsigned)liw.x, (unsigned)liw.y}, + {(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)} + }; + booContext->m_callback->mouseDown(coord, button, getMod([theEvent modifierFlags])); +} + +- (void)otherMouseUp:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + boo::IWindowCallback::EMouseButton button = getButton(theEvent); + if (!button) + return; + NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + float pixelFactor = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + boo::IWindowCallback::SWindowCoord coord = + { + {(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)}, + {(unsigned)liw.x, (unsigned)liw.y}, + {(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)} + }; + booContext->m_callback->mouseUp(coord, button, getMod([theEvent modifierFlags])); +} + +- (void)mouseMoved:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil]; + float pixelFactor = [[self window] backingScaleFactor]; + NSRect frame = [self frame]; + boo::IWindowCallback::SWindowCoord coord = + { + {(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)}, + {(unsigned)liw.x, (unsigned)liw.y}, + {(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)} + }; + booContext->m_callback->mouseMove(coord); +} +- (void)mouseDragged:(NSEvent*)theEvent +{ + [self mouseMoved:theEvent]; +} +- (void)rightMouseDragged:(NSEvent*)theEvent +{ + [self mouseMoved:theEvent]; +} +- (void)otherMouseDragged:(NSEvent*)theEvent +{ + [self mouseMoved:theEvent]; +} + +- (void)scrollWheel:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + boo::IWindowCallback::SScrollDelta scroll = + { + {(float)[theEvent scrollingDeltaX], (float)[theEvent scrollingDeltaY]}, + (bool)[theEvent hasPreciseScrollingDeltas] + }; + booContext->m_callback->scroll(scroll); +} + +- (void)touchesBeganWithEvent:(NSEvent*)event +{ + if (!booContext->m_callback) + return; + for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil]) + { + NSPoint pos = touch.normalizedPosition; + boo::IWindowCallback::SWindowCoord coord = + { + {0, 0}, + {0, 0}, + {(float)pos.x, (float)pos.y} + }; + booContext->m_callback->touchDown(coord, (uintptr_t)touch.identity); + } +} + +- (void)touchesEndedWithEvent:(NSEvent*)event +{ + if (!booContext->m_callback) + return; + for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil]) + { + NSPoint pos = touch.normalizedPosition; + boo::IWindowCallback::SWindowCoord coord = + { + {0, 0}, + {0, 0}, + {(float)pos.x, (float)pos.y} + }; + booContext->m_callback->touchUp(coord, (uintptr_t)touch.identity); + } +} + +- (void)touchesMovedWithEvent:(NSEvent*)event +{ + if (!booContext->m_callback) + return; + for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil]) + { + NSPoint pos = touch.normalizedPosition; + boo::IWindowCallback::SWindowCoord coord = + { + {0, 0}, + {0, 0}, + {(float)pos.x, (float)pos.y} + }; + booContext->m_callback->touchMove(coord, (uintptr_t)touch.identity); + } +} + +- (void)touchesCancelledWithEvent:(NSEvent*)event +{ + if (!booContext->m_callback) + return; + for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseCancelled inView:nil]) + { + NSPoint pos = touch.normalizedPosition; + boo::IWindowCallback::SWindowCoord coord = + { + {0, 0}, + {0, 0}, + {(float)pos.x, (float)pos.y} + }; + booContext->m_callback->touchUp(coord, (uintptr_t)touch.identity); + } +} + +/* keycodes for keys that are independent of keyboard layout*/ +enum +{ + kVK_Return = 0x24, + kVK_Tab = 0x30, + kVK_Space = 0x31, + kVK_Delete = 0x33, + kVK_Escape = 0x35, + kVK_Command = 0x37, + kVK_Shift = 0x38, + kVK_CapsLock = 0x39, + kVK_Option = 0x3A, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightOption = 0x3D, + kVK_RightControl = 0x3E, + kVK_Function = 0x3F, + kVK_F17 = 0x40, + kVK_VolumeUp = 0x48, + kVK_VolumeDown = 0x49, + kVK_Mute = 0x4A, + kVK_F18 = 0x4F, + kVK_F19 = 0x50, + kVK_F20 = 0x5A, + kVK_F5 = 0x60, + kVK_F6 = 0x61, + kVK_F7 = 0x62, + kVK_F3 = 0x63, + kVK_F8 = 0x64, + kVK_F9 = 0x65, + kVK_F11 = 0x67, + kVK_F13 = 0x69, + kVK_F16 = 0x6A, + kVK_F14 = 0x6B, + kVK_F10 = 0x6D, + kVK_F12 = 0x6F, + kVK_F15 = 0x71, + kVK_Help = 0x72, + kVK_Home = 0x73, + kVK_PageUp = 0x74, + kVK_ForwardDelete = 0x75, + kVK_F4 = 0x76, + kVK_End = 0x77, + kVK_F2 = 0x78, + kVK_PageDown = 0x79, + kVK_F1 = 0x7A, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E +}; +static boo::IWindowCallback::ESpecialKey translateKeycode(short code) +{ + switch (code) { + case kVK_F1: + return boo::IWindowCallback::KEY_F1; + case kVK_F2: + return boo::IWindowCallback::KEY_F2; + case kVK_F3: + return boo::IWindowCallback::KEY_F3; + case kVK_F4: + return boo::IWindowCallback::KEY_F4; + case kVK_F5: + return boo::IWindowCallback::KEY_F5; + case kVK_F6: + return boo::IWindowCallback::KEY_F6; + case kVK_F7: + return boo::IWindowCallback::KEY_F7; + case kVK_F8: + return boo::IWindowCallback::KEY_F8; + case kVK_F9: + return boo::IWindowCallback::KEY_F9; + case kVK_F10: + return boo::IWindowCallback::KEY_F10; + case kVK_F11: + return boo::IWindowCallback::KEY_F11; + case kVK_F12: + return boo::IWindowCallback::KEY_F12; + case kVK_Escape: + return boo::IWindowCallback::KEY_ESC; + case kVK_Return: + return boo::IWindowCallback::KEY_ENTER; + case kVK_Delete: + return boo::IWindowCallback::KEY_BACKSPACE; + case kVK_ForwardDelete: + return boo::IWindowCallback::KEY_DELETE; + case kVK_Home: + return boo::IWindowCallback::KEY_HOME; + case kVK_End: + return boo::IWindowCallback::KEY_END; + case kVK_PageUp: + return boo::IWindowCallback::KEY_PGUP; + case kVK_PageDown: + return boo::IWindowCallback::KEY_PGDOWN; + case kVK_LeftArrow: + return boo::IWindowCallback::KEY_LEFT; + case kVK_RightArrow: + return boo::IWindowCallback::KEY_RIGHT; + case kVK_UpArrow: + return boo::IWindowCallback::KEY_UP; + case kVK_DownArrow: + return boo::IWindowCallback::KEY_DOWN; + default: + return boo::IWindowCallback::KEY_NONE; + } +} + +- (void)keyDown:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSString* chars = theEvent.characters; + if ([chars length] == 0) + booContext->m_callback->specialKeyDown(translateKeycode(theEvent.keyCode), + getMod(theEvent.modifierFlags), + theEvent.isARepeat); + else + booContext->m_callback->charKeyDown([chars characterAtIndex:0], + getMod(theEvent.modifierFlags), + theEvent.isARepeat); +} + +- (void)keyUp:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSString* chars = theEvent.characters; + if ([chars length] == 0) + booContext->m_callback->specialKeyUp(translateKeycode(theEvent.keyCode), + getMod(theEvent.modifierFlags)); + else + booContext->m_callback->charKeyUp([chars characterAtIndex:0], + getMod(theEvent.modifierFlags)); +} + +- (void)flagsChanged:(NSEvent*)theEvent +{ + if (!booContext->m_callback) + return; + NSUInteger modFlags = theEvent.modifierFlags; + bool isRepeat = theEvent.isARepeat; + if (modFlags != lastModifiers) + { + NSUInteger changedFlags = modFlags ^ lastModifiers; + + NSUInteger downFlags = changedFlags & modFlags; + if (downFlags & NSControlKeyMask) + booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_CTRL, isRepeat); + if (downFlags & NSAlternateKeyMask) + booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_ALT, isRepeat); + if (downFlags & NSShiftKeyMask) + booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_SHIFT, isRepeat); + if (downFlags & NSCommandKeyMask) + booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_COMMAND, isRepeat); + + NSUInteger upFlags = changedFlags & ~modFlags; + if (upFlags & NSControlKeyMask) + booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_CTRL); + if (upFlags & NSAlternateKeyMask) + booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_ALT); + if (upFlags & NSShiftKeyMask) + booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_SHIFT); + if (upFlags & NSCommandKeyMask) + booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_COMMAND); + + lastModifiers = modFlags; + } +} + +@end + diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm new file mode 100644 index 0000000..942d9d2 --- /dev/null +++ b/lib/mac/WindowCocoa.mm @@ -0,0 +1,180 @@ +#import +#include "IApplication.hpp" +#include "windowsys/IWindow.hpp" +#include "windowsys/IGraphicsContext.hpp" + +namespace boo {class CWindowCocoa;} +@interface CWindowCocoaInternal : NSWindow +{ + boo::CWindowCocoa* booWindow; +} +- (id)initWithBooWindow:(boo::CWindowCocoa*)bw title:(const std::string&)title; +- (void)setFrameDefault; +- (NSRect)genFrameDefault; +@end + +namespace boo +{ + +IGraphicsContext* _CGraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow); + +class CWindowCocoa final : public IWindow +{ + + CWindowCocoaInternal* m_nsWindow; + IGraphicsContext* m_gfxCtx; + +public: + + CWindowCocoa(const std::string& title) + { + m_nsWindow = [[CWindowCocoaInternal alloc] initWithBooWindow:this title:title]; + m_gfxCtx = _CGraphicsContextCocoaNew(IGraphicsContext::API_OPENGL_3_3, this); + m_gfxCtx->initializeContext(); + } + + void _clearWindow() + { + m_nsWindow = NULL; + } + + ~CWindowCocoa() + { + [m_nsWindow orderOut:nil]; + [m_nsWindow release]; + delete m_gfxCtx; + IApplicationInstance()->_deletedWindow(this); + } + + void setCallback(IWindowCallback* cb) + { + m_gfxCtx->_setCallback(cb); + } + + void showWindow() + { + [m_nsWindow makeKeyAndOrderFront:nil]; + } + + void hideWindow() + { + [m_nsWindow orderOut:nil]; + } + + std::string getTitle() + { + return [[m_nsWindow title] UTF8String]; + } + + void setTitle(const std::string& title) + { + [m_nsWindow setTitle:[[NSString stringWithUTF8String:title.c_str()] autorelease]]; + } + + void setWindowFrameDefault() + { + NSScreen* mainScreen = [NSScreen mainScreen]; + NSRect scrFrame = mainScreen.frame; + float x_off = scrFrame.size.width / 3.0; + float y_off = scrFrame.size.height / 3.0; + [m_nsWindow setFrame:NSMakeRect(x_off, y_off, x_off * 2.0, y_off * 2.0) display:NO]; + } + + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const + { + NSRect wFrame = m_nsWindow.frame; + xOut = wFrame.origin.x; + yOut = wFrame.origin.y; + wOut = wFrame.size.width; + hOut = wFrame.size.height; + } + + void setWindowFrame(float x, float y, float w, float h) + { + NSRect wFrame = NSMakeRect(x, y, w, h); + [m_nsWindow setFrame:wFrame display:NO]; + } + + float getVirtualPixelFactor() const + { + return [m_nsWindow backingScaleFactor]; + } + + bool isFullscreen() const + { + return ([m_nsWindow styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask; + } + + void setFullscreen(bool fs) + { + if ((fs && !isFullscreen()) || (!fs && isFullscreen())) + [m_nsWindow toggleFullScreen:nil]; + } + + ETouchType getTouchType() const + { + return TOUCH_TRACKPAD; + } + + uintptr_t getPlatformHandle() const + { + return (uintptr_t)m_nsWindow; + } + +}; + +IWindow* _CWindowCocoaNew(const std::string& title) +{ + return new CWindowCocoa(title); +} + +} + +@implementation CWindowCocoaInternal +- (id)initWithBooWindow:(boo::CWindowCocoa *)bw title:(const std::string&)title +{ + self = [self initWithContentRect:[self genFrameDefault] + styleMask:NSTitledWindowMask| + NSClosableWindowMask| + NSMiniaturizableWindowMask| + NSResizableWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + self.title = [[NSString stringWithUTF8String:title.c_str()] autorelease]; + booWindow = bw; + return self; +} +- (void)setFrameDefault +{ + [self setFrame:[self genFrameDefault] display:NO]; +} +- (NSRect)genFrameDefault +{ + NSScreen* mainScreen = [NSScreen mainScreen]; + NSRect scrFrame = mainScreen.frame; + float width = scrFrame.size.width * 2.0 / 3.0; + float height = scrFrame.size.height * 2.0 / 3.0; + return NSMakeRect((scrFrame.size.width - width) / 2.0, + (scrFrame.size.height - height) / 2.0, + width, height); +} +- (void)close +{ + booWindow->_clearWindow(); + [super close]; +} +- (BOOL)acceptsFirstResponder +{ + return YES; +} +- (BOOL)acceptsMouseMovedEvents +{ + return YES; +} +- (NSWindowCollectionBehavior)collectionBehavior +{ + return NSWindowCollectionBehaviorFullScreenPrimary; +} +@end + diff --git a/lib/win/ApplicationWin32.cpp b/lib/win/ApplicationWin32.cpp new file mode 100644 index 0000000..ba53335 --- /dev/null +++ b/lib/win/ApplicationWin32.cpp @@ -0,0 +1,166 @@ +#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */ +#define _WIN32_LEAN_AND_MEAN 1 +#include +#include +#include + +#include + +#include "IRunLoop.hpp" +#include "inputdev/CDeviceFinder.hpp" + +namespace boo +{ + +IWindow* _CWindowWin32New(const std::string& title); + +class CApplicationWin32 final : public IApplication +{ + const IApplicationCallback& m_callback; + const std::string m_friendlyName; + const std::string m_pname; + const std::vector m_args; + std::unordered_map m_allWindows; + bool m_singleInstance; + + void _deletedWindow(IWindow* window) + { + m_allWindows.erase(window); + } + +public: + + CApplicationWin32(const IApplicationCallback& callback, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args, + bool singleInstance) + : m_callback(callback), + m_friendlyName(friendlyName), + m_pname(pname), + m_args(args), + m_singleInstance(singleInstance) + {} + + EPlatformType getPlatformType() const + { + return PLAT_WIN32; + } + + LRESULT winHwndHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + /* Lookup boo window instance */ + IWindow* window = m_allWindows[hwnd]; + switch (uMsg) + { + case WM_CREATE: + return 0; + + case WM_DEVICECHANGE: + return CDeviceFinder::winDevChangedHandler(wParam, lParam); + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + } + + void run() + { + /* Pump messages */ + MSG msg = {0}; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + const std::string& getProcessName() const + { + return m_pname; + } + + const std::vector& getArgs() const + { + return m_args; + } + + IWindow* newWindow(const std::string& title) + { + IWindow* window = _CWindowWin32New(title); + HWND hwnd = window->getPlatformHandle(); + m_allWindows[hwnd] = window; + } +}; + +IApplication* APP = NULL; +IApplication* IApplicationBootstrap(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args, + bool singleInstance) +{ + if (!APP) + { + if (platform != IApplication::PLAT_WIN32 && + platform != IApplication::PLAT_AUTO) + return NULL; + APP = new CApplicationWin32(cb, friendlyName, pname, args, singleInstance); + } + return APP; +} + +} + +static const DEV_BROADCAST_DEVICEINTERFACE_A HOTPLUG_CONF = +{ + sizeof(DEV_BROADCAST_DEVICEINTERFACE_A), + DBT_DEVTYP_DEVICEINTERFACE, + 0, + GUID_DEVINTERFACE_USB_DEVICE +}; +static bool HOTPLUG_REGISTERED = false; +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (!HOTPLUG_REGISTERED && hwnd == WM_CREATE) + { + /* Register hotplug notification with windows */ + RegisterDeviceNotificationA(hwnd, (LPVOID)&HOTPLUG_CONF, DEVICE_NOTIFY_WINDOW_HANDLE); + HOTPLUG_REGISTERED = true; + } + return IRunLoopInstance()->winHwndHandler(hwnd, uMsg, wParam, lParam); +} + +int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPCWSTR lpCmdLine, int) +{ +#if DEBUG + /* Debug console */ + AllocConsole(); + freopen("CONOUT$", "w", stdout); +#endif + + /* One class for *all* boo windows */ + WNDCLASS wndClass = + { + 0, + WindowProc, + 0, + 0, + hInstance, + 0, + 0, + 0, + 0, + L"BooWindow" + }; + + RegisterClassW(&wndClass); + + int argc = 0; + LPWSTR* argv = CommandLineToArgvW(lpCmdLine, &argc); + + /* Call into the 'proper' entry point */ + return main(argc, argv); + +} diff --git a/lib/win/GraphicsContextWin32.cpp b/lib/win/GraphicsContextWin32.cpp new file mode 100644 index 0000000..26436e9 --- /dev/null +++ b/lib/win/GraphicsContextWin32.cpp @@ -0,0 +1,83 @@ +#include "windowsys/IGraphicsContext.hpp" +#include "windowsys/IWindow.hpp" + +namespace boo +{ + +class CGraphicsContextWin32 final : public IGraphicsContext +{ + + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; + +public: + IWindowCallback* m_callback; + + CGraphicsContextWin32(EGraphicsAPI api, IWindow* parentWindow) + : m_api(api), + m_pf(PF_RGBA8), + m_parentWindow(parentWindow) + {} + + ~CGraphicsContextWin32() + { + + } + + void _setCallback(IWindowCallback* cb) + { + m_callback = cb; + } + + EGraphicsAPI getAPI() const + { + return m_api; + } + + EPixelFormat getPixelFormat() const + { + return m_pf; + } + + void setPixelFormat(EPixelFormat pf) + { + if (pf > PF_RGBAF32_Z24) + return; + m_pf = pf; + } + + void initializeContext() + { + + } + + IGraphicsContext* makeShareContext() const + { + + } + + void makeCurrent() + { + + } + + void clearCurrent() + { + + } + + void swapBuffer() + { + + } + +}; + +IGraphicsContext* _CGraphicsContextWin32New(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow) +{ + +} + +} diff --git a/lib/win/WindowWin32.cpp b/lib/win/WindowWin32.cpp new file mode 100644 index 0000000..5617358 --- /dev/null +++ b/lib/win/WindowWin32.cpp @@ -0,0 +1,96 @@ +#include "windowsys/IWindow.hpp" +#include "windowsys/IGraphicsContext.hpp" + +namespace boo +{ + +IGraphicsContext* _CGraphicsContextWin32New(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow); + +class CWindowWin32 final : public IWindow +{ + + HWND m_hwnd; + +public: + + CWindowWin32(const std::string& title) + { + m_hwnd = CreateWindowW(L"BooWindow", L"BooTest", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hInstance, NULL); + } + + ~CWindowWin32() + { + + } + + void setCallback(IWindowCallback* cb) + { + + } + + void showWindow() + { + + } + + void hideWindow() + { + + } + + std::string getTitle() + { + + } + + void setTitle(const std::string& title) + { + + } + + void setWindowFrameDefault() + { + + } + + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const + { + + } + + void setWindowFrame(float x, float y, float w, float h) + { + + } + + float getVirtualPixelFactor() const + { + + } + + bool isFullscreen() const + { + + } + + void setFullscreen(bool fs) + { + + } + + ETouchType getTouchType() const + { + + } + +}; + +IWindow* _CWindowWin32New(const std::string& title) +{ + return new CWindowWin32(title); +} + +} diff --git a/lib/x11/ApplicationUnix.cpp b/lib/x11/ApplicationUnix.cpp new file mode 100644 index 0000000..e3faf79 --- /dev/null +++ b/lib/x11/ApplicationUnix.cpp @@ -0,0 +1,71 @@ +/* Meta-implementation for dynamically-constructing user's preferred + * platform interface + */ + +#define APPLICATION_UNIX_CPP +#include "ApplicationXCB.hpp" +#include "ApplicationWayland.hpp" + +#include +#include +#include + +DBusConnection* registerDBus(const char* appName, bool& isFirst) +{ + isFirst = true; + DBusError err = {}; + dbus_error_init(&err); + + /* connect to the bus and check for errors */ + DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, &err); + if (dbus_error_is_set(&err)) + { + fprintf(stderr, "DBus Connection Error (%s)\n", err.message); + dbus_error_free(&err); + } + if (NULL == conn) + return NULL; + + /* request our name on the bus and check for errors */ + char busName[256]; + snprintf(busName, 256, "boo.%s.unique", appName); + int ret = dbus_bus_request_name(conn, busName, DBUS_NAME_FLAG_DO_NOT_QUEUE , &err); + if (dbus_error_is_set(&err)) + { + fprintf(stderr, "DBus Name Error (%s)\n", err.message); + dbus_error_free(&err); + dbus_connection_close(conn); + return NULL; + } + if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) + isFirst = false; + + return conn; + +} + +namespace boo +{ + +IApplication* APP = NULL; +std::unique_ptr ApplicationBootstrap(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const std::string& uniqueName, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args, + bool singleInstance) +{ + if (APP) + return std::unique_ptr(); + if (platform == IApplication::PLAT_WAYLAND) + APP = new ApplicationWayland(cb, uniqueName, friendlyName, pname, args, singleInstance); + else if (platform == IApplication::PLAT_XCB || + platform == IApplication::PLAT_AUTO) + APP = new ApplicationXCB(cb, uniqueName, friendlyName, pname, args, singleInstance); + else + return std::unique_ptr(); + return std::unique_ptr(APP); +} + +} diff --git a/lib/x11/ApplicationWayland.hpp b/lib/x11/ApplicationWayland.hpp new file mode 100644 index 0000000..c157bf2 --- /dev/null +++ b/lib/x11/ApplicationWayland.hpp @@ -0,0 +1,85 @@ +#ifndef APPLICATION_UNIX_CPP +#error This file may only be included from CApplicationUnix.cpp +#endif + +#include "boo/IApplication.hpp" + +#include +DBusConnection* registerDBus(const char* appName, bool& isFirst); + +namespace boo +{ + +IWindow* _CWindowWaylandNew(const std::string& title); + +class ApplicationWayland final : public IApplication +{ + IApplicationCallback& m_callback; + const std::string m_uniqueName; + const std::string m_friendlyName; + const std::string m_pname; + const std::vector m_args; + bool m_singleInstance; + + void _deletedWindow(IWindow* window) + { + (void)window; + } + +public: + ApplicationWayland(IApplicationCallback& callback, + const std::string& uniqueName, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args, + bool singleInstance) + : m_callback(callback), + m_uniqueName(uniqueName), + m_friendlyName(friendlyName), + m_pname(pname), + m_args(args), + m_singleInstance(singleInstance) + {} + + EPlatformType getPlatformType() const + { + return PLAT_WAYLAND; + } + + void run() + { + + } + + void quit() + { + + } + + const std::string& getUniqueName() const + { + return m_uniqueName; + } + + const std::string& getFriendlyName() const + { + return m_friendlyName; + } + + const std::string& getProcessName() const + { + return m_pname; + } + + const std::vector& getArgs() const + { + return m_args; + } + + IWindow* newWindow(const std::string& title) + { + return _CWindowWaylandNew(title); + } +}; + +} diff --git a/lib/x11/ApplicationXCB.hpp b/lib/x11/ApplicationXCB.hpp new file mode 100644 index 0000000..626a8f9 --- /dev/null +++ b/lib/x11/ApplicationXCB.hpp @@ -0,0 +1,334 @@ +#ifndef APPLICATION_UNIX_CPP +#error This file may only be included from CApplicationUnix.cpp +#endif + +#include "boo/IApplication.hpp" + +#define explicit explicit_c +#include +#include +#include +#include +#include +#undef explicit + +#include +DBusConnection* registerDBus(const char* appName, bool& isFirst); + +#include + +namespace boo +{ + +int XINPUT_OPCODE = 0; + +static xcb_window_t getWindowOfEvent(xcb_generic_event_t* event, bool& windowEvent) +{ + switch (XCB_EVENT_RESPONSE_TYPE(event)) + { + case XCB_CLIENT_MESSAGE: + { + xcb_client_message_event_t* ev = (xcb_client_message_event_t*)event; + windowEvent = true; + return ev->window; + } + case XCB_EXPOSE: + { + xcb_expose_event_t* ev = (xcb_expose_event_t*)event; + windowEvent = true; + return ev->window; + } + case XCB_CONFIGURE_NOTIFY: + { + xcb_configure_notify_event_t* ev = (xcb_configure_notify_event_t*)event; + windowEvent = true; + return ev->window; + } + case XCB_KEY_PRESS: + { + xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_KEY_RELEASE: + { + xcb_key_release_event_t* ev = (xcb_key_release_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_BUTTON_PRESS: + { + xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_BUTTON_RELEASE: + { + xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_MOTION_NOTIFY: + { + xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_GE_GENERIC: + { + xcb_ge_event_t* gev = (xcb_ge_event_t*)event; + if (gev->pad0 == XINPUT_OPCODE) + { + switch (gev->event_type) + { + case XCB_INPUT_MOTION: + { + xcb_input_motion_event_t* ev = (xcb_input_motion_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_INPUT_TOUCH_BEGIN: + { + xcb_input_touch_begin_event_t* ev = (xcb_input_touch_begin_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_INPUT_TOUCH_UPDATE: + { + xcb_input_touch_update_event_t* ev = (xcb_input_touch_update_event_t*)event; + windowEvent = true; + return ev->event; + } + case XCB_INPUT_TOUCH_END: + { + xcb_input_touch_end_event_t* ev = (xcb_input_touch_end_event_t*)event; + windowEvent = true; + return ev->event; + } + } + } + } + } + windowEvent = false; + return 0; +} + +IWindow* _CWindowXCBNew(const std::string& title, xcb_connection_t* conn); + +class ApplicationXCB final : public IApplication +{ + IApplicationCallback& m_callback; + const std::string m_uniqueName; + const std::string m_friendlyName; + const std::string m_pname; + const std::vector m_args; + + /* DBus single-instance */ + bool m_singleInstance; + DBusConnection* m_dbus = NULL; + + /* All windows */ + std::unordered_map m_windows; + + xcb_connection_t* m_xcbConn = NULL; + bool m_running; + + void _deletedWindow(IWindow* window) + { + m_windows.erase((xcb_window_t)window->getPlatformHandle()); + } + +public: + ApplicationXCB(IApplicationCallback& callback, + const std::string& uniqueName, + const std::string& friendlyName, + const std::string& pname, + const std::vector& args, + bool singleInstance) + : m_callback(callback), + m_uniqueName(uniqueName), + m_friendlyName(friendlyName), + m_pname(pname), + m_args(args), + m_singleInstance(singleInstance) + { + /* DBus single instance registration */ + bool isFirst; + m_dbus = registerDBus(uniqueName.c_str(), isFirst); + if (m_singleInstance) + { + if (!isFirst) + { + /* This is a duplicate instance, send signal and return */ + if (args.size()) + { + /* create a signal & check for errors */ + DBusMessage* + msg = dbus_message_new_signal("/boo/signal/FileHandler", + "boo.signal.FileHandling", + "Open"); + + /* append arguments onto signal */ + DBusMessageIter argsIter; + dbus_message_iter_init_append(msg, &argsIter); + for (const std::string& arg : args) + { + const char* sigvalue = arg.c_str(); + dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &sigvalue); + } + + /* send the message and flush the connection */ + dbus_uint32_t serial; + dbus_connection_send(m_dbus, msg, &serial); + dbus_connection_flush(m_dbus); + dbus_message_unref(msg); + } + return; + } + else + { + /* This is the first instance, register for signal */ + // add a rule for which messages we want to see + DBusError err = {}; + dbus_bus_add_match(m_dbus, "type='signal',interface='boo.signal.FileHandling'", &err); + dbus_connection_flush(m_dbus); + } + } + + /* Open X connection */ + m_xcbConn = xcb_connect(NULL, NULL); + + /* The xkb extension requests that the X server does not + * send repeated keydown events when a key is held */ + xkb_x11_setup_xkb_extension(m_xcbConn, + XKB_X11_MIN_MAJOR_XKB_VERSION, + XKB_X11_MIN_MINOR_XKB_VERSION, + XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, + NULL, NULL, NULL, NULL); + xcb_xkb_per_client_flags(m_xcbConn, XCB_XKB_ID_USE_CORE_KBD, + XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT, + XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT, 0, 0, 0); + + /* Xinput major opcode */ + const xcb_query_extension_reply_t* xiReply = + xcb_get_extension_data(m_xcbConn, &xcb_input_id); + if (xiReply) + XINPUT_OPCODE = xiReply->major_opcode; + + } + + ~ApplicationXCB() + { + xcb_disconnect(m_xcbConn); + } + + EPlatformType getPlatformType() const + { + return PLAT_XCB; + } + + void run() + { + if (!m_xcbConn) + return; + + xcb_generic_event_t* event; + m_running = true; + m_callback.appLaunched(this); + xcb_flush(m_xcbConn); + + int xcbFd = xcb_get_file_descriptor(m_xcbConn); + int dbusFd; + dbus_connection_get_unix_fd(m_dbus, &dbusFd); + int maxFd = MAX(xcbFd, dbusFd); + + while (m_running) + { + fd_set fds; + FD_ZERO(&fds); + FD_SET(xcbFd, &fds); + FD_SET(dbusFd, &fds); + select(maxFd+1, &fds, NULL, NULL, NULL); + + if (FD_ISSET(xcbFd, &fds)) + { + event = xcb_poll_for_event(m_xcbConn); + if (!event) + break; + + bool windowEvent; + xcb_window_t evWindow = getWindowOfEvent(event, windowEvent); + //fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event)); + if (windowEvent) + { + auto window = m_windows.find(evWindow); + if (window != m_windows.end()) + window->second->_incomingEvent(event); + } + free(event); + } + + if (FD_ISSET(dbusFd, &fds)) + { + DBusMessage* msg; + dbus_connection_read_write(m_dbus, 0); + while ((msg = dbus_connection_pop_message(m_dbus))) + { + /* check if the message is a signal from the correct interface and with the correct name */ + if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open")) + { + /* read the parameters */ + std::vector paths; + DBusMessageIter iter; + dbus_message_iter_init(msg, &iter); + while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) + { + const char* argVal; + dbus_message_iter_get_basic(&iter, &argVal); + paths.push_back(argVal); + dbus_message_iter_next(&iter); + } + m_callback.appFilesOpen(this, paths); + } + dbus_message_unref(msg); + } + } + } + + m_callback.appQuitting(this); + } + + void quit() + { + m_running = false; + } + + const std::string& getUniqueName() const + { + return m_uniqueName; + } + + const std::string& getFriendlyName() const + { + return m_friendlyName; + } + + const std::string& getProcessName() const + { + return m_pname; + } + + const std::vector& getArgs() const + { + return m_args; + } + + IWindow* newWindow(const std::string& title) + { + IWindow* newWindow = _CWindowXCBNew(title, m_xcbConn); + m_windows[(xcb_window_t)newWindow->getPlatformHandle()] = newWindow; + return newWindow; + } +}; + +} diff --git a/lib/x11/GraphicsContextWayland.cpp b/lib/x11/GraphicsContextWayland.cpp new file mode 100644 index 0000000..e84ae38 --- /dev/null +++ b/lib/x11/GraphicsContextWayland.cpp @@ -0,0 +1,63 @@ +#include "boo/IGraphicsContext.hpp" +#include "boo/IWindow.hpp" + +namespace boo +{ + +struct GraphicsContextWayland : IGraphicsContext +{ + + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; + +public: + IWindowCallback* m_callback; + + GraphicsContextWayland(EGraphicsAPI api, IWindow* parentWindow) + : m_api(api), + m_pf(PF_RGBA8), + m_parentWindow(parentWindow) + {} + + ~GraphicsContextWayland() + { + + } + + void _setCallback(IWindowCallback* cb) + { + m_callback = cb; + } + + EGraphicsAPI getAPI() const + { + return m_api; + } + + EPixelFormat getPixelFormat() const + { + return m_pf; + } + + void setPixelFormat(EPixelFormat pf) + { + if (pf > PF_RGBAF32_Z24) + return; + m_pf = pf; + } + + void initializeContext() + { + + } + +}; + +IGraphicsContext* _GraphicsContextWaylandNew(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow) +{ + return new GraphicsContextWayland(api, parentWindow); +} + +} diff --git a/lib/x11/GraphicsContextXCB.cpp b/lib/x11/GraphicsContextXCB.cpp new file mode 100644 index 0000000..8544e14 --- /dev/null +++ b/lib/x11/GraphicsContextXCB.cpp @@ -0,0 +1,153 @@ +#include "boo/IGraphicsContext.hpp" +#include "boo/IWindow.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace boo +{ + +struct GraphicsContextXCB : IGraphicsContext +{ + + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; + xcb_connection_t* m_xcbConn; + + xcb_glx_fbconfig_t m_fbconfig = 0; + xcb_visualid_t m_visualid = 0; + xcb_glx_window_t m_glxWindow = 0; + xcb_glx_context_t m_glxCtx = 0; + xcb_glx_context_tag_t m_glxCtxTag = 0; + + std::thread* m_commandThread = NULL; + +public: + IWindowCallback* m_callback; + + GraphicsContextXCB(EGraphicsAPI api, IWindow* parentWindow, xcb_connection_t* conn, uint32_t& visualIdOut) + : m_api(api), + m_pf(PF_RGBA8), + m_parentWindow(parentWindow), + m_xcbConn(conn) + { + + /* WTF freedesktop?? Fix this awful API and your nonexistant docs */ + xcb_glx_get_fb_configs_reply_t* fbconfigs = + xcb_glx_get_fb_configs_reply(m_xcbConn, xcb_glx_get_fb_configs(m_xcbConn, 0), NULL); + struct conf_prop + { + uint32_t key; + uint32_t val; + }* props = (struct conf_prop*)xcb_glx_get_fb_configs_property_list(fbconfigs); + + for (uint32_t i=0 ; inum_FB_configs ; ++i) + { + struct conf_prop* configProps = &props[fbconfigs->num_properties * i]; + uint32_t fbconfId, visualId, depthSize, colorSize, doubleBuffer; + for (uint32_t j=0 ; jnum_properties ; ++j) + { + struct conf_prop* prop = &configProps[j]; + if (prop->key == GLX_FBCONFIG_ID) + fbconfId = prop->val; + if (prop->key == GLX_VISUAL_ID) + visualId = prop->val; + else if (prop->key == GLX_DEPTH_SIZE) + depthSize = prop->val; + else if (prop->key == GLX_BUFFER_SIZE) + colorSize = prop->val; + else if (prop->key == GLX_DOUBLEBUFFER) + doubleBuffer = prop->val; + } + + /* Double-buffer only */ + if (!doubleBuffer) + continue; + + if (m_pf == PF_RGBA8 && colorSize >= 32) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + else if (m_pf == PF_RGBA8_Z24 && colorSize >= 32 && depthSize >= 24) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + else if (m_pf == PF_RGBAF32 && colorSize >= 128) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + else if (m_pf == PF_RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + } + free(fbconfigs); + + if (!m_fbconfig) + { + fprintf(stderr, "unable to find suitable pixel format"); + return; + } + + visualIdOut = m_visualid; + } + + ~GraphicsContextXCB() + { + + } + + void _setCallback(IWindowCallback* cb) + { + m_callback = cb; + } + + EGraphicsAPI getAPI() const + { + return m_api; + } + + EPixelFormat getPixelFormat() const + { + return m_pf; + } + + void setPixelFormat(EPixelFormat pf) + { + if (pf > PF_RGBAF32_Z24) + return; + m_pf = pf; + } + + void initializeContext() + { + m_glxWindow = xcb_generate_id(m_xcbConn); + xcb_glx_create_window(m_xcbConn, 0, m_fbconfig, + m_parentWindow->getPlatformHandle(), + m_glxWindow, 0, NULL); + } + +}; + +IGraphicsContext* _GraphicsContextXCBNew(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow, xcb_connection_t* conn, + uint32_t& visualIdOut) +{ + return new GraphicsContextXCB(api, parentWindow, conn, visualIdOut); +} + +} diff --git a/lib/x11/WindowWayland.cpp b/lib/x11/WindowWayland.cpp new file mode 100644 index 0000000..442836d --- /dev/null +++ b/lib/x11/WindowWayland.cpp @@ -0,0 +1,94 @@ +#include "boo/IWindow.hpp" +#include "boo/IGraphicsContext.hpp" + +namespace boo +{ + +IGraphicsContext* _CGraphicsContextWaylandNew(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow); + +struct WindowWayland : IWindow +{ + WindowWayland(const std::string& title) + { + + } + + ~WindowWayland() + { + + } + + void setCallback(IWindowCallback* cb) + { + + } + + void showWindow() + { + + } + + void hideWindow() + { + + } + + std::string getTitle() + { + + } + + void setTitle(const std::string& title) + { + + } + + void setWindowFrameDefault() + { + + } + + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const + { + + } + + void setWindowFrame(float x, float y, float w, float h) + { + + } + + float getVirtualPixelFactor() const + { + + } + + bool isFullscreen() const + { + + } + + void setFullscreen(bool fs) + { + + } + + uintptr_t getPlatformHandle() const + { + + } + + ETouchType getTouchType() const + { + + } + +}; + +IWindow* _CWindowWaylandNew(const std::string& title) +{ + return new WindowWayland(title); +} + +} diff --git a/lib/x11/WindowXCB.cpp b/lib/x11/WindowXCB.cpp new file mode 100644 index 0000000..b2200ec --- /dev/null +++ b/lib/x11/WindowXCB.cpp @@ -0,0 +1,770 @@ +#include "boo/IWindow.hpp" +#include "boo/IGraphicsContext.hpp" +#include "boo/IApplication.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define XK_MISCELLANY +#define XK_XKB_KEYS +#define XK_LATIN1 +#include + +#define REF_DPMM 3.7824 /* 96 DPI */ +#define FS_ATOM "_NET_WM_STATE_FULLSCREEN" + +namespace boo +{ + +extern int XINPUT_OPCODE; + +static inline double fp3232val(xcb_input_fp3232_t* val) +{ + return val->integral + val->frac / (double)UINT_MAX; +} + +static uint32_t translateKeysym(xcb_keysym_t sym, int& specialSym, int& modifierSym) +{ + specialSym = IWindowCallback::KEY_NONE; + modifierSym = IWindowCallback::MKEY_NONE; + if (sym >= XK_F1 && sym <= XK_F12) + specialSym = IWindowCallback::KEY_F1 + sym - XK_F1; + else if (sym == XK_Escape) + specialSym = IWindowCallback::KEY_ESC; + else if (sym == XK_Return) + specialSym = IWindowCallback::KEY_ENTER; + else if (sym == XK_BackSpace) + specialSym = IWindowCallback::KEY_BACKSPACE; + else if (sym == XK_Insert) + specialSym = IWindowCallback::KEY_INSERT; + else if (sym == XK_Delete) + specialSym = IWindowCallback::KEY_DELETE; + else if (sym == XK_Home) + specialSym = IWindowCallback::KEY_HOME; + else if (sym == XK_End) + specialSym = IWindowCallback::KEY_END; + else if (sym == XK_Page_Up) + specialSym = IWindowCallback::KEY_PGUP; + else if (sym == XK_Page_Down) + specialSym = IWindowCallback::KEY_PGDOWN; + else if (sym == XK_Left) + specialSym = IWindowCallback::KEY_LEFT; + else if (sym == XK_Right) + specialSym = IWindowCallback::KEY_RIGHT; + else if (sym == XK_Up) + specialSym = IWindowCallback::KEY_UP; + else if (sym == XK_Down) + specialSym = IWindowCallback::KEY_DOWN; + else if (sym == XK_Shift_L || sym == XK_Shift_R) + modifierSym = IWindowCallback::MKEY_SHIFT; + else if (sym == XK_Control_L || sym == XK_Control_R) + modifierSym = IWindowCallback::MKEY_CTRL; + else if (sym == XK_Alt_L || sym == XK_Alt_R) + modifierSym = IWindowCallback::MKEY_ALT; + else + return xkb_keysym_to_utf32(sym); + return 0; +} + +static int translateModifiers(unsigned state) +{ + int retval = 0; + if (state & XCB_MOD_MASK_SHIFT) + retval |= IWindowCallback::MKEY_SHIFT; + if (state & XCB_MOD_MASK_CONTROL) + retval |= IWindowCallback::MKEY_CTRL; + if (state & XCB_MOD_MASK_1) + retval |= IWindowCallback::MKEY_ALT; + return retval; +} + +static int translateButton(unsigned detail) +{ + int retval = 0; + if (detail == 1) + retval = IWindowCallback::BUTTON_PRIMARY; + else if (detail == 3) + retval = IWindowCallback::BUTTON_SECONDARY; + else if (detail == 2) + retval = IWindowCallback::BUTTON_MIDDLE; + else if (detail == 8) + retval = IWindowCallback::BUTTON_AUX1; + else if (detail == 9) + retval = +IWindowCallback::BUTTON_AUX2; + return retval; +} + +#define INTERN_ATOM(var, conn, name, if_exists) \ +do {\ + xcb_intern_atom_cookie_t cookie = \ + xcb_intern_atom(conn, if_exists, sizeof(#name), #name); \ + xcb_intern_atom_reply_t* reply = \ + xcb_intern_atom_reply(conn, cookie, NULL); \ + var = reply->atom; \ + free(reply); \ +} while(0) + +struct XCBAtoms +{ + xcb_atom_t m_wmProtocols = 0; + xcb_atom_t m_wmDeleteWindow = 0; + xcb_atom_t m_netwmState = 0; + xcb_atom_t m_netwmStateFullscreen = 0; + xcb_atom_t m_netwmStateAdd = 0; + xcb_atom_t m_netwmStateRemove = 0; + xcb_key_symbols_t* m_keySyms = NULL; + XCBAtoms(xcb_connection_t* conn) + { + INTERN_ATOM(m_wmProtocols, conn, WM_PROTOCOLS, 1); + INTERN_ATOM(m_wmDeleteWindow, conn, WM_DELETE_WINDOW, 1); + INTERN_ATOM(m_netwmState, conn, _NET_WM_STATE, 0); + INTERN_ATOM(m_netwmStateFullscreen, conn, _NET_WM_STATE_FULLSCREEN, 0); + INTERN_ATOM(m_netwmStateAdd, conn, _NET_WM_STATE_ADD, 0); + INTERN_ATOM(m_netwmStateRemove, conn, _NET_WM_STATE_REMOVE, 0); + m_keySyms = xcb_key_symbols_alloc(conn); + } +}; +static XCBAtoms* S_ATOMS = NULL; + +static void genFrameDefault(xcb_screen_t* screen, int* xOut, int* yOut, int* wOut, int* hOut) +{ + float width = screen->width_in_pixels * 2.0 / 3.0; + float height = screen->height_in_pixels * 2.0 / 3.0; + *xOut = (screen->width_in_pixels - width) / 2.0; + *yOut = (screen->height_in_pixels - height) / 2.0; + *wOut = width; + *hOut = height; +} + +IGraphicsContext* _GraphicsContextXCBNew(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow, xcb_connection_t* conn, + uint32_t& visualIdOut); + +struct WindowXCB : IWindow +{ + xcb_connection_t* m_xcbConn; + xcb_window_t m_windowId; + IGraphicsContext* m_gfxCtx; + IWindowCallback* m_callback; + + /* Last known input device id (0xffff if not yet set) */ + xcb_input_device_id_t m_lastInputID = 0xffff; + ETouchType m_touchType = TOUCH_NONE; + + /* Scroll valuators */ + int m_hScrollValuator = -1; + int m_vScrollValuator = -1; + double m_hScrollLast = 0.0; + double m_vScrollLast = 0.0; + + /* Cached window rectangle (to avoid repeated X queries) */ + int m_wx, m_wy, m_ww, m_wh; + float m_pixelFactor; + +public: + + WindowXCB(const std::string& title, xcb_connection_t* conn) + : m_xcbConn(conn), m_callback(NULL) + { + if (!S_ATOMS) + S_ATOMS = new XCBAtoms(conn); + + /* Default screen */ + xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(m_xcbConn)).data; + m_pixelFactor = screen->width_in_pixels / (float)screen->width_in_millimeters / REF_DPMM; + + /* Construct graphics context */ + uint32_t visualId; + m_gfxCtx = _GraphicsContextXCBNew(IGraphicsContext::API_OPENGL_3_3, this, m_xcbConn, visualId); + + /* Create colormap */ + xcb_colormap_t colormap = xcb_generate_id(m_xcbConn); + xcb_create_colormap(m_xcbConn, XCB_COLORMAP_ALLOC_NONE, + colormap, screen->root, visualId); + + /* Create window */ + int x, y, w, h; + genFrameDefault(screen, &x, &y, &w, &h); + uint32_t valueMasks[] = + { + XCB_NONE, + XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY, + colormap, + XCB_NONE + }; + m_windowId = xcb_generate_id(conn); + xcb_create_window(m_xcbConn, XCB_COPY_FROM_PARENT, m_windowId, screen->root, + x, y, w, h, 10, + XCB_WINDOW_CLASS_INPUT_OUTPUT, visualId, + XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP, + valueMasks); + + /* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */ + xcb_generic_error_t* xiErr = NULL; + xcb_input_xi_query_version_reply_t* xiReply = + xcb_input_xi_query_version_reply(m_xcbConn, + xcb_input_xi_query_version(m_xcbConn, 2, 1), &xiErr); + if (!xiErr) + { + struct + { + xcb_input_event_mask_t mask; + uint32_t maskVal; + } masks = + { + {XCB_INPUT_DEVICE_ALL_MASTER, 1}, + XCB_INPUT_XI_EVENT_MASK_MOTION | + XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN | + XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE | + XCB_INPUT_XI_EVENT_MASK_TOUCH_END + }; + xcb_input_xi_select_events(m_xcbConn, m_windowId, 1, &masks.mask); + } + free(xiReply); + + /* Register netwm extension atom for window closing */ +#if 0 + xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, S_ATOMS->m_wmProtocols, + XCB_ATOM_ATOM, 32, 1, &S_ATOMS->m_wmDeleteWindow); + const xcb_atom_t wm_protocols[1] = { + S_ATOMS->m_wmDeleteWindow, + }; + xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, + S_ATOMS->m_wmProtocols, 4, + 32, 1, wm_protocols); +#endif + + /* Set the title of the window */ + const char* c_title = title.c_str(); + xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, + XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, + strlen(c_title), c_title); + + /* Set the title of the window icon */ + xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, + XCB_ATOM_WM_ICON_NAME, XCB_ATOM_STRING, 8, + strlen(c_title), c_title); + + /* Initialize context */ + xcb_map_window(m_xcbConn, m_windowId); + xcb_flush(m_xcbConn); + + m_gfxCtx->initializeContext(); + } + + ~WindowXCB() + { + APP->_deletedWindow(this); + } + + void setCallback(IWindowCallback* cb) + { + m_callback = cb; + } + + void showWindow() + { + xcb_map_window(m_xcbConn, m_windowId); + xcb_flush(m_xcbConn); + } + + void hideWindow() + { + xcb_unmap_window(m_xcbConn, m_windowId); + xcb_flush(m_xcbConn); + } + + std::string getTitle() + { + xcb_get_property_cookie_t cookie = + xcb_get_property(m_xcbConn, 0, m_windowId, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 64); + xcb_get_property_reply_t* reply = + xcb_get_property_reply(m_xcbConn, cookie, NULL); + std::string retval((const char*)xcb_get_property_value(reply)); + free(reply); + return retval; + } + + void setTitle(const std::string& title) + { + const char* c_title = title.c_str(); + xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, + XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, + strlen(c_title), c_title); + } + + void setWindowFrameDefault() + { + int x, y, w, h; + xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(m_xcbConn)).data; + genFrameDefault(screen, &x, &y, &w, &h); + uint32_t values[] = {(uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h}; + xcb_configure_window(m_xcbConn, m_windowId, + XCB_CONFIG_WINDOW_X | + XCB_CONFIG_WINDOW_Y | + XCB_CONFIG_WINDOW_WIDTH | + XCB_CONFIG_WINDOW_HEIGHT, + values); + } + + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const + { + xOut = m_wx; + yOut = m_wy; + wOut = m_ww; + hOut = m_wh; + } + + void setWindowFrame(float x, float y, float w, float h) + { + uint32_t values[] = {(uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h}; + xcb_configure_window(m_xcbConn, m_windowId, + XCB_CONFIG_WINDOW_X | + XCB_CONFIG_WINDOW_Y | + XCB_CONFIG_WINDOW_WIDTH | + XCB_CONFIG_WINDOW_HEIGHT, + values); + } + + float getVirtualPixelFactor() const + { + return m_pixelFactor; + } + + bool isFullscreen() const + { + xcb_get_property_cookie_t cookie = + xcb_get_property(m_xcbConn, 0, m_windowId, S_ATOMS->m_netwmState, XCB_ATOM_ATOM, 0, 32); + xcb_get_property_reply_t* reply = + xcb_get_property_reply(m_xcbConn, cookie, NULL); + char* props = (char*)xcb_get_property_value(reply); + char fullscreen = false; + for (unsigned i=0 ; ilength/4 ; ++i) + { + if ((xcb_atom_t)props[i] == S_ATOMS->m_netwmStateFullscreen) + { + fullscreen = true; + break; + } + } + free(reply); + return fullscreen; + } + + void setFullscreen(bool fs) + { + xcb_client_message_event_t fsEvent = + { + XCB_CLIENT_MESSAGE, + 32, + 0, + m_windowId, + S_ATOMS->m_netwmState, + {} + }; + fsEvent.data.data32[0] = fs ? S_ATOMS->m_netwmStateAdd : S_ATOMS->m_netwmStateRemove; + fsEvent.data.data32[1] = S_ATOMS->m_netwmStateFullscreen; + xcb_send_event(m_xcbConn, 0, m_windowId, + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)&fsEvent); + } + + uintptr_t getPlatformHandle() const + { + return (uintptr_t)m_windowId; + } + + void _pointingDeviceChanged(xcb_input_device_id_t deviceId) + { + xcb_input_xi_query_device_reply_t* reply = + xcb_input_xi_query_device_reply(m_xcbConn, xcb_input_xi_query_device(m_xcbConn, deviceId), NULL); + + xcb_input_xi_device_info_iterator_t infoIter = xcb_input_xi_query_device_infos_iterator(reply); + while (infoIter.rem) + { + /* First iterate classes for scrollables */ + xcb_input_device_class_iterator_t classIter = + xcb_input_xi_device_info_classes_iterator(infoIter.data); + int hScroll = -1; + int vScroll = -1; + m_hScrollLast = 0.0; + m_vScrollLast = 0.0; + m_hScrollValuator = -1; + m_vScrollValuator = -1; + while (classIter.rem) + { + if (classIter.data->type == XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL) + { + xcb_input_scroll_class_t* scrollClass = (xcb_input_scroll_class_t*)classIter.data; + if (scrollClass->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) + vScroll = scrollClass->number; + else if (scrollClass->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) + hScroll = scrollClass->number; + } + xcb_input_device_class_next(&classIter); + } + + /* Next iterate for touch and scroll valuators */ + classIter = xcb_input_xi_device_info_classes_iterator(infoIter.data); + while (classIter.rem) + { + if (classIter.data->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR) + { + xcb_input_valuator_class_t* valClass = (xcb_input_valuator_class_t*)classIter.data; + if (valClass->number == vScroll) + { + m_vScrollLast = fp3232val(&valClass->value); + m_vScrollValuator = vScroll; + } + else if (valClass->number == hScroll) + { + m_hScrollLast = fp3232val(&valClass->value); + m_hScrollValuator = hScroll; + } + } + else if (classIter.data->type == XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH) + { + xcb_input_touch_class_t* touchClass = (xcb_input_touch_class_t*)classIter.data; + if (touchClass->mode == XCB_INPUT_TOUCH_MODE_DIRECT) + m_touchType = TOUCH_DISPLAY; + else if (touchClass->mode == XCB_INPUT_TOUCH_MODE_DEPENDENT) + m_touchType = TOUCH_TRACKPAD; + else + m_touchType = TOUCH_NONE; + } + xcb_input_device_class_next(&classIter); + } + xcb_input_xi_device_info_next(&infoIter); + } + + free(reply); + m_lastInputID = deviceId; + } + + void _incomingEvent(void* e) + { + xcb_generic_event_t* event = (xcb_generic_event_t*)e; + switch (XCB_EVENT_RESPONSE_TYPE(event)) + { + case XCB_EXPOSE: + { + xcb_expose_event_t* ev = (xcb_expose_event_t*)event; + m_wx = ev->x; + m_wy = ev->y; + m_ww = ev->width; + m_wh = ev->height; + return; + } + case XCB_CONFIGURE_NOTIFY: + { + xcb_configure_notify_event_t* ev = (xcb_configure_notify_event_t*)event; + if (ev->width && ev->height) + { + m_wx = ev->x; + m_wy = ev->y; + m_ww = ev->width; + m_wh = ev->height; + } + return; + } + case XCB_KEY_PRESS: + { + xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event; + if (m_callback) + { + int specialKey; + int modifierKey; + wchar_t charCode = translateKeysym(xcb_key_press_lookup_keysym(S_ATOMS->m_keySyms, ev, 0), + specialKey, modifierKey); + int modifierMask = translateModifiers(ev->state); + if (charCode) + m_callback->charKeyDown(charCode, + (IWindowCallback::EModifierKey)modifierMask, false); + else if (specialKey) + m_callback->specialKeyDown((IWindowCallback::ESpecialKey)specialKey, + (IWindowCallback::EModifierKey)modifierMask, false); + else if (modifierKey) + m_callback->modKeyDown((IWindowCallback::EModifierKey)modifierKey, false); + } + return; + } + case XCB_KEY_RELEASE: + { + xcb_key_release_event_t* ev = (xcb_key_release_event_t*)event; + if (m_callback) + { + int specialKey; + int modifierKey; + wchar_t charCode = translateKeysym(xcb_key_release_lookup_keysym(S_ATOMS->m_keySyms, ev, 0), + specialKey, modifierKey); + int modifierMask = translateModifiers(ev->state); + if (charCode) + m_callback->charKeyUp(charCode, + (IWindowCallback::EModifierKey)modifierMask); + else if (specialKey) + m_callback->specialKeyUp((IWindowCallback::ESpecialKey)specialKey, + (IWindowCallback::EModifierKey)modifierMask); + else if (modifierKey) + m_callback->modKeyUp((IWindowCallback::EModifierKey)modifierKey); + } + return; + } + case XCB_BUTTON_PRESS: + { + xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event; + if (m_callback) + { + int button = translateButton(ev->detail); + if (button) + { + int modifierMask = translateModifiers(ev->state); + IWindowCallback::SWindowCoord coord = + { + {(unsigned)ev->event_x, (unsigned)ev->event_y}, + {(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)}, + {ev->event_x / (float)m_ww, ev->event_y / (float)m_wh} + }; + m_callback->mouseDown(coord, (IWindowCallback::EMouseButton)button, + (IWindowCallback::EModifierKey)modifierMask); + } + + /* Also handle legacy scroll events here */ + if (ev->detail >= 4 && ev->detail <= 7 && + m_hScrollValuator == -1 && m_vScrollValuator == -1) + { + IWindowCallback::SWindowCoord coord = + { + {(unsigned)ev->event_x, (unsigned)ev->event_y}, + {(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)}, + {ev->event_x / (float)m_ww, ev->event_y / (float)m_wh} + }; + IWindowCallback::SScrollDelta scrollDelta = + { + {0.0, 0.0}, + false + }; + if (ev->detail == 4) + scrollDelta.delta[1] = 1.0; + else if (ev->detail == 5) + scrollDelta.delta[1] = -1.0; + else if (ev->detail == 6) + scrollDelta.delta[0] = 1.0; + else if (ev->detail == 7) + scrollDelta.delta[0] = -1.0; + m_callback->scroll(coord, scrollDelta); + } + } + return; + } + case XCB_BUTTON_RELEASE: + { + xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event; + if (m_callback) + { + int button = translateButton(ev->detail); + if (button) + { + int modifierMask = translateModifiers(ev->state); + IWindowCallback::SWindowCoord coord = + { + {(unsigned)ev->event_x, (unsigned)ev->event_y}, + {(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)}, + {ev->event_x / (float)m_ww, ev->event_y / (float)m_wh} + }; + m_callback->mouseUp(coord, (IWindowCallback::EMouseButton)button, + (IWindowCallback::EModifierKey)modifierMask); + } + } + return; + } + case XCB_MOTION_NOTIFY: + { + xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*)event; + if (m_callback) + { + IWindowCallback::SWindowCoord coord = + { + {(unsigned)ev->event_x, (unsigned)ev->event_y}, + {(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)}, + {ev->event_x / (float)m_ww, ev->event_y / (float)m_wh} + }; + m_callback->mouseMove(coord); + } + return; + } + case XCB_GE_GENERIC: + { + xcb_ge_event_t* gev = (xcb_ge_event_t*)event; + if (gev->pad0 == XINPUT_OPCODE) + { + switch (gev->event_type) + { + case XCB_INPUT_MOTION: + { + xcb_input_motion_event_t* ev = (xcb_input_motion_event_t*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len); + xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len); + int cv = 0; + double newScroll[2] = {m_hScrollLast, m_vScrollLast}; + bool didScroll = false; + for (int i=0 ; i<32 ; ++i) + { + if (valuators[0] & (1<event_x >> 16; + unsigned event_y = ev->event_y >> 16; + IWindowCallback::SWindowCoord coord = + { + {event_x, event_y}, + {(unsigned)(event_x / m_pixelFactor), (unsigned)(event_y / m_pixelFactor)}, + {event_x / (float)m_ww, event_y / (float)m_wh} + }; + m_callback->scroll(coord, scrollDelta); + } + return; + } + case XCB_INPUT_TOUCH_BEGIN: + { + xcb_input_touch_begin_event_t* ev = (xcb_input_touch_begin_event_t*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len); + xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len); + int cv = 0; + double vals[32] = {}; + for (int i=0 ; i<32 ; ++i) + { + if (valuators[0] & (1<touchDown(coord, ev->detail); + return; + } + case XCB_INPUT_TOUCH_UPDATE: + { + xcb_input_touch_update_event_t* ev = (xcb_input_touch_update_event_t*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len); + xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len); + int cv = 0; + double vals[32] = {}; + for (int i=0 ; i<32 ; ++i) + { + if (valuators[0] & (1<touchMove(coord, ev->detail); + return; + } + case XCB_INPUT_TOUCH_END: + { + xcb_input_touch_end_event_t* ev = (xcb_input_touch_end_event_t*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len); + xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len); + int cv = 0; + double vals[32] = {}; + for (int i=0 ; i<32 ; ++i) + { + if (valuators[0] & (1<touchUp(coord, ev->detail); + return; + } + } + } + } + } + } + + ETouchType getTouchType() const + { + return m_touchType; + } + +}; + +IWindow* _CWindowXCBNew(const std::string& title, xcb_connection_t* conn) +{ + return new WindowXCB(title, conn); +} + +} diff --git a/libBoo.pri b/libBoo.pri deleted file mode 100644 index f589cd3..0000000 --- a/libBoo.pri +++ /dev/null @@ -1,75 +0,0 @@ -HEADERS += \ - $$PWD/include/boo.hpp \ - $$PWD/include/IGraphicsContext.hpp \ - $$PWD/include/ISurface.hpp \ - $$PWD/include/CSurface.hpp \ - $$PWD/include/IRetraceWaiter.hpp \ - $$PWD/include/IInputWaiter.hpp \ - $$PWD/include/CInputRelay.hpp \ - $$PWD/include/CInputDeferredRelay.hpp \ - $$PWD/include/inputdev/CDolphinSmashAdapter.hpp \ - $$PWD/include/inputdev/CRevolutionPad.hpp \ - $$PWD/include/inputdev/CCafeProPad.hpp \ - $$PWD/include/inputdev/CDualshockPad.hpp \ - $$PWD/include/inputdev/CGenericPad.hpp \ - $$PWD/include/inputdev/CDeviceFinder.hpp \ - $$PWD/include/inputdev/CDeviceToken.hpp \ - $$PWD/include/inputdev/CDeviceBase.hpp \ - $$PWD/include/inputdev/IHIDListener.hpp \ - $$PWD/src/inputdev/IHIDDevice.hpp \ - $$PWD/include/inputdev/SDeviceSignature.hpp - -SOURCES += \ - $$PWD/InputDeviceClasses.cpp \ - $$PWD/src/CSurface.cpp \ - $$PWD/src/CRetraceWaiter.cpp \ - $$PWD/src/CInputRelay.cpp \ - $$PWD/src/CInputDeferredRelay.cpp \ - $$PWD/src/inputdev/CDolphinSmashAdapter.cpp \ - $$PWD/src/inputdev/CRevolutionPad.cpp \ - $$PWD/src/inputdev/CCafeProPad.cpp \ - $$PWD/src/inputdev/CDualshockPad.cpp \ - $$PWD/src/inputdev/CGenericPad.cpp \ - $$PWD/src/inputdev/CDeviceBase.cpp \ - $$PWD/src/inputdev/SDeviceSignature.cpp - -unix:!macx { - HEADERS += \ - $$PWD/include/x11/CGLXContext.hpp - - SOURCES += \ - $$PWD/src/x11/CGLXContext.cpp -} - -linux { - SOURCES += \ - $$PWD/src/inputdev/CHIDListenerUdev.cpp \ - $$PWD/src/inputdev/CHIDDeviceUdev.cpp - - LIBS += -ludev -} - -macx { - HEADERS += \ - $$PWD/include/mac/CCGLContext.hpp - - SOURCES += \ - $$PWD/src/mac/CCGLContext.cpp \ - $$PWD/src/inputdev/CHIDDeviceIOKit.cpp \ - $$PWD/src/inputdev/CHIDListenerIOKit.cpp - - OBJECTIVE_SOURCES += \ - $$PWD/src/mac/CCGLCocoaView.mm -} - -win32 { - HEADERS += \ - $$PWD/include/win/CWGLContext.hpp - SOURCES += \ - $$PWD/src/win/CWGLContext.cpp \ - $$PWD/src/inputdev/CHIDListenerWinUSB.cpp \ - $$PWD/src/inputdev/CHIDDeviceWinUSB.cpp -} - -INCLUDEPATH += $$PWD/include - diff --git a/src/CInputDeferredRelay.cpp b/src/CInputDeferredRelay.cpp deleted file mode 100644 index 7fed569..0000000 --- a/src/CInputDeferredRelay.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CInputDeferredRelay.hpp" \ No newline at end of file diff --git a/src/CInputRelay.cpp b/src/CInputRelay.cpp deleted file mode 100644 index 2d38700..0000000 --- a/src/CInputRelay.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CInputRelay.hpp" \ No newline at end of file diff --git a/src/CQtOpenGLWindow.cpp b/src/CQtOpenGLWindow.cpp deleted file mode 100644 index 07d3ba2..0000000 --- a/src/CQtOpenGLWindow.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "CQtOpenGLWindow.hpp" - - diff --git a/src/CRetraceWaiter.cpp b/src/CRetraceWaiter.cpp deleted file mode 100644 index 6734c86..0000000 --- a/src/CRetraceWaiter.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "IRetraceWaiter.hpp" diff --git a/src/CSurface.cpp b/src/CSurface.cpp deleted file mode 100644 index e23af70..0000000 --- a/src/CSurface.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "CSurface.hpp" - -namespace boo -{ - -ISurface* CSurfaceNewWindow() -{ - return nullptr; -} - -ISurface* CSurfaceNewQWidget() -{ - return nullptr; -} - -} diff --git a/src/inputdev/CCafeProPad.cpp b/src/inputdev/CCafeProPad.cpp deleted file mode 100644 index bcedf76..0000000 --- a/src/inputdev/CCafeProPad.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "inputdev/CCafeProPad.hpp" diff --git a/src/inputdev/CDeviceBase.cpp b/src/inputdev/CDeviceBase.cpp deleted file mode 100644 index c182bb3..0000000 --- a/src/inputdev/CDeviceBase.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "inputdev/CDeviceBase.hpp" -#include "inputdev/CDeviceToken.hpp" -#include "IHIDDevice.hpp" -#include - -namespace boo -{ - -CDeviceBase::CDeviceBase(CDeviceToken* token) -: m_token(token), m_hidDev(NULL) -{ -} - -CDeviceBase::~CDeviceBase() -{ - delete m_hidDev; -} - -void CDeviceBase::_deviceDisconnected() -{ - deviceDisconnected(); - m_token = NULL; - if (m_hidDev) - { - m_hidDev->_deviceDisconnected(); - delete m_hidDev; - m_hidDev = NULL; - } -} - -void CDeviceBase::closeDevice() -{ - if (m_token) - m_token->_deviceClose(); -} - -void CDeviceBase::deviceError(const char* error, ...) -{ - va_list vl; - va_start(vl, error); - vfprintf(stderr, error, vl); - va_end(vl); -} - -bool CDeviceBase::sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) -{ - if (m_hidDev) - return m_hidDev->_sendUSBInterruptTransfer(pipe, data, length); - return false; -} - -size_t CDeviceBase::receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) -{ - if (m_hidDev) - return m_hidDev->_receiveUSBInterruptTransfer(pipe, data, length); - return false; -} - -bool CDeviceBase::sendHIDReport(const uint8_t* data, size_t length, uint16_t message) -{ - if (m_hidDev) - return m_hidDev->_sendHIDReport(data, length, message); - return false; -} - -size_t CDeviceBase::receiveReport(uint8_t* data, size_t length, uint16_t message) -{ - if (m_hidDev) - return m_hidDev->_recieveReport(data, length, message); - return false; -} - -} diff --git a/src/inputdev/CGenericPad.cpp b/src/inputdev/CGenericPad.cpp deleted file mode 100644 index dc12a3e..0000000 --- a/src/inputdev/CGenericPad.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "inputdev/CGenericPad.hpp" -#include "inputdev/CDeviceToken.hpp" - -namespace boo -{ - -CGenericPad::CGenericPad(CDeviceToken* token) - : CDeviceBase(token) -{ - -} - -CGenericPad::~CGenericPad() -{ - -} - -void CGenericPad::deviceDisconnected() -{ - -} - -} diff --git a/src/inputdev/CRevolutionPad.cpp b/src/inputdev/CRevolutionPad.cpp deleted file mode 100644 index cd0e214..0000000 --- a/src/inputdev/CRevolutionPad.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "inputdev/CRevolutionPad.hpp" diff --git a/src/mac/CCGLContext.cpp b/src/mac/CCGLContext.cpp deleted file mode 100644 index 7e3217c..0000000 --- a/src/mac/CCGLContext.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifdef __APPLE__ -#include "CCGLContext.hpp" -#include - -namespace boo -{ - -CCGLContext::CCGLContext() - : m_minVersion(3), - m_majVersion(3) -{ - std::cout << "Hello from CGL" << std::endl; -} - -CCGLContext::~CCGLContext() -{ - -} - -bool CCGLContext::create() -{ - return true; -} - -void CCGLContext::setMinVersion(const int& min) -{ - m_minVersion = min; -} - -void CCGLContext::setMajorVersion(const int& maj) -{ - m_majVersion = maj; -} - -const std::string CCGLContext::version() const -{ - return "Invalid version"; -} - -const std::string CCGLContext::name() const -{ - return "GLX Context"; -} - -int CCGLContext::depthSize() const -{ - return -1; -} - -int CCGLContext::redDepth() const -{ - return -1; -} - -int CCGLContext::greenDepth() const -{ - return -1; -} - -int CCGLContext::blueDepth() const -{ - return -1; -} - -} - -#endif \ No newline at end of file diff --git a/src/win/CWGLContext.cpp b/src/win/CWGLContext.cpp deleted file mode 100644 index dfdd625..0000000 --- a/src/win/CWGLContext.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#ifdef _WIN32 -#include "win/CWGLContext.hpp" - -#endif diff --git a/src/x11/CGLXContext.cpp b/src/x11/CGLXContext.cpp deleted file mode 100644 index f1e42e2..0000000 --- a/src/x11/CGLXContext.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#if !defined(__APPLE__) && (defined(__linux__) || defined(BSD)) -#include "x11/CGLXContext.hpp" -#include - -namespace boo -{ - -CGLXContext::CGLXContext() - : m_majVersion(3), - m_minVersion(3), - m_display(nullptr) -{ - std::cout << "Hello from GLX" << std::endl; -} - -bool CGLXContext::create() -{ - return true; -} - -void CGLXContext::setMinVersion(const int& min) -{ - m_minVersion = min; -} - -void CGLXContext::setMajorVersion(const int& maj) -{ - m_majVersion = maj; -} - -const std::string CGLXContext::version() const -{ - return "Invalid version"; -} - -const std::string CGLXContext::name() const -{ - return "GLX Context"; -} - -int CGLXContext::depthSize() const -{ - return -1; -} - -int CGLXContext::redDepth() const -{ - return -1; -} - -int CGLXContext::greenDepth() const -{ - return -1; -} - -int CGLXContext::blueDepth() const -{ - return -1; -} - -} - -#endif // !defined(__APPLE__) && (defined(__linux__) || defined(BSD)) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..1eaf7b6 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(booTest main.cpp) +target_link_libraries(booTest Boo ${BOO_SYS_LIBS}) diff --git a/test/main.cpp b/test/main.cpp index b172a16..75724c6 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,49 +1,34 @@ -#define _CRT_SECURE_NO_WARNINGS 1 - -#if __APPLE__ -#include -#else -#endif #include -#include -#include -#if _WIN32 -#define _WIN32_LEAN_AND_MEAN 1 -#include -#include -#include -#else -#include -#endif +#include namespace boo { -class CDolphinSmashAdapterCallback : public IDolphinSmashAdapterCallback +class DolphinSmashAdapterCallback : public IDolphinSmashAdapterCallback { - void controllerConnected(unsigned idx, EDolphinControllerType type) + void controllerConnected(unsigned idx, EDolphinControllerType) { printf("CONTROLLER %u CONNECTED\n", idx); } - void controllerDisconnected(unsigned idx, EDolphinControllerType type) + void controllerDisconnected(unsigned idx, EDolphinControllerType) { printf("CONTROLLER %u DISCONNECTED\n", idx); } - void controllerUpdate(unsigned idx, EDolphinControllerType type, - const SDolphinControllerState& state) + void controllerUpdate(unsigned idx, EDolphinControllerType, + const DolphinControllerState& state) { printf("CONTROLLER %u UPDATE %d %d\n", idx, state.m_leftStick[0], state.m_leftStick[1]); printf(" %d %d\n", state.m_rightStick[0], state.m_rightStick[1]); } }; -class CDualshockControllerCallback : public IDualshockControllerCallback +class DualshockPadCallback : public IDualshockControllerCallback { void controllerDisconnected() { printf("CONTROLLER DISCONNECTED\n"); } - void controllerUpdate(const SDualshockControllerState& state) + void controllerUpdate(const DualshockControllerState& state) { static time_t timeTotal; static time_t lastTime = 0; @@ -64,7 +49,6 @@ class CDualshockControllerCallback : public IDualshockControllerCallback { if (timeDif >= 1) // wait 30 seconds before issuing another rumble event { - std::cout << "RUMBLE" << std::endl; ctrl->startRumble(DS3_MOTOR_LEFT); ctrl->startRumble(DS3_MOTOR_RIGHT, 100); lastTime = timeTotal; @@ -80,34 +64,34 @@ class CDualshockControllerCallback : public IDualshockControllerCallback } }; -class CTestDeviceFinder : public CDeviceFinder +class TestDeviceFinder : public DeviceFinder { - CDolphinSmashAdapter* smashAdapter = NULL; - CDualshockController* ds3 = nullptr; - CDolphinSmashAdapterCallback m_cb; - CDualshockControllerCallback m_ds3CB; + + DolphinSmashAdapter* smashAdapter = NULL; + DualshockPad* ds3 = nullptr; + DolphinSmashAdapterCallback m_cb; + DualshockPadCallback m_ds3CB; public: - CTestDeviceFinder() - : CDeviceFinder({"CDolphinSmashAdapter", - "CDualshockController"}) + TestDeviceFinder() + : DeviceFinder({typeid(DolphinSmashAdapter)}) {} - void deviceConnected(CDeviceToken& tok) + void deviceConnected(DeviceToken& tok) { - smashAdapter = dynamic_cast(tok.openAndGetDevice()); + smashAdapter = dynamic_cast(tok.openAndGetDevice()); if (smashAdapter) { smashAdapter->setCallback(&m_cb); smashAdapter->startRumble(0); return; } - ds3 = dynamic_cast(tok.openAndGetDevice()); + ds3 = dynamic_cast(tok.openAndGetDevice()); if (ds3) { ds3->setCallback(&m_ds3CB); ds3->setLED(DS3_LED_1); } } - void deviceDisconnected(CDeviceToken&, CDeviceBase* device) + void deviceDisconnected(DeviceToken&, DeviceBase* device) { if (smashAdapter == device) { @@ -122,111 +106,102 @@ public: } }; -} -#if _WIN32 - -/* This simple 'test' console app needs a full windows - * message loop for receiving device connection events - */ -static const DEV_BROADCAST_DEVICEINTERFACE_A HOTPLUG_CONF = +struct CTestWindowCallback : IWindowCallback { - sizeof(DEV_BROADCAST_DEVICEINTERFACE_A), - DBT_DEVTYP_DEVICEINTERFACE, - 0, - GUID_DEVINTERFACE_USB_DEVICE + void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + { + fprintf(stderr, "Mouse Down %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]); + } + void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + { + fprintf(stderr, "Mouse Up %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]); + } + void mouseMove(const SWindowCoord& coord) + { + //fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]); + } + void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) + { + fprintf(stderr, "Mouse Scroll (%f,%f) (%f,%f)\n", coord.norm[0], coord.norm[1], scroll.delta[0], scroll.delta[1]); + } + + void touchDown(const STouchCoord& coord, uintptr_t tid) + { + //fprintf(stderr, "Touch Down %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); + } + void touchUp(const STouchCoord& coord, uintptr_t tid) + { + //fprintf(stderr, "Touch Up %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); + } + void touchMove(const STouchCoord& coord, uintptr_t tid) + { + //fprintf(stderr, "Touch Move %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); + } + + void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) + { + + } + void charKeyUp(unsigned long charCode, EModifierKey mods) + { + + } + void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) + { + + } + void specialKeyUp(ESpecialKey key, EModifierKey mods) + { + + } + void modKeyDown(EModifierKey mod, bool isRepeat) + { + + } + void modKeyUp(EModifierKey mod) + { + + } + }; -LRESULT CALLBACK WindowProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) + +struct TestApplicationCallback : IApplicationCallback { - switch (uMsg) + IWindow* mainWindow = NULL; + boo::TestDeviceFinder devFinder; + CTestWindowCallback windowCallback; + void appLaunched(IApplication* app) { - case WM_CREATE: - /* Register hotplug notification with windows */ - RegisterDeviceNotificationA(hwnd, (LPVOID)&HOTPLUG_CONF, DEVICE_NOTIFY_WINDOW_HANDLE); - return 0; - - case WM_DEVICECHANGE: - return boo::CDeviceFinder::winDevChangedHandler(wParam, lParam); - - default: - return DefWindowProc(hwnd, uMsg, wParam, lParam); + mainWindow = app->newWindow("YAY!"); + mainWindow->setCallback(&windowCallback); + mainWindow->showWindow(); + devFinder.startScanning(); } -} - -int APIENTRY wWinMain( - _In_ HINSTANCE hInstance, - _In_ HINSTANCE, - _In_ LPTSTR, - _In_ int - ) -{ - AllocConsole(); - freopen("CONOUT$", "w", stdout); - - WNDCLASS wndClass = + void appQuitting(IApplication*) { - 0, - WindowProc, - 0, - 0, - hInstance, - 0, - 0, - 0, - 0, - L"BooTestWindow" - }; - - RegisterClassW(&wndClass); - - boo::CTestDeviceFinder finder; - finder.startScanning(); - - HWND hwnd = CreateWindowW(L"BooTestWindow", L"BooTest", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, hInstance, NULL); - - /* Pump messages */ - MSG msg = {0}; - while (GetMessage(&msg, hwnd, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); + delete mainWindow; } + void appFilesOpen(IApplication*, const std::vector& paths) + { + fprintf(stderr, "OPENING: "); + for (const std::string& path : paths) + fprintf(stderr, "%s ", path.c_str()); + fprintf(stderr, "\n"); + } +}; } -#else - -int main(int argc, char** argv) +int main(int argc, const char** argv) { - - boo::CTestDeviceFinder finder; - finder.startScanning(); - -#if 0 - boo::IGraphicsContext* ctx = new boo::CGraphicsContext; - - if (ctx->create()) - { - } -#endif - -#if __APPLE__ - CFRunLoopRun(); -#endif - - while(1) - { - } - //delete ctx; + boo::TestApplicationCallback appCb; + std::unique_ptr app = + ApplicationBootstrap(boo::IApplication::PLAT_AUTO, + appCb, "rwk", "RWK", argc, argv); + app->run(); + printf("IM DYING!!\n"); return 0; } -#endif diff --git a/test/test.pri b/test/test.pri deleted file mode 100644 index 872e5fb..0000000 --- a/test/test.pri +++ /dev/null @@ -1,4 +0,0 @@ -SOURCES += \ - $$PWD/main.cpp - -win32:SOURCES +=