static void set_key_state(KeyEvent const& event) { Window* const window = event.window; if (event.action == KeyAction::press) { // If state already has KeyAction::release, retain it // (it will be cleared by update()) window->_key_states[ unsigned_cast(event.code) ] |= 1 << unsigned_cast(event.action); } else if (event.action == KeyAction::release) { // Replace state and enqueue clear window->_key_states[ unsigned_cast(event.code) ] = 1 << unsigned_cast(event.action); for (auto const code : window->_key_clear_queue) { if (code == event.code) { return; } } if (fixed_array::space(window->_key_clear_queue)) { fixed_array::push_back(window->_key_clear_queue, event.code); } else { TOGO_LOGF( "input_buffer: warning: discarded key-clear for key %u on window %p\n", unsigned_cast(event.code), event.window ); } } }
static void update_input_states(Window* window) { for (auto const code : window->_key_clear_queue) { window->_key_states[ unsigned_cast(code) ] &= ~(1 << unsigned_cast(KeyAction::release)); } fixed_array::clear(window->_key_clear_queue); for (auto& state : window->_mouse_button_states) { state &= ~(1 << unsigned_cast(MouseButtonAction::release)); } }
void Cursor::col_recalc() noexcept { auto const& node = this->node(); if (0 >= m_col) { m_col = 0; m_index = 0; } else if (node.points() <= unsigned_cast(m_col)) { m_col = signed_cast(node.points()); m_index = signed_cast(node.units()); } else if (node.singular()) { m_index = m_col; } else { position_type col = 0; auto const end = node.cend(); auto step = node.cbegin(), from = step; while ( from < (step = txt::EncUtils::next(from, end)) && col > m_col ) { from = step; ++col; } m_col = col; m_index = std::distance(node.cbegin(), from); } }
std::size_t Cursor::insert( char32 const cp ) { txt::EncUtils::char_type units[txt::EncUtils::max_units]; auto const it = txt::EncUtils::encode( cp, std::begin(units), duct::CHAR_NULL ); if (std::begin(units) != it) { auto& node = this->node(); node.m_buffer.insert(node.cbegin() + m_index, std::begin(units), it); auto const size = std::distance(std::begin(units), it); tree().update_counts(node, size, 1); return unsigned_cast(size); } else { // Invalid code point (ignored) return 0u; } }
int unsigned_handler(PF *argument, va_list ap) { uintmax_t n; if (argument->spec == 'x' || argument->spec == 'X' || argument->spec == 'u' || argument->spec == 'o' || argument->spec == 'b') n = unsigned_cast(argument, ap); else n = (unsigned long int)va_arg(ap, uintmax_t); if (argument->spec == 'o' || argument->spec == 'O') argument->arg = fpf_itoa_base(n, 8); else if (argument->spec == 'u' || argument->spec == 'U') argument->arg = fpf_itoa_base(n, 10); else if (argument->spec == 'x') argument->arg = fpf_strlower(fpf_itoa_base(n, 16)); else if (argument->spec == 'b') argument->arg = fpf_itoa_base(n, 2); else argument->arg = fpf_itoa_base(n, 16); return (unsigned_helper(argument)); }
/// Parse program arguments. /// /// Command-leading options are pushed into k_command_options. /// Later options to the command are pushed into k_command to retain /// argument order (sub-options per command stage). /// Returns true if a command was parsed. bool parse_args( KVS& k_options, KVS& k_command_options, KVS& k_command, signed const argc, char const* const argv[] ) { kvs::set_type(k_options, KVSType::node); kvs::set_type(k_command_options, KVSType::node); kvs::set_type(k_command, KVSType::node); kvs::clear(k_options); kvs::clear(k_command_options); kvs::clear(k_command); if (argc == 0) { return false; } kvs::set_name(k_options, StringRef{argv[0], cstr_tag{}}); signed aidx; char const* str; signed pos; signed pos_eq; signed num_dashes; KVS* k_current = &k_options; for (aidx = 1; argc > aidx; ++aidx) { str = argv[aidx]; pos = 0; pos_eq = 0; num_dashes = 0; for (; str[pos] != '\0'; ++pos) { if (str[pos] == '-' && num_dashes == pos) { ++num_dashes; } else if (str[pos] == '=') { pos_eq = pos; break; } } for (; str[pos] != '\0'; ++pos) { // Continue to the end of the string (pos becomes size of string) } if (pos_eq == 0) { pos_eq = pos; } if (num_dashes == pos) { // Consists only of dashes num_dashes = 0; } if (num_dashes == 1 || num_dashes == 2) { KVS& back = kvs::push_back( *k_current, KVS{StringRef{str, unsigned_cast(pos_eq)}, null_tag{}} ); if (pos > pos_eq) { ++pos_eq; // TODO: Parse string to typed value kvs::string( back, StringRef{str + pos_eq, unsigned_cast(pos - pos_eq)} ); } else { kvs::boolean(back, true); } } else if (k_current == &k_options) { // Command reached; switch to parse leading options k_current = &k_command_options; kvs::set_name(k_command, StringRef{str, unsigned_cast(pos)}); } else { // Undashed argument to command k_current = &k_command; kvs::push_back(*k_current, KVS{StringRef{str, unsigned_cast(pos)}}); } } return k_current != &k_options; }
void Cursor::col_step( difference_type const n ) noexcept { if (0 == n) { return; } auto const& node = this->node(); difference_type const dest = m_col + n; /*DUCT_DEBUGF( "col_step: m_col = %zd, m_index = %zd, dest = %ld, n = %ld, " "diff = %zd, abs = %zd", m_col, m_index, dest, n, dest - m_col, std::abs(dest - m_col) );*/ // Recalculate (i.e., count from the beginning) or step // depending on the distance from the current column if (0 >= dest) { m_col = 0; m_index = 0; } else if (node.points() <= unsigned_cast(dest)) { m_col = signed_cast(node.points()); m_index = signed_cast(node.units()); } else if (node.singular()) { m_col = dest; m_index = dest; } else if (dest < std::abs(dest - m_col)) { m_col = dest; col_recalc(); } else { auto const begin = node.cbegin(), end = node.cend(); auto step = begin + m_index, from = step; if (0 > n) { // Step backward while ( from > (step = txt::EncUtils::prev(from, begin)) && dest < m_col ) { from = step; --m_col; } } else { // Step forward while ( from < (step = txt::EncUtils::next(from, end)) && dest > m_col ) { from = step; ++m_col; } } m_index = std::distance(begin, from); /*DUCT_DEBUGF( " m_col = %zd, m_index = %zd, dist = %ld", m_col, m_index, std::distance(begin, from) );*/ } }
/// Poll events. /// /// Returns true if an event was fetched. /// /// @warning This must be called on the thread that created the /// windows. bool input_buffer::poll( InputBuffer& ib, InputEventType& type, InputEvent const*& event ) { if (!ib._buffer._consume_mode) { window::process_events(ib); if (!object_buffer::empty(ib._buffer)) { object_buffer::begin_consume(ib._buffer); } else { return false; } } else { if (!object_buffer::has_more(ib._buffer)) { object_buffer::end_consume(ib._buffer); return false; } } void const* vptr = nullptr; object_buffer::read(ib._buffer, type, vptr); event = static_cast<InputEvent const*>(vptr); #if defined(TOGO_TEST_INPUT_BUFFER) switch (type) { case InputEventType::key: TOGO_TEST_LOGF( "input event: %p => " "key: action = %u code = %u mods = %u\n", event->window, unsigned_cast(event->key.action), unsigned_cast(event->key.code), unsigned_cast(event->key.mods) ); break; case InputEventType::mouse_button: TOGO_TEST_LOGF( "input event: %p => " "mouse_button: action = %u button = %u\n", event->window, unsigned_cast(event->mouse_button.action), unsigned_cast(event->mouse_button.button) ); break; case InputEventType::mouse_motion: /*TOGO_TEST_LOGF( "input event: %p => " "mouse_motion: (%d, %d)\n", event->window, event->mouse_motion.x, event->mouse_motion.y );*/ break; case InputEventType::window_focus: TOGO_TEST_LOGF( "input event: %p => " "window_focus: focused = %s\n", event->window, event->window_focus.focused ? "true" : "false" ); break; case InputEventType::window_close_request: TOGO_TEST_LOGF( "input event: %p => " "window_close_request\n", event->window ); break; case InputEventType::window_resize: TOGO_TEST_LOGF( "input event: %p => " "window_resize: (%-4u, %-4u) -> (%-4u, %-4u)\n", event->window, event->window_resize.old_size.width, event->window_resize.old_size.height, event->window_resize.new_size.width, event->window_resize.new_size.height ); break; case InputEventType::window_backbuffer_dirtied: TOGO_TEST_LOGF( "input event: %p => " "window_backbuffer_dirtied\n", event->window ); break; } #endif switch (type) { case InputEventType::key: set_key_state(event->key); break; case InputEventType::mouse_button: if (event->mouse_button.action == MouseButtonAction::press) { event->window->_mouse_button_states[ unsigned_cast(event->mouse_button.button) ] |= 1 << unsigned_cast(event->mouse_button.action); } else if (event->mouse_button.action == MouseButtonAction::release) { event->window->_mouse_button_states[ unsigned_cast(event->mouse_button.button) ] = 1 << unsigned_cast(event->mouse_button.action); } break; case InputEventType::mouse_motion: event->window->_mouse_x = event->mouse_motion.x; event->window->_mouse_y = event->mouse_motion.y; break; default: break; }; return true; }
namespace notification { /** @addtogroup lib_platform_notification @{ */ /// Notification type. enum class Type : unsigned { generic, /// Indicates that an error has occurred. error, /// Indicates that the application is persisting (e.g., a background /// service/task). persisting_process, /// Indicates that an alarm has triggered. alarm, /// Indicates that a message has arrived (e.g., SMS). message, /// Indicates that the application is playing media. media, }; static constexpr unsigned const c_num_type = unsigned_cast(Type::media) + 1; /// Notification priority. enum class Priority : unsigned { normal, low, high, }; static constexpr unsigned const c_num_priority = unsigned_cast(Priority::high) + 1; /// Maximum lifetime of a notification in milliseconds (8m74s, 524.287s, 524287ms, 0x7FFFF). static constexpr signed const MAX_LIFETIME = 0x7FFFF; struct NotificationImpl; /// Notification. struct Notification { TOGO_LUA_MARK_USERDATA(Notification); u32 _properties; NotificationImpl* _impl; Notification(Notification&&) = default; Notification& operator=(Notification&&) = default; Notification(Notification const&) = delete; Notification& operator=(Notification const&) = delete; Notification( StringRef title, StringRef body, signed lifetime = -1, Type type = Type::generic, Priority priority = Priority::normal ); ~Notification(); }; /** @} */ // end of doc-group lib_platform_notification } // namespace notification