Skip to content

Commit ad64110

Browse files
authored
Merge pull request #826 from o-sdn-o/gui-bridge
Revise multi-focus keyboard events forwarding (fix multi-focus input within a process)
2 parents 3023c87 + d8d60b1 commit ad64110

File tree

4 files changed

+87
-63
lines changed

4 files changed

+87
-63
lines changed

src/netxs/desktopio/application.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace netxs::app
2222

2323
namespace netxs::app::shared
2424
{
25-
static const auto version = "v2025.10.14";
25+
static const auto version = "v2025.10.15";
2626
static const auto repository = "https://github.com/directvt/vtm";
2727
static const auto usr_config = "~/.config/vtm/settings.xml"s;
2828
static const auto sys_config = "/etc/vtm/settings.xml"s;

src/netxs/desktopio/controls.hpp

Lines changed: 80 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,6 +1735,71 @@ namespace netxs::ui
17351735
}
17361736
};
17371737

1738+
// pro: Keyboard events.
1739+
class keybd
1740+
: public skill
1741+
{
1742+
using skill::boss,
1743+
skill::memo;
1744+
1745+
std::unordered_map<id_t, time> last_key; // keybd: .
1746+
si64 instance_id; // keybd: .
1747+
1748+
public:
1749+
static void forward_release(base& boss, hids& gear)
1750+
{
1751+
auto parent_ptr = boss.base::This();
1752+
while ((!gear.handled || gear.keystat == input::key::released) && parent_ptr) // Always pass released key events. Stop on gear.timecod > last_key[gear.id] in pro::keybd (gear.handled).
1753+
{
1754+
parent_ptr->base::signal(tier::release, input::events::keybd::post, gear);
1755+
parent_ptr = parent_ptr->base::parent();
1756+
}
1757+
}
1758+
1759+
keybd(base&&) = delete;
1760+
keybd(base& boss)
1761+
: skill{ boss },
1762+
instance_id{ datetime::now().time_since_epoch().count() }
1763+
{
1764+
boss.LISTEN(tier::general, input::events::die, gear, memo)
1765+
{
1766+
last_key.erase(gear.id);
1767+
};
1768+
boss.LISTEN(tier::release, input::events::keybd::any, gear, memo)
1769+
{
1770+
gear.shared_event = gear.touched && gear.touched != instance_id;
1771+
auto& timecod = last_key[gear.id];
1772+
if (gear.timecod > timecod)
1773+
{
1774+
timecod = gear.timecod;
1775+
if (gear.payload == input::keybd::type::keypress && gear.keystat != input::key::interrupted)
1776+
{
1777+
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, boss.indexer.anykey_event);
1778+
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, gear.vkevent);
1779+
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, gear.chevent);
1780+
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, gear.scevent);
1781+
}
1782+
}
1783+
else
1784+
{
1785+
gear.set_handled(faux); // faux: Set handled for keybd only.
1786+
gear.keystat = input::key::interrupted; // Forward gear.keystat == input::key::released only once.
1787+
}
1788+
};
1789+
boss.LISTEN(tier::preview, input::events::keybd::any, gear, memo)
1790+
{
1791+
gear.shared_event = gear.touched && gear.touched != instance_id;
1792+
if (gear.payload == input::keybd::type::keypress)
1793+
{
1794+
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, gear.vkevent);
1795+
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, gear.chevent);
1796+
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, gear.scevent);
1797+
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, boss.indexer.anykey_event);
1798+
}
1799+
};
1800+
}
1801+
};
1802+
17381803
// pro: Text input focus tree.
17391804
class focus
17401805
: public skill
@@ -2138,15 +2203,28 @@ namespace netxs::ui
21382203
{
21392204
auto sent = faux;
21402205
auto& chain = get_chain(gear.id);
2206+
auto in_keystat = gear.keystat;
2207+
auto ou_keystat = gear.keystat;
2208+
auto in_handled = gear.handled;
2209+
auto ou_handled = gear.handled;
21412210
chain.foreach([&](auto& nexthop, auto& status)
21422211
{
21432212
if (status == state::live)
21442213
{
21452214
sent = true;
2215+
gear.handled = in_handled; // Split handled state.
2216+
gear.keystat = in_keystat; // Split keystat state.
21462217
nexthop.base::signal(tier::preview, input::events::keybd::post, gear);
2218+
ou_handled |= gear.handled; // Combine handled state.
2219+
if (gear.keystat == input::key::interrupted)
2220+
{
2221+
ou_keystat = gear.keystat;
2222+
}
21472223
}
21482224
});
2149-
if (!sent && node_type != mode::relay) // Send key::post event back. The relays themselves will later send it back.
2225+
gear.handled = ou_handled;
2226+
gear.keystat = ou_keystat;
2227+
if (!sent && node_type != mode::relay) // Send key::post event back. The relays themselves will send it back later.
21502228
{
21512229
if constexpr (debugmode)
21522230
{
@@ -2156,12 +2234,7 @@ namespace netxs::ui
21562234
// auto i = 0;
21572235
//}
21582236
}
2159-
auto parent_ptr = boss.base::This();
2160-
while ((!gear.handled || gear.keystat == input::key::released) && parent_ptr) // Always pass released key events.
2161-
{
2162-
parent_ptr->base::signal(tier::release, input::events::keybd::post, gear);
2163-
parent_ptr = parent_ptr->base::parent();
2164-
}
2237+
pro::keybd::forward_release(boss, gear);
21652238
}
21662239
};
21672240
// all tier::previews going to outside (upstream)
@@ -2591,60 +2664,6 @@ namespace netxs::ui
25912664
}
25922665
};
25932666

2594-
// pro: Keyboard events.
2595-
class keybd
2596-
: public skill
2597-
{
2598-
using skill::boss,
2599-
skill::memo;
2600-
2601-
std::unordered_map<id_t, time> last_key; // keybd: .
2602-
si64 instance_id; // keybd: .
2603-
2604-
public:
2605-
keybd(base&&) = delete;
2606-
keybd(base& boss)
2607-
: skill{ boss },
2608-
instance_id{ datetime::now().time_since_epoch().count() }
2609-
{
2610-
boss.LISTEN(tier::general, input::events::die, gear, memo)
2611-
{
2612-
last_key.erase(gear.id);
2613-
};
2614-
boss.LISTEN(tier::release, input::events::keybd::any, gear, memo)
2615-
{
2616-
gear.shared_event = gear.touched && gear.touched != instance_id;
2617-
auto& timecod = last_key[gear.id];
2618-
if (gear.timecod > timecod)
2619-
{
2620-
timecod = gear.timecod;
2621-
if (gear.payload == input::keybd::type::keypress)
2622-
{
2623-
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, boss.indexer.anykey_event);
2624-
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, gear.vkevent);
2625-
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, gear.chevent);
2626-
if (!gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdrelease, gear.scevent);
2627-
}
2628-
}
2629-
else
2630-
{
2631-
gear.set_handled(faux); // faux: Set handled for keybd only.
2632-
}
2633-
};
2634-
boss.LISTEN(tier::preview, input::events::keybd::any, gear, memo)
2635-
{
2636-
gear.shared_event = gear.touched && gear.touched != instance_id;
2637-
if (gear.payload == input::keybd::type::keypress)
2638-
{
2639-
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, gear.vkevent);
2640-
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, gear.chevent);
2641-
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, gear.scevent);
2642-
if (!gear.touched && !gear.handled) input::bindings::dispatch(boss, instance_id, gear, tier::keybdpreview, boss.indexer.anykey_event);
2643-
}
2644-
};
2645-
}
2646-
};
2647-
26482667
// pro: Glow gradient filter.
26492668
class grade
26502669
: public skill

src/netxs/desktopio/gui.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,6 +2889,10 @@ namespace netxs::gui
28892889
stream.m.timecod = datetime::now();
28902890
stream.m.enabled = hids::stat::halt;
28912891
if (!mfocus.focused()) stream.m.ctlstat &= input::hids::NumLock | input::hids::CapsLock | input::hids::ScrlLock;
2892+
if (std::exchange(stream.gears->tooltip.visible, faux)) // Hide all active tooltips on mouse leave.
2893+
{
2894+
update_tooltip();
2895+
}
28922896
stream.mouse(stream.m);
28932897
}
28942898
void mouse_leave()

src/netxs/desktopio/terminal.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9093,7 +9093,8 @@ namespace netxs::ui
90939093
gear.keybd::scevent = owner.indexer.get_kbchord_hint(k.scchord);
90949094
gear.keybd::chevent = owner.indexer.get_kbchord_hint(k.chchord);
90959095
k.syncto(gear);
9096-
owner.base::riseup(tier::release, input::events::keybd::post, gear, true);
9096+
//owner.base::riseup(tier::release, input::events::keybd::post, gear, true);
9097+
pro::keybd::forward_release(owner, gear);
90979098
}
90989099
}
90999100
};

0 commit comments

Comments
 (0)