LCOV - code coverage report
Current view: top level - xenolith/core - XLCoreInput.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 31 32 96.9 %
Date: 2024-05-12 00:16:13 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #ifndef XENOLITH_CORE_XLCOREINPUT_H_
      24             : #define XENOLITH_CORE_XLCOREINPUT_H_
      25             : 
      26             : #include "XLCore.h"
      27             : 
      28             : #if WIN32
      29             : #ifdef DELETE
      30             : #undef DELETE
      31             : #endif
      32             : #endif
      33             : 
      34             : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
      35             : 
      36             : enum class InputFlags {
      37             :         None,
      38             :         TouchMouseInput = 1 << 0,
      39             :         KeyboardInput = 1 << 1,
      40             :         FocusInput = 1 << 2,
      41             : };
      42             : 
      43             : SP_DEFINE_ENUM_AS_MASK(InputFlags)
      44             : 
      45             : enum class InputMouseButton : uint32_t {
      46             :         None,
      47             :         MouseLeft,
      48             :         MouseMiddle,
      49             :         MouseRight,
      50             :         MouseScrollUp,
      51             :         MouseScrollDown,
      52             :         MouseScrollLeft,
      53             :         MouseScrollRight,
      54             :         Mouse8,
      55             :         Mouse9,
      56             :         Mouse10,
      57             :         Mouse11,
      58             :         Mouse12,
      59             :         Mouse13,
      60             :         Mouse14,
      61             :         Mouse15,
      62             :         Max,
      63             : 
      64             :         Touch = MouseLeft
      65             : };
      66             : 
      67             : enum class InputModifier : uint32_t {
      68             :         None = 0,
      69             :         Shift = 1 << 0,
      70             :         CapsLock = 1 << 1,
      71             :         Ctrl = 1 << 2,
      72             :         Alt = 1 << 3,
      73             :         NumLock = 1 << 4,
      74             :         Mod3 = 1 << 5,
      75             :         Mod4 = 1 << 6,
      76             :         Mod5 = 1 << 7,
      77             :         Button1 = 1 << 8,
      78             :         Button2 = 1 << 9,
      79             :         Button3 = 1 << 10,
      80             :         Button4 = 1 << 11,
      81             :         Button5 = 1 << 12,
      82             : 
      83             :         // Linux-only, experimental
      84             :         LayoutAlternative = 1 << 13,
      85             : 
      86             :         ShiftL = 1 << 14,
      87             :         ShiftR = 1 << 15,
      88             :         CtrlL = 1 << 16,
      89             :         CtrlR = 1 << 17,
      90             :         AltL = 1 << 18,
      91             :         AltR = 1 << 19,
      92             :         Mod3L = 1 << 20,
      93             :         Mod3R = 1 << 21,
      94             :         Mod4L = 1 << 22,
      95             :         Mod4R = 1 << 23,
      96             : 
      97             :         ScrollLock = 1 << 24,
      98             : 
      99             :         Command = Mod3, // MacOS Command
     100             :         Meta = Mod3, // Android Meta
     101             :         Function = Mod4, // Android Function
     102             :         Sym = Mod5, // Android Sym
     103             :         Win = Mod3,
     104             :         WinL = Mod3L,
     105             :         WinR = Mod3R,
     106             :         Menu = Alt, // VK_MENU
     107             :         MenuL = AltL, // VK_LMENU
     108             :         MenuR = AltR, // VK_RMENU
     109             : 
     110             :         // boolean value for switch event (background/focus)
     111             :         ValueFalse = None,
     112             :         ValueTrue = uint32_t(1) << uint32_t(31),
     113             :         Unmanaged = ValueTrue
     114             : };
     115             : 
     116             : SP_DEFINE_ENUM_AS_MASK(InputModifier)
     117             : 
     118             : /* Based on GLFW
     119             :  *
     120             :  * Designed to fit 128-bit bitmask for pressed key tracking
     121             :  * Undefined char is 0 instead of -1
     122             :  * Codepoints for BACKSPACE, TAB, ENTER, ESCAPE, DELETE matches ASCII positions
     123             :  *  - Platform can send this with or without keychar
     124             :  * Printable keys (and keypad nums) within [32-96]
     125             :  * APOSTROPHE moved from 39 to 43 to fit keypad nums in single block
     126             :  *  - expressions like KP_0 + 8 is more probable then direct casting InputKeyCode -> char
     127             :  * Key names based on QWERTY keyboard, but actually refers to physical key position rather then symbol
     128             :  * - actual physical key name defined in XKB convention
     129             :  * - e.g. InputKeyCode::S = AC02 key = A on QWERTY = O on Dworak
     130             :  * */
     131             : enum class InputKeyCode : uint16_t {
     132             :         Unknown = 0,
     133             : 
     134             :         KP_DECIMAL              = 1,    // "KPDL"
     135             :         KP_DIVIDE               = 2,    // "KPDV"
     136             :         KP_MULTIPLY             = 3,    // "KPMU"
     137             :         KP_SUBTRACT             = 4,    // "KPSU"
     138             :         KP_ADD                  = 5,    // "KPAD"
     139             :         KP_ENTER                = 6,    // "KPEN"
     140             :         KP_EQUAL                = 7,    // "KPEQ"
     141             : 
     142             :         BACKSPACE               = 8,    // "BKSP"; ASCII-compatible
     143             :         TAB                             = 9,    // "TAB"; ASCII-compatible
     144             :         ENTER                   = 10,   // "RTRN"; ASCII-compatible
     145             : 
     146             :         RIGHT                   = 11,   // "RGHT"
     147             :         LEFT                    = 12,   // "LEFT"
     148             :         DOWN                    = 13,   // "DOWN"
     149             :         UP                              = 14,   // "UP"
     150             :         PAGE_UP                 = 15,   // "PGUP"
     151             :         PAGE_DOWN               = 16,   // "PGDN"
     152             :         HOME                    = 17,   // "HOME"
     153             :         END                             = 18,   // "END"
     154             :         LEFT_SHIFT              = 19,   // "LFSH"
     155             :         LEFT_CONTROL    = 20,   // "LCTL"
     156             :         LEFT_ALT                = 21,   // "LALT"
     157             :         LEFT_SUPER              = 22,   // "LWIN"
     158             :         RIGHT_SHIFT             = 23,   // "RTSH"
     159             :         RIGHT_CONTROL   = 24,   // "RCTL"
     160             :         RIGHT_ALT               = 25,   // "RALT", "LVL3", MDSW"
     161             :         RIGHT_SUPER             = 26,   // "RWIN"
     162             : 
     163             :         ESCAPE                  = 27,   // "ESC"; ASCII-compatible :
     164             : 
     165             :         INSERT                  = 28,   // "INS"
     166             :         CAPS_LOCK               = 29,   // "CAPS"
     167             :         SCROLL_LOCK             = 30,   // "SCLK"
     168             :         NUM_LOCK                = 31,   // "NMLK"
     169             : 
     170             :         SPACE                   = 32,   // "SPCE"
     171             : 
     172             :         KP_0                    = 33,   // "KP0"
     173             :         KP_1                    = 34,   // "KP1"
     174             :         KP_2                    = 35,   // "KP2"
     175             :         KP_3                    = 36,   // "KP3"
     176             :         KP_4                    = 37,   // "KP4"
     177             :         KP_5                    = 38,   // "KP5"
     178             :         KP_6                    = 39,   // "KP6"
     179             :         KP_7                    = 40,   // "KP7"
     180             :         KP_8                    = 41,   // "KP8"
     181             :         KP_9                    = 42,   // "KP9"
     182             : 
     183             :         APOSTROPHE              = 43,   // "AC11"; '\''
     184             :         COMMA                   = 44,   // "AB08"; ','
     185             :         MINUS                   = 45,   // "AE11"; '-'
     186             :         PERIOD                  = 46,   // "AB09"; '.'
     187             :         SLASH                   = 47,   // "AB10"; '/'
     188             :         _0                              = 48,   // "AE10"
     189             :         _1                              = 49,   // "AE01"
     190             :         _2                              = 50,   // "AE02"
     191             :         _3                              = 51,   // "AE03"
     192             :         _4                              = 52,   // "AE04"
     193             :         _5                              = 53,   // "AE05"
     194             :         _6                              = 54,   // "AE06"
     195             :         _7                              = 55,   // "AE07"
     196             :         _8                              = 56,   // "AE08"
     197             :         _9                              = 57,   // "AE09"
     198             :         SEMICOLON               = 59,   // "AC10"; ';'
     199             :         EQUAL                   = 61,   // "AE12"; '='
     200             : 
     201             :         WORLD_1                 = 62,   // "LSGT"; non-US #1 :
     202             :         WORLD_2                 = 63,   // non-US #2
     203             : 
     204             :         A                               = 65,   // "AC01"
     205             :         B                               = 66,   // "AB05"
     206             :         C                               = 67,   // "AB03"
     207             :         D                               = 68,   // "AC03"
     208             :         E                               = 69,   // "AD03"
     209             :         F                               = 70,   // "AC04"
     210             :         G                               = 71,   // "AC05"
     211             :         H                               = 72,   // "AC06"
     212             :         I                               = 73,   // "AD08"
     213             :         J                               = 74,   // "AC07"
     214             :         K                               = 75,   // "AC08"
     215             :         L                               = 76,   // "AC09"
     216             :         M                               = 77,   // "AB07"
     217             :         N                               = 78,   // "AB06"
     218             :         O                               = 79,   // "AD09"
     219             :         P                               = 80,   // "AD10"
     220             :         Q                               = 81,   // "AD01"
     221             :         R                               = 82,   // "AD04"
     222             :         S                               = 83,   // "AC02"
     223             :         T                               = 84,   // "AD05"
     224             :         U                               = 85,   // "AD07"
     225             :         V                               = 86,   // "AB04"
     226             :         W                               = 87,   // "AD02"
     227             :         X                               = 88,   // "AB02"
     228             :         Y                               = 89,   // "AD06"
     229             :         Z                               = 90,   // "AB01"
     230             :         LEFT_BRACKET    = 91,   // "AD11"; '['
     231             :         BACKSLASH               = 92,   // "BKSL"; '\\'
     232             :         RIGHT_BRACKET   = 93,   // "AD12"; ']'
     233             :         GRAVE_ACCENT    = 96,   // "TLDE"; '`'
     234             : 
     235             :         /* Function keys */
     236             :         F1                              = 97,   // "FK01"
     237             :         F2                              = 98,   // "FK02"
     238             :         F3                              = 99,   // "FK03"
     239             :         F4                              = 100,  // "FK04"
     240             :         F5                              = 101,  // "FK05"
     241             :         F6                              = 102,  // "FK06"
     242             :         F7                              = 103,  // "FK07"
     243             :         F8                              = 104,  // "FK08"
     244             :         F9                              = 105,  // "FK09"
     245             :         F10                             = 106,  // "FK10"
     246             :         F11                             = 107,  // "FK11"
     247             :         F12                             = 108,  // "FK12"
     248             :         F13                             = 109,  // "FK13"
     249             :         F14                             = 110,  // "FK14"
     250             :         F15                             = 111,  // "FK15"
     251             :         F16                             = 112,  // "FK16"
     252             :         F17                             = 113,  // "FK17"
     253             :         F18                             = 114,  // "FK18"
     254             :         F19                             = 115,  // "FK19"
     255             :         F20                             = 116,  // "FK20"
     256             :         F21                             = 117,  // "FK21"
     257             :         F22                             = 118,  // "FK22"
     258             :         F23                             = 119,  // "FK23"
     259             :         F24                             = 120,  // "FK24"
     260             :         F25                             = 121,  // "FK25"
     261             : 
     262             :         MENU                    = 124,  // "MENU"
     263             :         PRINT_SCREEN    = 125,  // "PRSC"
     264             :         PAUSE                   = 126,  // "PAUS"
     265             :         DELETE                  = 127,  // "DELE"; ASCII-compatible
     266             : 
     267             :         Max
     268             : };
     269             : 
     270             : enum class InputKeyComposeState : uint16_t {
     271             :         Nothing = 0,
     272             :         Composed,
     273             :         Composing,
     274             :         Disabled, // do not use this key event for text input processing
     275             :         Forced, // use, when key up should be processed
     276             : };
     277             : 
     278             : enum class InputEventName : uint32_t {
     279             :         None,
     280             :         Begin,
     281             :         Move,
     282             :         End,
     283             :         Cancel,
     284             :         MouseMove,
     285             :         Scroll,
     286             : 
     287             :         Background,
     288             :         PointerEnter,
     289             :         FocusGain,
     290             : 
     291             :         KeyPressed,
     292             :         KeyRepeated,
     293             :         KeyReleased,
     294             :         KeyCanceled,
     295             : 
     296             :         Max,
     297             : };
     298             : 
     299             : struct InputEventData {
     300         122 :         static InputEventData BoolEvent(InputEventName event, bool value) {
     301             :                 return InputEventData{maxOf<uint32_t>(), event, InputMouseButton::None,
     302         122 :                         value ? InputModifier::ValueTrue : InputModifier::None};
     303             :         }
     304             : 
     305          26 :         static InputEventData BoolEvent(InputEventName event, bool value, const Vec2 &pt) {
     306             :                 return InputEventData{maxOf<uint32_t>(), event, InputMouseButton::None,
     307          26 :                         value ? InputModifier::ValueTrue : InputModifier::None, pt.x, pt.y};
     308             :         }
     309             : 
     310             :         static InputEventData BoolEvent(InputEventName event, bool value, InputModifier mod, const Vec2 &pt) {
     311             :                 return InputEventData{maxOf<uint32_t>(), event, InputMouseButton::None,
     312             :                         mod | (value ? InputModifier::ValueTrue : InputModifier::None), pt.x, pt.y};
     313             :         }
     314             : 
     315             :         uint32_t id = maxOf<uint32_t>();
     316             :         InputEventName event = InputEventName::None;
     317             :         InputMouseButton button = InputMouseButton::None;
     318             :         InputModifier modifiers = InputModifier::None;
     319             :         float x = 0.0f;
     320             :         float y = 0.0f;
     321             :         union {
     322             :                 struct {
     323             :                         float valueX = 0.0f;
     324             :                         float valueY = 0.0f;
     325             :                         float density = 1.0f;
     326             :                 } point = { 0.0f, 0.0f, 1.0f };
     327             :                 struct {
     328             :                         InputKeyCode keycode; // layout-independent key name
     329             :                         InputKeyComposeState compose;
     330             :                         uint32_t keysym; // OS-dependent keysym
     331             :                         char32_t keychar; // unicode char for key
     332             :                 } key;
     333             :         };
     334             : 
     335             :         bool operator==(const uint32_t &i) const { return id == i; }
     336             :         bool operator!=(const uint32_t &i) const { return id != i; }
     337             : 
     338         931 :         bool getValue() const { return (modifiers & InputModifier::ValueTrue) != InputModifier::None; }
     339             : 
     340        6790 :         bool hasLocation() const {
     341        6790 :                 switch (event) {
     342         134 :                 case InputEventName::None:
     343             :                 case InputEventName::Background:
     344             :                 case InputEventName::PointerEnter:
     345             :                 case InputEventName::FocusGain:
     346         134 :                         return false;
     347             :                         break;
     348             : #if ANDROID
     349             :                 case InputEventName::KeyPressed:
     350             :                 case InputEventName::KeyReleased:
     351             :                 case InputEventName::KeyRepeated:
     352             :                         return false;
     353             :                         break;
     354             : #endif
     355        6656 :                 default:
     356        6656 :                         break;
     357             :                 }
     358        6656 :                 return true;
     359             :         }
     360             : 
     361        6097 :         bool isPointEvent() const {
     362        6097 :                 switch (event) {
     363        4376 :                 case InputEventName::Begin:
     364             :                 case InputEventName::Move:
     365             :                 case InputEventName::End:
     366             :                 case InputEventName::Cancel:
     367             :                 case InputEventName::MouseMove:
     368             :                 case InputEventName::Scroll:
     369        4376 :                         return true;
     370             :                         break;
     371        1721 :                 default:
     372        1721 :                         break;
     373             :                 }
     374        1721 :                 return false;
     375             :         }
     376             : 
     377         210 :         bool isKeyEvent() const {
     378         210 :                 switch (event) {
     379         189 :                 case InputEventName::KeyPressed:
     380             :                 case InputEventName::KeyRepeated:
     381             :                 case InputEventName::KeyReleased:
     382         189 :                         return true;
     383             :                         break;
     384          21 :                 default:
     385          21 :                         break;
     386             :                 }
     387          21 :                 return false;
     388             :         }
     389             : 
     390             :         bool operator==(const InputEventData &r) const {
     391             :                 if (id != r.id || event != r.event || button != r.button || modifiers != r.modifiers || x != r.x || y != r.y) {
     392             :                         return false;
     393             :                 }
     394             :                 switch (event) {
     395             :                 case InputEventName::Begin:
     396             :                 case InputEventName::Move:
     397             :                 case InputEventName::End:
     398             :                 case InputEventName::Cancel:
     399             :                 case InputEventName::MouseMove:
     400             :                 case InputEventName::Scroll:
     401             :                         // pointer event
     402             :                         if (point.valueX != r.point.valueX || point.valueY != r.point.valueY || point.density != r.point.density) {
     403             :                                 return false;
     404             :                         }
     405             :                         break;
     406             :                 case InputEventName::KeyPressed:
     407             :                 case InputEventName::KeyRepeated:
     408             :                 case InputEventName::KeyReleased:
     409             :                         // key event
     410             :                         if (key.keycode != r.key.keycode || key.compose != r.key.compose || key.keysym != r.key.keysym || key.keychar != r.key.keychar) {
     411             :                                 return false;
     412             :                         }
     413             :                         break;
     414             :                 default:
     415             :                         // bool event
     416             :                         break;
     417             :                 }
     418             :                 return true;
     419             :         }
     420             : 
     421             :         bool operator!=(const InputEventData &r) const {
     422             :                 return !(*this == r);
     423             :         }
     424             : 
     425             :         bool operator<(const InputEventData &r) const {
     426             :                 if (id < r.id) {
     427             :                         return true;
     428             :                 } else if (id > r.id) {
     429             :                         return false;
     430             :                 }
     431             : 
     432             :                 if (toInt(event) < toInt(r.event)) {
     433             :                         return true;
     434             :                 } else if (toInt(event) > toInt(r.event)) {
     435             :                         return false;
     436             :                 }
     437             : 
     438             :                 if (toInt(button) < toInt(r.button)) {
     439             :                         return true;
     440             :                 } else if (toInt(button) > toInt(r.button)) {
     441             :                         return false;
     442             :                 }
     443             : 
     444             :                 if (toInt(modifiers) < toInt(r.modifiers)) {
     445             :                         return true;
     446             :                 } else if (toInt(modifiers) > toInt(r.modifiers)) {
     447             :                         return false;
     448             :                 }
     449             : 
     450             :                 return false;
     451             :         }
     452             : };
     453             : 
     454             : enum class TextInputType {
     455             :         Empty                           = 0,
     456             :         Date_Date                       = 1,
     457             :         Date_DateTime           = 2,
     458             :         Date_Time                       = 3,
     459             :         Date                            = Date_DateTime,
     460             : 
     461             :         Number_Numbers          = 4,
     462             :         Number_Decimial         = 5,
     463             :         Number_Signed           = 6,
     464             :         Number                          = Number_Numbers,
     465             : 
     466             :         Phone                           = 7,
     467             : 
     468             :         Text_Text                       = 8,
     469             :         Text_Search                     = 9,
     470             :         Text_Punctuation        = 10,
     471             :         Text_Email                      = 11,
     472             :         Text_Url                        = 12,
     473             :         Text                            = Text_Text,
     474             : 
     475             :         Default                         = Text_Text,
     476             : 
     477             :         ClassMask                       = 0b00011111,
     478             :         PasswordBit                     = 0b00100000,
     479             :         MultiLineBit            = 0b01000000,
     480             :         AutoCorrectionBit       = 0b10000000,
     481             : 
     482             :         ReturnKeyMask           = 0b00001111 << 8,
     483             : 
     484             :         ReturnKeyDefault        = 1 << 8,
     485             :         ReturnKeyGo                     = 2 << 8,
     486             :         ReturnKeyGoogle         = 3 << 8,
     487             :         ReturnKeyJoin           = 4 << 8,
     488             :         ReturnKeyNext           = 5 << 8,
     489             :         ReturnKeyRoute          = 6 << 8,
     490             :         ReturnKeySearch         = 7 << 8,
     491             :         ReturnKeySend           = 8 << 8,
     492             :         ReturnKeyYahoo          = 9 << 8,
     493             :         ReturnKeyDone           = 10 << 8,
     494             :         ReturnKeyEmergencyCall = 11 << 8,
     495             : };
     496             : 
     497             : SP_DEFINE_ENUM_AS_MASK(TextInputType);
     498             : 
     499             : using TextCursorPosition = ValueWrapper<uint32_t, class TextCursorPositionFlag>;
     500             : using TextCursorLength = ValueWrapper<uint32_t, class TextCursorStartFlag>;
     501             : 
     502             : struct TextCursor {
     503             :         static const TextCursor InvalidCursor;
     504             : 
     505       28132 :         uint32_t start;
     506       27772 :         uint32_t length;
     507             : 
     508         180 :         constexpr TextCursor() : start(maxOf<uint32_t>()), length(0) { }
     509           0 :         constexpr TextCursor(uint32_t pos) : start(pos), length(0) { }
     510         132 :         constexpr TextCursor(uint32_t st, uint32_t len) : start(st), length(len) { }
     511             :         constexpr TextCursor(TextCursorPosition pos) : start(pos.get()), length(0) { }
     512             :         constexpr TextCursor(TextCursorPosition pos, TextCursorLength len) : start(pos.get()), length(len.get()) { }
     513             :         constexpr TextCursor(TextCursorPosition first, TextCursorPosition last)
     514             :         : start(std::min(first.get(), last.get()))
     515             :         , length(((first > last)?(first - last).get():(last - first).get()) + 1) { }
     516             : 
     517       28132 :         constexpr bool operator==(const TextCursor &) const = default;
     518             : };
     519             : 
     520             : StringView getInputKeyCodeName(InputKeyCode);
     521             : StringView getInputKeyCodeKeyName(InputKeyCode);
     522             : StringView getInputEventName(InputEventName);
     523             : 
     524             : StringView getInputButtonName(InputMouseButton);
     525             : 
     526             : String getInputModifiersNames(InputModifier);
     527             : 
     528             : }
     529             : 
     530             : namespace std {
     531             : 
     532             : std::ostream &operator<<(std::ostream &, STAPPLER_VERSIONIZED_NAMESPACE::xenolith::core::InputKeyCode);
     533             : std::ostream &operator<<(std::ostream &, STAPPLER_VERSIONIZED_NAMESPACE::xenolith::core::InputEventName);
     534             : 
     535             : }
     536             : 
     537             : #endif /* XENOLITH_CORE_XLCOREINPUT_H_ */

Generated by: LCOV version 1.14