Text input and font rendering improvements
This commit is contained in:
parent
24b4aa449b
commit
eaa2a24efb
|
|
@ -13,6 +13,8 @@ rustflags = [
|
|||
|
||||
[env]
|
||||
ESP_LOG = "info"
|
||||
# This is overkill, but we can afford it.
|
||||
SLINT_FONT_SIZES = "8,11,10,12,13,14,15,16,18,20,22,24,32"
|
||||
|
||||
# Xtensa only:
|
||||
# Needed for nightly, until llvm upstream has support for Rust Xtensa.
|
||||
|
|
|
|||
|
|
@ -53,12 +53,18 @@ fn main() {
|
|||
r#"cargo:rerun-if-changed=C:\Users\Limeth\workspace\c\libxkbcommon-linux\build-debug-redefined-syms\libxkbcommon.a"#
|
||||
);
|
||||
|
||||
// Slint config and compilation
|
||||
{
|
||||
// Don't think this does anything:
|
||||
// println!("cargo:rerun-if-env-changed=SLINT_FONT_SIZES");
|
||||
|
||||
let slint_config = CompilerConfiguration::new()
|
||||
// .with_scale_factor(4.0)
|
||||
// .with_scale_factor(2.0)
|
||||
.with_style("cosmic-dark".to_string())
|
||||
.embed_resources(EmbedResourcesKind::EmbedForSoftwareRenderer);
|
||||
slint_build::compile_with_config("ui/main.slint", slint_config).expect("Slint build failed");
|
||||
slint_build::print_rustc_flags().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_vial_config() {
|
||||
|
|
|
|||
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Bold.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Bold.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Italic.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Italic.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Light.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Light.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Medium.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Medium.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Regular.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Regular.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Thin.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-Thin.ttf
Normal file
Binary file not shown.
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf
Normal file
BIN
firmware2/fonts/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf
Normal file
Binary file not shown.
93
firmware2/fonts/IBM_Plex_Mono/OFL.txt
Normal file
93
firmware2/fonts/IBM_Plex_Mono/OFL.txt
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
use core::alloc::Layout;
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt::Debug;
|
||||
use core::slice;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::btree_map::BTreeMap;
|
||||
use alloc::string::String;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
|
|
@ -28,6 +30,20 @@ pub static KEY_MESSAGE_CHANNEL: Channel<CriticalSectionRawMutex, KeyMessage, 16>
|
|||
pub struct KeyMessage {
|
||||
pub keysym: Keysym,
|
||||
pub string: Option<String>,
|
||||
pub direction: KeyDirection,
|
||||
}
|
||||
|
||||
impl Debug for KeyMessage {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("KeyMessage")
|
||||
.field("keysym", &self.keysym)
|
||||
.field("string", &self.string)
|
||||
.field_with("direction", |f| match self.direction {
|
||||
KeyDirection::Down => f.write_str("Down"),
|
||||
KeyDirection::Up => f.write_str("Up"),
|
||||
})
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
|
@ -100,6 +116,9 @@ pub fn create_hid_report_interceptor() -> impl Future<Output = ()> {
|
|||
let mut state = xkb::State::new(&keymap);
|
||||
let mut previous_state = KeyboardReport::default();
|
||||
let mut compose_state = xkb::compose::State::new(&compose_table, xkb::compose::STATE_NO_FLAGS);
|
||||
// TODO: Use a stack-allocated map instead
|
||||
// This is a map from the basic keysyms (not a composed ones) to the string that should be produced.
|
||||
let mut pressed_keys_to_strings = BTreeMap::<Keysym, Option<String>>::new();
|
||||
|
||||
async move {
|
||||
loop {
|
||||
|
|
@ -152,7 +171,20 @@ pub fn create_hid_report_interceptor() -> impl Future<Output = ()> {
|
|||
|
||||
for keycode in released_keys {
|
||||
debug!("Release: 0x{:02x} ({})", keycode, keycode);
|
||||
state.update_key(into_xkb_keycode(keycode), KeyDirection::Up);
|
||||
let keycode_xkb = into_xkb_keycode(keycode);
|
||||
state.update_key(keycode_xkb, KeyDirection::Up);
|
||||
let keysym = state.key_get_one_sym(keycode_xkb);
|
||||
let string = pressed_keys_to_strings.remove(&keysym).unwrap_or_else(|| {
|
||||
warn!("Could not determine the string of a released key: keysym={keysym:?} pressed_keys_to_strings={pressed_keys_to_strings:?}");
|
||||
None
|
||||
});
|
||||
KEY_MESSAGE_CHANNEL
|
||||
.send(KeyMessage {
|
||||
keysym,
|
||||
string,
|
||||
direction: KeyDirection::Up,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
for keycode in pressed_keys {
|
||||
|
|
@ -160,10 +192,12 @@ pub fn create_hid_report_interceptor() -> impl Future<Output = ()> {
|
|||
let keycode_xkb = into_xkb_keycode(keycode);
|
||||
let sym = state.key_get_one_sym(keycode_xkb);
|
||||
|
||||
let result: Option<(Keysym, Option<String>)> = match compose_state.feed(sym) {
|
||||
let result: Option<(Keysym, Keysym, Option<String>)> = match compose_state
|
||||
.feed(sym)
|
||||
{
|
||||
FeedResult::Ignored => {
|
||||
let string = state.key_get_utf8(keycode_xkb);
|
||||
Some((sym, Some(string)))
|
||||
Some((sym, sym, Some(string)))
|
||||
}
|
||||
FeedResult::Accepted => {
|
||||
let status = compose_state.status();
|
||||
|
|
@ -171,28 +205,35 @@ pub fn create_hid_report_interceptor() -> impl Future<Output = ()> {
|
|||
match status {
|
||||
Status::Nothing => {
|
||||
let string = state.key_get_utf8(keycode_xkb);
|
||||
Some((sym, Some(string)))
|
||||
Some((sym, sym, Some(string)))
|
||||
}
|
||||
Status::Composing => None,
|
||||
Status::Composed => {
|
||||
let sym = compose_state.keysym().unwrap_or_default();
|
||||
let composed_sym = compose_state.keysym().unwrap_or_default();
|
||||
let string = compose_state.utf8().unwrap_or_default();
|
||||
Some((sym, Some(string)))
|
||||
Some((sym, composed_sym, Some(string)))
|
||||
}
|
||||
Status::Cancelled => None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some((keysym, string)) = result {
|
||||
if let Some((basic_keysym, composed_keysym, string)) = result {
|
||||
// Change `Some("")` into `None`.
|
||||
let string = string.filter(|string| !string.is_empty());
|
||||
|
||||
info!("Keysym: {keysym:?}");
|
||||
info!("String: {:?}", string.as_ref());
|
||||
info!(
|
||||
"Basic keysym: {basic_keysym:?}, composed keysym: {composed_keysym:?}, string: {:?}",
|
||||
string.as_ref()
|
||||
);
|
||||
|
||||
pressed_keys_to_strings.insert(basic_keysym, string.clone());
|
||||
KEY_MESSAGE_CHANNEL
|
||||
.send(KeyMessage { keysym, string })
|
||||
.send(KeyMessage {
|
||||
keysym: composed_keysym,
|
||||
string,
|
||||
direction: KeyDirection::Down,
|
||||
})
|
||||
.await;
|
||||
state.update_key(keycode_xkb, KeyDirection::Down);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#![feature(macro_metavar_expr)]
|
||||
#![feature(c_variadic)]
|
||||
#![feature(c_size_t)]
|
||||
#![feature(debug_closure_helpers)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ use ui::AppWindow;
|
|||
use xkbcommon::xkb::{self, FeedResult, KeyDirection, Keysym, Status};
|
||||
use {esp_alloc as _, esp_backtrace as _};
|
||||
|
||||
use crate::keymap::{KEY_MESSAGE_CHANNEL, hid_report, run_hid_report_interceptor};
|
||||
use crate::keymap::{KEY_MESSAGE_CHANNEL, create_hid_report_interceptor};
|
||||
use crate::matrix::IoeMatrix;
|
||||
use crate::peripherals::st7701s::St7701s;
|
||||
use crate::ui::backend::{FramebufferPtr, SlintBackend};
|
||||
|
|
@ -421,7 +422,7 @@ async fn main(_spawner: Spawner) {
|
|||
&mut storage,
|
||||
rmk_config,
|
||||
),
|
||||
hid_report(),
|
||||
create_hid_report_interceptor(),
|
||||
user_controller.event_loop(),
|
||||
alt_uart_rx_task
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use core::{cell::RefCell, time::Duration};
|
|||
|
||||
use alloc::rc::Rc;
|
||||
use esp_hal::time::Instant;
|
||||
use log::info;
|
||||
use log::{debug, info, warn};
|
||||
use slint::{
|
||||
PhysicalSize, SharedString, WindowSize,
|
||||
platform::{
|
||||
|
|
@ -60,17 +60,23 @@ impl slint::platform::Platform for SlintBackend {
|
|||
if let Some(window) = self.window.borrow().clone() {
|
||||
// Handle key presses
|
||||
while let Ok(key_message) = KEY_MESSAGE_CHANNEL.try_receive() {
|
||||
debug!("key_message = {key_message:?}");
|
||||
|
||||
let text = key_message.string.map(SharedString::from).or_else(|| {
|
||||
Key::try_from_keysym(key_message.keysym).map(SharedString::from)
|
||||
});
|
||||
|
||||
debug!("text = {text:?}");
|
||||
|
||||
if let Some(text) = text {
|
||||
window
|
||||
match key_message.direction {
|
||||
xkb::KeyDirection::Down => window
|
||||
.try_dispatch_event(WindowEvent::KeyPressed { text: text.clone() })
|
||||
.unwrap();
|
||||
window
|
||||
.try_dispatch_event(WindowEvent::KeyPressed { text })
|
||||
.unwrap();
|
||||
.unwrap(),
|
||||
xkb::KeyDirection::Up => window
|
||||
.try_dispatch_event(WindowEvent::KeyReleased { text })
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import { Button, VerticalBox, LineEdit, GridBox } from "std-widgets.slint";
|
||||
|
||||
// See https://github.com/slint-ui/slint/issues/4956 for issues with fonts.
|
||||
import "../fonts/IBM_Plex_Mono/IBMPlexMono-Regular.ttf";
|
||||
|
||||
export component AppWindow inherits Window {
|
||||
default-font-family: "IBM Plex Sans";
|
||||
in property <string> dummy: "ÄÖÜÁÉÍÓÚÝŔŚĹŹĆŃĚĽŽŠČŘĎŤŇŮÅäöüáéíóúýŕśĺźćńěľžščřďťňůåß„“”‘’—–@&$%+=¡¿¢£$¥€²³¼½¬¤¦§©®™°";
|
||||
default-font-family: "IBM Plex Mono";
|
||||
default-font-size: 16pt;
|
||||
height: 368px;
|
||||
width: 960px;
|
||||
|
|
@ -32,7 +36,7 @@ export component AppWindow inherits Window {
|
|||
}
|
||||
|
||||
LineEdit {
|
||||
input-type: InputType.password;
|
||||
input-type: InputType.text;
|
||||
text: "LineEdit";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue