├── src ├── widgets │ ├── window │ │ ├── ui_state.rs │ │ ├── inhibit.rs │ │ └── focus.rs │ ├── mod.rs │ ├── text_view.blp │ ├── text_view │ │ ├── accessibility.rs │ │ ├── scrolling.rs │ │ ├── caret.rs │ │ └── input.rs │ ├── custom_text_dialog.blp │ ├── results_view.blp │ ├── custom_text_dialog.rs │ └── text_language_dialog.blp ├── config.rs.in ├── settings.rs ├── main.rs ├── meson.build ├── application.rs ├── typing_test_utils.rs └── discord_rpc.rs ├── data ├── artwork │ ├── poster.png │ ├── square.png │ ├── symbolic.png │ ├── wordmark.png │ ├── lutris_title.png │ ├── steam_title.png │ ├── wordmark_black.png │ ├── wordmark_white.png │ └── icon │ │ ├── dev.bragefuglseth.Keypunch.png │ │ ├── meson.build │ │ └── dev.bragefuglseth.Keypunch-symbolic.svg ├── screenshots │ ├── 1-session.png │ ├── 2-ready.png │ ├── 3-results.png │ ├── 4-languages.png │ └── 5-custom-text.png ├── resources │ ├── icons │ │ └── scalable │ │ │ ├── actions │ │ │ ├── plus-large-symbolic.svg │ │ │ ├── edit-symbolic.svg │ │ │ ├── check-plain-symbolic.svg │ │ │ ├── quotation-symbolic.svg │ │ │ ├── arrow3-up-symbolic.svg │ │ │ ├── language-symbolic.svg │ │ │ ├── arrow-circular-top-right-symbolic.svg │ │ │ ├── heart-outline-thick-symbolic.svg │ │ │ ├── external-link-symbolic.svg │ │ │ └── timer-symbolic.svg │ │ │ └── apps │ │ │ └── dev.bragefuglseth.Fretboard.svg │ ├── style.css │ └── gtk │ │ └── help-overlay.ui ├── dev.bragefuglseth.Keypunch.desktop.in.in ├── word_lists │ ├── hu.txt │ ├── sk.txt │ ├── fr.txt │ ├── bn.txt │ ├── da.txt │ ├── ru.txt │ ├── sv.txt │ ├── nb.txt │ ├── hi.txt │ ├── nn.txt │ ├── he.txt │ ├── pl.txt │ ├── fa.txt │ ├── en.txt │ ├── cs.txt │ ├── de.txt │ ├── de_CH.txt │ ├── ar.txt │ ├── nl.txt │ ├── uk.txt │ ├── es.txt │ ├── bg.txt │ ├── ne.txt │ ├── tr.txt │ ├── sw.txt │ ├── rw.txt │ ├── pt.txt │ ├── ar_advanced.txt │ ├── it.txt │ ├── fi.txt │ ├── el.txt │ ├── pt_advanced.txt │ ├── et.txt │ ├── ro.txt │ ├── vn.txt │ ├── id.txt │ └── ko.txt ├── meson.build ├── dev.bragefuglseth.Keypunch.gschema.xml └── assets │ └── vipps_button.svg ├── scripts ├── json_to_word_list.sh ├── clear_data.sh └── update_translations.sh ├── po ├── meson.build ├── LINGUAS └── POTFILES.in ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── bug-report.md │ ├── suggestion.md │ └── language_request.yaml ├── FUNDING.yml └── workflows │ └── ci.yml ├── subprojects └── blueprint-compiler.wrap ├── .gitignore ├── meson_options.txt ├── meson.build ├── keypunch.doap ├── Cargo.toml ├── CONTRIBUTING.md └── README.md /src/widgets/window/ui_state.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/artwork/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/poster.png -------------------------------------------------------------------------------- /data/artwork/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/square.png -------------------------------------------------------------------------------- /data/artwork/symbolic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/symbolic.png -------------------------------------------------------------------------------- /data/artwork/wordmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/wordmark.png -------------------------------------------------------------------------------- /data/artwork/lutris_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/lutris_title.png -------------------------------------------------------------------------------- /data/artwork/steam_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/steam_title.png -------------------------------------------------------------------------------- /data/screenshots/1-session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/screenshots/1-session.png -------------------------------------------------------------------------------- /data/screenshots/2-ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/screenshots/2-ready.png -------------------------------------------------------------------------------- /data/screenshots/3-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/screenshots/3-results.png -------------------------------------------------------------------------------- /data/artwork/wordmark_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/wordmark_black.png -------------------------------------------------------------------------------- /data/artwork/wordmark_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/wordmark_white.png -------------------------------------------------------------------------------- /data/screenshots/4-languages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/screenshots/4-languages.png -------------------------------------------------------------------------------- /data/screenshots/5-custom-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/screenshots/5-custom-text.png -------------------------------------------------------------------------------- /scripts/json_to_word_list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for file in "$@" 4 | do 5 | jq -r '.words[]' $file > $file.tmp && mv $file.tmp $file 6 | done -------------------------------------------------------------------------------- /data/artwork/icon/dev.bragefuglseth.Keypunch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bragefuglseth/keypunch/HEAD/data/artwork/icon/dev.bragefuglseth.Keypunch.png -------------------------------------------------------------------------------- /scripts/clear_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf ~/.var/app/dev.bragefuglseth.Keypunch.Devel 4 | echo "Cleared ~/.var/app/dev.bragefuglseth.Keypunch.Devel" -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext( 2 | 'keypunch', 3 | preset: 'glib', 4 | args: [ 5 | '--keyword=i18n_fmt', 6 | '--keyword=i18n_nfmt:1,2' 7 | ] 8 | ) 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Help & Support 4 | url: https://matrix.to/#/#keypunch:gnome.org 5 | about: Ask questions and receive help -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: bragefuglseth 2 | custom: ['https://www.paypal.me/bragefuglseth', 'https://qr.vipps.no/box/c18bade5-d2c3-48a2-91ec-2eb235590bea/pay-in', 'https://qr.mobilepay.dk/box/c18bade5-d2c3-48a2-91ec-2eb235590bea/pay-in'] 3 | -------------------------------------------------------------------------------- /subprojects/blueprint-compiler.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | directory = blueprint-compiler 3 | url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git 4 | revision = main 5 | depth = 1 6 | 7 | [provide] 8 | program_names = blueprint-compiler -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | ar 2 | bg 3 | ca 4 | cs 5 | de 6 | el 7 | en_GB 8 | es 9 | eu 10 | fa 11 | fi 12 | fr 13 | he 14 | hi 15 | hu 16 | id 17 | it 18 | ka 19 | kab 20 | nb 21 | nl 22 | oc 23 | pl 24 | pt_BR 25 | ro 26 | ru 27 | sk 28 | sl 29 | sv 30 | tr 31 | uk 32 | uz 33 | zh_CN 34 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/plus-large-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /scripts/update_translations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR="translation-build/" 4 | if [ -d "$BUILD_DIR" ]; then 5 | rm -r translation-build 6 | fi 7 | 8 | meson translation-build 9 | meson compile -C translation-build keypunch-pot 10 | meson compile -C translation-build keypunch-update-po 11 | 12 | rm -r translation-build -------------------------------------------------------------------------------- /data/dev.bragefuglseth.Keypunch.desktop.in.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Keypunch 3 | Comment=Practice your typing skills 4 | Exec=keypunch 5 | Icon=@icon@ 6 | Terminal=false 7 | Type=Application 8 | Categories=Education; 9 | Keywords=typing;trainer;touch typing;keyboard;speed;wpm;words per minute;accuracy;test; 10 | StartupNotify=true 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Added by cargo 2 | 3 | /target 4 | 5 | .vscode/ 6 | target/ 7 | build/ 8 | _build/ 9 | builddir/ 10 | build-dir/ 11 | src/config.rs 12 | data/dev.bragefuglseth.Keypunch.metainfo.xml.in 13 | data/resources/dev.bragefuglseth.Keypunch.metainfo.xml 14 | .flatpak/ 15 | vendor 16 | .flatpak-builder 17 | .cargo 18 | /subprojects/blueprint-compiler 19 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'sandboxed', 3 | type : 'boolean', 4 | value : false, 5 | description: 'Whether the build happens in a sandbox.' + 6 | 'When that is the case, cargo will not be able to download the dependencies during' + 7 | 'the build so they are assumed to be in meson.project_source_root()/cargo' 8 | ) 9 | 10 | -------------------------------------------------------------------------------- /data/artwork/icon/meson.build: -------------------------------------------------------------------------------- 1 | scalable_dir = 'hicolor' / 'scalable' / 'apps' 2 | install_data( 3 | '@0@.svg'.format(app_id), 4 | install_dir: get_option('datadir') / 'icons' / scalable_dir 5 | ) 6 | 7 | symbolic_dir = 'hicolor' / 'symbolic' / 'apps' 8 | install_data( 9 | 'dev.bragefuglseth.Keypunch-symbolic.svg', 10 | install_dir: get_option('datadir') / 'icons' / symbolic_dir 11 | ) 12 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | data/dev.bragefuglseth.Keypunch.desktop.in.in 2 | data/dev.bragefuglseth.Keypunch.metainfo.xml.in.in 3 | data/dev.bragefuglseth.Keypunch.gschema.xml 4 | data/resources/gtk/help-overlay.ui 5 | src/widgets/custom_text_dialog.blp 6 | src/widgets/results_view.blp 7 | src/widgets/results_view.rs 8 | src/widgets/text_language_dialog.blp 9 | src/widgets/text_view.blp 10 | src/widgets/window.blp 11 | src/widgets/window.rs 12 | src/widgets/window/typing_test.rs 13 | src/widgets/window/ui_state.rs -------------------------------------------------------------------------------- /data/artwork/icon/dev.bragefuglseth.Keypunch-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('keypunch', 'rust', 2 | version: '6.3', 3 | meson_version: '>= 0.62.0', 4 | default_options: [ 'warning_level=2', 'werror=false', ], 5 | ) 6 | 7 | i18n = import('i18n') 8 | gnome = import('gnome') 9 | 10 | app_id = 'dev.bragefuglseth.Keypunch' 11 | 12 | if get_option('buildtype') != 'release' 13 | app_id += '.Devel' 14 | endif 15 | 16 | subdir('po') 17 | subdir('data') 18 | subdir('src') 19 | 20 | gnome.post_install( 21 | glib_compile_schemas: true, 22 | gtk_update_icon_cache: true, 23 | update_desktop_database: true, 24 | ) 25 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/edit-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [main] 4 | pull_request: 5 | 6 | name: CI 7 | 8 | jobs: 9 | 10 | flatpak: 11 | name: Flatpak 12 | runs-on: ubuntu-latest 13 | container: 14 | image: bilelmoussaoui/flatpak-github-actions:gnome-nightly 15 | options: --privileged 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: flathub-infra/flatpak-github-actions/flatpak-builder@master 19 | with: 20 | bundle: keypunch.flatpak 21 | manifest-path: build-aux/dev.bragefuglseth.Keypunch.Devel.json 22 | run-tests: true 23 | cache-key: flatpak-builder-${{ github.sha }} 24 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/check-plain-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/quotation-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/arrow3-up-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report something that isn't working as intended 4 | title: "[Bug]: " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | 29 | 30 | 31 | - [ ] I confirm that I can reproduce the bug in the Flathub version of the app. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/suggestion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Suggestion 3 | about: Suggest new functionality or changes to the app 4 | title: "[Suggestion]: " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your suggestion related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | 22 | 23 | 24 | - [ ] This suggestion is compatible with the [GNOME Human Interface Guidelines](https://developer.gnome.org/hig) 25 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/language-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/word_lists/hu.txt: -------------------------------------------------------------------------------- 1 | lapát 2 | vödör 3 | fuss 4 | játék 5 | nap 6 | hold 7 | éjszaka 8 | reggel 9 | délután 10 | címke 11 | ugrás 12 | kosár 13 | kosárlabda 14 | eszik 15 | csokoládé 16 | palacsinta 17 | labda 18 | teniszlabda 19 | denevér 20 | fejlesztő 21 | busz 22 | pilóta 23 | desszert 24 | egér 25 | kutya 26 | macska 27 | ital 28 | villa 29 | kanál 30 | kés 31 | táska 32 | iskola 33 | ceruza 34 | szín 35 | ebéd 36 | reggeli 37 | vacsora 38 | falatozás 39 | pénztárca 40 | fürdőszoba 41 | mosogató 42 | kád 43 | zuhany 44 | kazán 45 | mosógép 46 | mosó 47 | szárítógép 48 | száraz 49 | lány 50 | fiú 51 | férfi 52 | női 53 | ők 54 | őket 55 | csinál 56 | bor 57 | víz 58 | kávé 59 | sör 60 | nehéz 61 | könnyű 62 | csúnya 63 | gyönyörű 64 | szép 65 | rossz 66 | jó 67 | nagy 68 | kicsi 69 | bocsánat 70 | szívesen 71 | köszönöm 72 | igen 73 | nem 74 | viszontlátásra 75 | viszlát 76 | szia 77 | szervusz 78 | káröröm 79 | ordít 80 | csendes 81 | hangos 82 | elmosolyodik 83 | bezzeg 84 | megcsörget 85 | ügyeskedő 86 | rosszarcú 87 | meghazudtol 88 | szöszmötöl 89 | -------------------------------------------------------------------------------- /src/config.rs.in: -------------------------------------------------------------------------------- 1 | /* config.rs.in 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | pub static APP_ID: &str = @APP_ID@; 21 | pub static _VERSION: &str = @VERSION@; 22 | pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@; 23 | pub static LOCALEDIR: &str = @LOCALEDIR@; 24 | pub static _PKGDATADIR: &str = @PKGDATADIR@; 25 | -------------------------------------------------------------------------------- /data/resources/style.css: -------------------------------------------------------------------------------- 1 | KpTextView { 2 | transition: filter 200ms; 3 | } 4 | 5 | KpTextView.unfocused { 6 | filter: blur(3px); 7 | } 8 | 9 | KpTextView > textview { 10 | font-size: 1.5rem; 11 | line-height: 50px; /* This needs to mirror the value in `src/widgets/text_view.rs` */ 12 | background: none; 13 | font-variant-ligatures: none; 14 | } 15 | 16 | KpResultsView .key-number { 17 | font-size: 3.5rem; 18 | font-weight: 700; 19 | } 20 | 21 | headerbar .start, 22 | headerbar .end, 23 | window.hide-controls headerbar.test:focus-within .start, 24 | window.hide-controls headerbar.test:focus-within .end { 25 | opacity: 1; 26 | transition: opacity 200ms; 27 | } 28 | 29 | window.hide-controls headerbar.test .start, 30 | window.hide-controls headerbar.test .end { 31 | opacity: 0; 32 | } 33 | 34 | .card-text-view { 35 | padding: 12px; 36 | color: var(--card-fg-color); 37 | background: var(--card-bg-color); 38 | } 39 | 40 | .toolbar-thick { 41 | padding: 12px; 42 | } 43 | 44 | .status-icon { 45 | -gtk-icon-size: 96px; 46 | } 47 | 48 | .pill-entry { 49 | border-radius: 9999px; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/arrow-circular-top-right-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/settings.rs: -------------------------------------------------------------------------------- 1 | use gtk::gio; 2 | use gtk::prelude::*; 3 | 4 | // Must match their corresponding gschema enumss 5 | pub const SESSION_TYPE_VALUES: &'static [&str] = &["Simple", "Advanced", "Custom"]; 6 | pub const SESSION_DURATION_VALUES: &'static [&str] = &["Sec15", "Sec30", "Min1", "Min5", "Min10"]; 7 | 8 | pub fn bind_dropdown_selected( 9 | settings: &gio::Settings, 10 | dropdown: >k::DropDown, 11 | key: &str, 12 | values: &'static [&str], 13 | ) { 14 | settings 15 | .bind(key, dropdown, "selected") 16 | .mapping(|stored_variant, _| { 17 | let index = values 18 | .iter() 19 | .position(|value| *value == stored_variant.get::().unwrap()) 20 | .expect("values array corresponds to gschema enum"); 21 | Some((index as u32).to_value()) 22 | }) 23 | .set_mapping(|index_value, _| { 24 | let value = values 25 | .get(index_value.get::().unwrap() as usize) 26 | .expect("values array corresponds to gschema enum") 27 | .to_variant(); 28 | Some(value) 29 | }) 30 | .build(); 31 | } 32 | -------------------------------------------------------------------------------- /src/widgets/mod.rs: -------------------------------------------------------------------------------- 1 | /* mod.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | mod custom_text_dialog; 21 | mod results_view; 22 | mod text_language_dialog; 23 | mod text_view; 24 | mod window; 25 | 26 | pub use custom_text_dialog::KpCustomTextDialog; 27 | pub use results_view::KpResultsView; 28 | pub use text_language_dialog::KpTextLanguageDialog; 29 | pub use text_view::KpTextView; 30 | pub use window::KpWindow; 31 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/heart-outline-thick-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/widgets/text_view.blp: -------------------------------------------------------------------------------- 1 | /* text_view.blp 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | using Gtk 4.0; 21 | 22 | template $KpTextView: Widget { 23 | focusable: true; 24 | overflow: hidden; 25 | accessible-role: text_box; 26 | 27 | accessibility { 28 | label: _("Text View"); 29 | multi-line: true; 30 | } 31 | 32 | TextView text_view { 33 | monospace: true; 34 | focusable: false; 35 | editable: false; 36 | wrap-mode: word_char; 37 | accessible-role: presentation; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/external-link-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/actions/timer-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /keypunch.doap: -------------------------------------------------------------------------------- 1 | 6 | 7 | Keypunch 8 | Practice your typing skills 9 | 10 | 11 | 12 | Rust 13 | GTK 4 14 | Libadwaita 15 | 16 | 17 | 18 | Brage Fuglseth 19 | 20 | 21 | 22 | 23 | bragefuglseth 24 | 25 | 26 | 27 | 28 | 29 | bragefuglseth 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/widgets/window/inhibit.rs: -------------------------------------------------------------------------------- 1 | /* inhibit.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use super::*; 21 | 22 | impl imp::KpWindow { 23 | pub(super) fn inhibit_session(&self, reason: &str) { 24 | self.end_existing_inhibit(); 25 | 26 | let cookie = self.obj().kp_application().inhibit( 27 | Some(self.obj().upcast_ref::()), 28 | gtk::ApplicationInhibitFlags::LOGOUT, 29 | Some(&reason), 30 | ); 31 | 32 | self.inhibit_cookie.set(Some(cookie)); 33 | } 34 | 35 | pub(super) fn end_existing_inhibit(&self) { 36 | if let Some(cookie) = self.inhibit_cookie.take() { 37 | self.obj().kp_application().uninhibit(cookie); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | # Cargo.toml 2 | # 3 | # SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | [package] 20 | name = "keypunch" 21 | version = "0.1.0" 22 | edition = "2021" 23 | 24 | [dependencies] 25 | discord-presence = "1.5.0" 26 | # Locked to 0.7.0 because of https://github.com/hfiguiere/i18n-format/issues/1 27 | gettext-rs = { version = "=0.7.0", features = ["gettext-system"] } 28 | gvdb-macros = "0.1.12" 29 | i18n-format = "0.2.0" 30 | include_dir = "0.7.3" 31 | rand = "0.8.5" 32 | rayon = "1.10.0" 33 | strum = "0.26.2" 34 | strum_macros = "0.26.2" 35 | unicode-segmentation = "1.11.0" 36 | unidecode = "0.3.0" 37 | 38 | [dependencies.gtk] 39 | package = "gtk4" 40 | version = "0.9" 41 | features = ["v4_16", "blueprint"] 42 | 43 | [dependencies.adw] 44 | package = "libadwaita" 45 | version = "0.7.1" 46 | features = ["v1_7"] 47 | -------------------------------------------------------------------------------- /data/word_lists/sk.txt: -------------------------------------------------------------------------------- 1 | jeho 2 | že 3 | pre 4 | sú 5 | s 6 | byť 7 | jeden 8 | majú 9 | tento 10 | od 11 | slovo 12 | ale 13 | čo 14 | niektorí 15 | to 16 | ste 17 | alebo 18 | mal 19 | biela 20 | a 21 | v 22 | sme 23 | moci 24 | ďalšie 25 | boli 26 | ktorý 27 | robiť 28 | ich 29 | čas 30 | ak 31 | vôľa 32 | uvedený 33 | píla 34 | povedať 35 | robí 36 | sada 37 | tri 38 | chcieť 39 | vzduch 40 | dobre 41 | tiež 42 | hrať 43 | malé 44 | koniec 45 | domáce 46 | čítať 47 | ručné 48 | prístav 49 | kúzlo 50 | pridať 51 | dokonca 52 | musí 53 | vysoká 54 | taký 55 | nasledovať 56 | akt 57 | prečo 58 | opýtať 59 | muži 60 | zmena 61 | šiel 62 | svetlo 63 | druh 64 | dom 65 | obrázok 66 | skúste 67 | znova 68 | bod 69 | svet 70 | blízkosti 71 | stavať 72 | otec 73 | akýkoľvek 74 | nový 75 | časť 76 | so 77 | miesto 78 | žiť 79 | kde 80 | po 81 | späť 82 | málo 83 | iba 84 | kolo 85 | muž 86 | rok 87 | prišiel 88 | výstava 89 | dobrý 90 | ma 91 | naše 92 | pod 93 | názov 94 | veľmi 95 | len 96 | forma 97 | veta 98 | myslíte 99 | hovoria 100 | pomoc 101 | nízky 102 | linka 103 | líšia 104 | príčina 105 | stredná 106 | pred 107 | právo 108 | chlapec 109 | starý 110 | príliš 111 | rovnaký 112 | ona 113 | všetky 114 | kedy 115 | použitie 116 | vaše 117 | o 118 | potom 119 | napísať 120 | by 121 | tak 122 | tieto 123 | nej 124 | dlho 125 | aby 126 | vec 127 | viď 128 | ho 129 | dva 130 | má 131 | hľadať 132 | viac 133 | deň 134 | mohol 135 | ísť 136 | prísť 137 | áno 138 | číslo 139 | zvuk 140 | nie 141 | najviac 142 | ľudia 143 | my 144 | vedieť 145 | voda 146 | volanie 147 | prvý 148 | kto 149 | mája 150 | dole 151 | strana 152 | teraz 153 | nájsť 154 | podľa 155 | svoj 156 | môcť 157 | človek 158 | borovička 159 | žena 160 | mesto 161 | sa 162 | na 163 | veľký 164 | ja 165 | krajiny 166 | z 167 | každý 168 | dať 169 | tu 170 | cesta 171 | veľa 172 | je 173 | ako 174 | cez 175 | bol 176 | matka 177 | zviera -------------------------------------------------------------------------------- /src/widgets/text_view/accessibility.rs: -------------------------------------------------------------------------------- 1 | /* accessibility.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use super::*; 21 | 22 | impl imp::KpTextView { 23 | pub(super) fn update_accessible_state(&self) { 24 | let typed_len = self.typed_text.borrow().chars().count(); 25 | 26 | let original_text = self.original_text.borrow(); 27 | 28 | let current_word_start = original_text.chars().take(typed_len).enumerate().fold( 29 | 0, 30 | |previous_index, (index, c)| { 31 | if c.is_whitespace() { 32 | index + 1 33 | } else { 34 | previous_index 35 | } 36 | }, 37 | ); 38 | 39 | let current_word: String = original_text 40 | .chars() 41 | .skip(current_word_start) 42 | .take_while(|c| !c.is_whitespace()) 43 | .collect(); 44 | 45 | let pos_in_current_word = typed_len.checked_sub(current_word_start).unwrap_or(0); 46 | if pos_in_current_word == 0 { 47 | let obj = self.obj(); 48 | obj.update_property(&[gtk::accessible::Property::Label(¤t_word)]); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /data/word_lists/fr.txt: -------------------------------------------------------------------------------- 1 | a 2 | à 3 | acte 4 | aider 5 | air 6 | ajouter 7 | aller 8 | animal 9 | année 10 | appel 11 | après 12 | arrière 13 | aucun 14 | aussi 15 | autre 16 | avant 17 | avec 18 | avoir 19 | bas 20 | beaucoup 21 | besoin 22 | bien 23 | boîte 24 | bon 25 | cause 26 | ce 27 | certains 28 | ces 29 | changement 30 | chaque 31 | chaud 32 | chose 33 | comme 34 | comment 35 | construire 36 | côté 37 | dans 38 | de 39 | dehors 40 | déménagement 41 | deux 42 | différer 43 | dire 44 | dit 45 | donner 46 | droit 47 | eau 48 | écrire 49 | elle 50 | encore 51 | ensemble 52 | épeler 53 | essayer 54 | est allé 55 | est venu 56 | est 57 | et 58 | étaient 59 | était 60 | été 61 | être 62 | eu 63 | fabriqué 64 | faible 65 | faire 66 | fait 67 | faut 68 | fin 69 | forme 70 | garçon 71 | genre 72 | grand 73 | haut 74 | homme 75 | hommes 76 | ici 77 | il 78 | ils 79 | image 80 | interroger 81 | je 82 | jouer 83 | jour 84 | juste 85 | la 86 | là 87 | le 88 | les 89 | leur 90 | lieu 91 | ligne 92 | lire 93 | long 94 | lui 95 | lumière 96 | ma 97 | main 98 | maintenant 99 | mais 100 | maison 101 | manière 102 | même 103 | mère 104 | mettre 105 | moi 106 | monde 107 | montrer 108 | mot 109 | ne 110 | nom 111 | nombre 112 | notre 113 | nous 114 | nouveau 115 | obtenir 116 | ou 117 | où 118 | par 119 | partie 120 | partir 121 | penser 122 | père 123 | personnes 124 | petit 125 | peu 126 | peut 127 | phrase 128 | plus 129 | point 130 | port 131 | pour 132 | pourquoi 133 | pourrait 134 | première 135 | prendre 136 | près 137 | puis 138 | quand 139 | que 140 | qui 141 | regarder 142 | savoir 143 | seulement 144 | si 145 | signifier 146 | soi 147 | son 148 | sont 149 | sous 150 | suivre 151 | sur 152 | tel 153 | temps 154 | terre 155 | tour 156 | tous 157 | tout 158 | travail 159 | très 160 | trois 161 | trop 162 | trouver 163 | un 164 | utiliser 165 | venir 166 | vers 167 | vieux 168 | vivre 169 | voir 170 | volonté 171 | votre 172 | voudrais 173 | vouloir 174 | vous 175 | -------------------------------------------------------------------------------- /data/word_lists/bn.txt: -------------------------------------------------------------------------------- 1 | আমি 2 | না 3 | তুমি 4 | আমার 5 | কি 6 | এটা 7 | আর 8 | তোমার 9 | আছে 10 | সে 11 | এই 12 | আমরা 13 | করে 14 | হবে 15 | জন্য 16 | আমাদের 17 | করতে 18 | একটা 19 | আমাকে 20 | ঠিক 21 | আপনি 22 | তো 23 | যে 24 | তার 25 | থেকে 26 | কিছু 27 | সাথে 28 | কিন্তু 29 | এখানে 30 | তোমাকে 31 | এখন 32 | কোন 33 | কথা 34 | মনে 35 | কী 36 | যদি 37 | এবং 38 | হয় 39 | আপনার 40 | নিয়ে 41 | ছিল 42 | তাকে 43 | তারা 44 | নেই 45 | হয়ে 46 | তাহলে 47 | অনেক 48 | কেন 49 | করা 50 | হ্যাঁ 51 | করো 52 | তাই 53 | সব 54 | এক 55 | এর 56 | হচ্ছে 57 | যাও 58 | কাজ 59 | হয়েছে 60 | ও 61 | কে 62 | কাছে 63 | শুধু 64 | একটি 65 | স্যার 66 | দাও 67 | তাদের 68 | ভালো 69 | যা 70 | একজন 71 | ভাল 72 | জানি 73 | যেতে 74 | দিয়ে 75 | খুব 76 | কোথায় 77 | করবে 78 | যাবে 79 | চাই 80 | পারে 81 | শেষ 82 | করার 83 | ধন্যবাদ 84 | যখন 85 | বলতে 86 | কেউ 87 | করি 88 | সময় 89 | তুই 90 | গেছে 91 | বাবা 92 | ওকে 93 | মত 94 | সেটা 95 | হতে 96 | চলে 97 | ওহ 98 | নয় 99 | হ্যা 100 | একটু 101 | পারি 102 | দেখতে 103 | সবাই 104 | আগে 105 | দেখা 106 | করছি 107 | তিনি 108 | বের 109 | বলে 110 | ঐ 111 | কর 112 | আবার 113 | দিতে 114 | নাম 115 | যায় 116 | ওর 117 | পারবে 118 | নাকি 119 | কিভাবে 120 | মধ্যে 121 | তোমরা 122 | ফিরে 123 | আচ্ছা 124 | সাহায্য 125 | আপনাকে 126 | মানুষ 127 | তা 128 | মা 129 | করেছে 130 | দিকে 131 | দরকার 132 | সেই 133 | আসলে 134 | শুরু 135 | ওটা 136 | দুঃখিত 137 | দিন 138 | চলো 139 | মানে 140 | তোর 141 | তোমাদের 142 | করছে 143 | বলছি 144 | বিশ্বাস 145 | বন্ধ 146 | করেছি 147 | এমন 148 | অবশ্যই 149 | নিজের 150 | কারণ 151 | বড় 152 | করবো 153 | বেশি 154 | বছর 155 | উপর 156 | যাচ্ছে 157 | আসো 158 | চেষ্টা 159 | তারপর 160 | হল 161 | হেই 162 | এসব 163 | দেখো 164 | কিছুই 165 | কোনো 166 | এটাই 167 | আছি 168 | টাকা 169 | যাচ্ছি 170 | জানো 171 | বুঝতে 172 | আজ 173 | ছিলো 174 | বলো 175 | মতো 176 | ধরে 177 | কখনো 178 | খারাপ 179 | কেমন 180 | প্লিজ 181 | মারা 182 | পছন্দ 183 | সেখানে 184 | চাও 185 | নাও 186 | সমস্যা 187 | দেখে 188 | নি 189 | পর 190 | থাকে 191 | এখনো 192 | সুন্দর 193 | তখন 194 | ভুল 195 | ভাই 196 | ওখানে 197 | পর্যন্ত 198 | -------------------------------------------------------------------------------- /data/word_lists/da.txt: -------------------------------------------------------------------------------- 1 | ville 2 | ud 3 | første 4 | siden 5 | gang 6 | giver 7 | komme 8 | nok 9 | i 10 | kun 11 | min 12 | måtte 13 | dig 14 | langt 15 | man 16 | ham 17 | være 18 | sine 19 | for 20 | nogen 21 | endnu 22 | have 23 | hende 24 | havde 25 | os 26 | flere 27 | du 28 | blandt 29 | står 30 | sin 31 | tror 32 | får 33 | samme 34 | allerede 35 | hvordan 36 | noget 37 | har 38 | på 39 | alle 40 | ved 41 | dem 42 | fået 43 | gør 44 | give 45 | sådan 46 | hver 47 | gennem 48 | også 49 | han 50 | vi 51 | se 52 | år 53 | del 54 | unge 55 | hvis 56 | nu 57 | det 58 | men 59 | at 60 | om 61 | lidt 62 | kom 63 | tid 64 | mig 65 | ny 66 | selv 67 | sige 68 | tilbage 69 | arbejde 70 | andre 71 | skal 72 | disse 73 | stor 74 | alt 75 | altså 76 | altid 77 | ingen 78 | to 79 | frem 80 | helt 81 | går 82 | mod 83 | gøre 84 | derfor 85 | af 86 | måde 87 | måske 88 | næsten 89 | mens 90 | dog 91 | synes 92 | kommer 93 | jo 94 | jeg 95 | mindre 96 | blev 97 | par 98 | god 99 | godt 100 | gamle 101 | folk 102 | fik 103 | sidste 104 | da 105 | dansk 106 | dag 107 | omkring 108 | under 109 | mand 110 | når 111 | siger 112 | et 113 | en 114 | dette 115 | vil 116 | tale 117 | ja 118 | ind 119 | netop 120 | bare 121 | hos 122 | er 123 | hele 124 | der 125 | deres 126 | med 127 | som 128 | tage 129 | først 130 | både 131 | mange 132 | de 133 | til 134 | mennesker 135 | her 136 | mere 137 | været 138 | aldrig 139 | igen 140 | kunne 141 | meget 142 | få 143 | lille 144 | denne 145 | lige 146 | nogle 147 | fordi 148 | mellem 149 | før 150 | stadig 151 | over 152 | blive 153 | ikke 154 | mest 155 | var 156 | vores 157 | ligger 158 | sagde 159 | mon 160 | ned 161 | sig 162 | gå 163 | hun 164 | eller 165 | uden 166 | hvad 167 | andet 168 | hvor 169 | verden 170 | så 171 | ser 172 | skulle 173 | gik 174 | tidligere 175 | sammen 176 | kan 177 | tre 178 | fra 179 | mit 180 | heller 181 | side 182 | anden 183 | efter 184 | store 185 | mener 186 | må 187 | end 188 | op 189 | hovedet 190 | gav 191 | ca 192 | danske 193 | rigtig 194 | døren 195 | finde 196 | børn 197 | -------------------------------------------------------------------------------- /data/word_lists/ru.txt: -------------------------------------------------------------------------------- 1 | о 2 | у 3 | и 4 | я 5 | к 6 | в 7 | а 8 | со 9 | да 10 | не 11 | уж 12 | же 13 | по 14 | об 15 | во 16 | ну 17 | за 18 | на 19 | он 20 | вы 21 | ни 22 | но 23 | бы 24 | ли 25 | мы 26 | из 27 | ты 28 | до 29 | от 30 | они 31 | раз 32 | мир 33 | кто 34 | для 35 | уже 36 | нет 37 | еще 38 | она 39 | над 40 | так 41 | вот 42 | тот 43 | что 44 | ваш 45 | про 46 | дом 47 | час 48 | это 49 | там 50 | наш 51 | чем 52 | сам 53 | где 54 | при 55 | как 56 | ряд 57 | мой 58 | без 59 | вид 60 | под 61 | тут 62 | год 63 | или 64 | отец 65 | друг 66 | сила 67 | дело 68 | если 69 | жить 70 | день 71 | тоже 72 | свет 73 | свой 74 | твой 75 | мочь 76 | весь 77 | есть 78 | надо 79 | свое 80 | идти 81 | ночь 82 | стол 83 | пока 84 | нога 85 | рука 86 | вода 87 | дать 88 | быть 89 | хотя 90 | лицо 91 | лишь 92 | себя 93 | жена 94 | даже 95 | этот 96 | ведь 97 | куда 98 | много 99 | иметь 100 | никто 101 | тогда 102 | пойти 103 | время 104 | земля 105 | новый 106 | когда 107 | какой 108 | здесь 109 | после 110 | хочет 111 | сразу 112 | такой 113 | выйти 114 | стать 115 | знать 116 | почти 117 | опять 118 | более 119 | самый 120 | белый 121 | очень 122 | перед 123 | слово 124 | город 125 | ничто 126 | потом 127 | место 128 | чтобы 129 | жизнь 130 | между 131 | конец 132 | вдруг 133 | дверь 134 | снова 135 | через 136 | взять 137 | можно 138 | начало 139 | давать 140 | работа 141 | другой 142 | хотеть 143 | каждый 144 | сидеть 145 | страна 146 | деньги 147 | видеть 148 | минута 149 | старый 150 | потому 151 | делать 152 | голова 153 | правда 154 | бывать 155 | вопрос 156 | понять 157 | стоять 158 | теперь 159 | просто 160 | только 161 | почему 162 | всегда 163 | думать 164 | машина 165 | значить 166 | кровать 167 | сторона 168 | человек 169 | молчать 170 | ребенок 171 | главный 172 | должный 173 | женщина 174 | увидеть 175 | сказать 176 | сделать 177 | который 178 | ответить 179 | казаться 180 | подумать 181 | понимать 182 | работать 183 | спросить 184 | смотреть 185 | оказаться 186 | показаться 187 | радоваться 188 | посмотреть 189 | отказываться -------------------------------------------------------------------------------- /data/word_lists/sv.txt: -------------------------------------------------------------------------------- 1 | jag 2 | det 3 | är 4 | du 5 | inte 6 | att 7 | en 8 | och 9 | har 10 | vi 11 | på 12 | i 13 | för 14 | han 15 | vad 16 | med 17 | mig 18 | som 19 | här 20 | om 21 | dig 22 | var 23 | den 24 | så 25 | till 26 | kan 27 | de 28 | ni 29 | ska 30 | ett 31 | men 32 | av 33 | vill 34 | nu 35 | ja 36 | vet 37 | nej 38 | bara 39 | hon 40 | kommer 41 | hur 42 | min 43 | där 44 | honom 45 | gör 46 | kom 47 | måste 48 | din 49 | skulle 50 | då 51 | bra 52 | när 53 | ha 54 | er 55 | ta 56 | ut 57 | får 58 | man 59 | vara 60 | oss 61 | göra 62 | dem 63 | eller 64 | varför 65 | alla 66 | från 67 | okej 68 | upp 69 | tror 70 | igen 71 | gå 72 | tack 73 | sa 74 | hade 75 | allt 76 | in 77 | sig 78 | se 79 | ingen 80 | få 81 | henne 82 | lite 83 | mycket 84 | vem 85 | går 86 | ser 87 | mitt 88 | hej 89 | aldrig 90 | kanske 91 | behöver 92 | finns 93 | nåt 94 | blir 95 | än 96 | inget 97 | efter 98 | bli 99 | något 100 | ju 101 | två 102 | tar 103 | tillbaka 104 | hans 105 | över 106 | säger 107 | sen 108 | ge 109 | mer 110 | ditt 111 | gjorde 112 | någon 113 | mina 114 | ner 115 | åt 116 | väl 117 | vänta 118 | också 119 | fick 120 | nån 121 | säga 122 | år 123 | kunde 124 | låt 125 | varit 126 | detta 127 | hit 128 | nog 129 | pappa 130 | andra 131 | mamma 132 | hela 133 | mot 134 | vid 135 | känner 136 | några 137 | komma 138 | rätt 139 | borde 140 | menar 141 | själv 142 | alltid 143 | dina 144 | hem 145 | gjort 146 | ville 147 | såg 148 | dom 149 | verkligen 150 | titta 151 | dag 152 | utan 153 | fel 154 | tre 155 | visst 156 | prata 157 | vår 158 | liv 159 | förstår 160 | sätt 161 | tog 162 | älskar 163 | blev 164 | håll 165 | döda 166 | tid 167 | tycker 168 | sluta 169 | trodde 170 | precis 171 | säg 172 | bort 173 | gillar 174 | gång 175 | gud 176 | sin 177 | tänker 178 | hör 179 | veta 180 | just 181 | bättre 182 | många 183 | berätta 184 | gick 185 | barn 186 | hjälp 187 | god 188 | händer 189 | under 190 | innan 191 | visste 192 | sett 193 | helt 194 | folk 195 | förlåt 196 | pengar 197 | död 198 | hjälpa 199 | pojke 200 | flicka 201 | -------------------------------------------------------------------------------- /data/word_lists/nb.txt: -------------------------------------------------------------------------------- 1 | i 2 | og 3 | det 4 | er 5 | til 6 | en 7 | av 8 | på 9 | for 10 | at 11 | å 12 | med 13 | de 14 | har 15 | den 16 | ikke 17 | et 18 | fra 19 | var 20 | han 21 | men 22 | seg 23 | deg 24 | jeg 25 | kan 26 | ble 27 | vil 28 | skal 29 | sier 30 | etter 31 | så 32 | år 33 | også 34 | hun 35 | dette 36 | ved 37 | da 38 | blir 39 | nå 40 | ut 41 | være 42 | hadde 43 | over 44 | mot 45 | eller 46 | to 47 | må 48 | går 49 | få 50 | andre 51 | opp 52 | sin 53 | når 54 | du 55 | bare 56 | alle 57 | ha 58 | enn 59 | mer 60 | denne 61 | selv 62 | noe 63 | mange 64 | inn 65 | bli 66 | noen 67 | vært 68 | får 69 | før 70 | der 71 | man 72 | kroner 73 | nye 74 | dag 75 | ting 76 | flere 77 | fikk 78 | første 79 | under 80 | slik 81 | siden 82 | mye 83 | dårlig 84 | kommer 85 | både 86 | kunne 87 | meg 88 | mellom 89 | hva 90 | tre 91 | her 92 | store 93 | mener 94 | ingen 95 | dem 96 | oss 97 | hele 98 | sine 99 | siste 100 | gang 101 | skulle 102 | hans 103 | ta 104 | helt 105 | godt 106 | sammen 107 | sa 108 | kom 109 | håper 110 | hvor 111 | nok 112 | hjemme 113 | alt 114 | blant 115 | tid 116 | sitt 117 | ville 118 | uten 119 | blitt 120 | igjen 121 | tidligere 122 | fått 123 | rundt 124 | ny 125 | samme 126 | mens 127 | annet 128 | gjennom 129 | disse 130 | litt 131 | stor 132 | står 133 | gjør 134 | gå 135 | ser 136 | gjøre 137 | gikk 138 | folk 139 | ned 140 | ham 141 | se 142 | hvis 143 | derfor 144 | gamle 145 | fire 146 | fordi 147 | mest 148 | god 149 | tar 150 | tilbake 151 | gir 152 | barn 153 | like 154 | neste 155 | gi 156 | kanskje 157 | langt 158 | tatt 159 | del 160 | bedre 161 | komme 162 | saken 163 | ønsker 164 | tror 165 | viser 166 | først 167 | måtte 168 | aldri 169 | side 170 | ligger 171 | si 172 | min 173 | hvordan 174 | hos 175 | tok 176 | bør 177 | beste 178 | vår 179 | grunn 180 | hver 181 | sett 182 | vel 183 | gjort 184 | land 185 | allerede 186 | frem 187 | heller 188 | gode 189 | vet 190 | jo 191 | tiden 192 | begge 193 | finnes 194 | foto 195 | fram 196 | plass 197 | mennesker 198 | gjorde 199 | mine 200 | om 201 | -------------------------------------------------------------------------------- /data/word_lists/hi.txt: -------------------------------------------------------------------------------- 1 | में 2 | है 3 | हैं 4 | नहीं 5 | लिए 6 | गया 7 | तथा 8 | अपने 9 | कुछ 10 | साथ 11 | होता 12 | था 13 | दिया 14 | हुए 15 | कोई 16 | रूप 17 | से 18 | मैं 19 | रहा 20 | हुआ 21 | बात 22 | कहा 23 | समय 24 | क्या 25 | अपनी 26 | होती 27 | प्रकार 28 | बहुत 29 | तरह 30 | बाद 31 | फिर 32 | रहे 33 | द्वारा 34 | अधिक 35 | रही 36 | होने 37 | एवं 38 | हुई 39 | थे 40 | उनके 41 | थी 42 | वाले 43 | चाहिए 44 | दिन 45 | लेकिन 46 | काम 47 | हूँ 48 | होते 49 | इसके 50 | उन्हें 51 | गये 52 | कभी 53 | आदि 54 | लोग 55 | बार 56 | यहाँ 57 | दोनों 58 | उन्होंने 59 | कार्य 60 | पास 61 | वहाँ 62 | भारत 63 | लिया 64 | प्राप्त 65 | उनकी 66 | लोगों 67 | गयी 68 | लगा 69 | अन्य 70 | होगा 71 | इसी 72 | देश 73 | यदि 74 | सभी 75 | नाम 76 | वर्ष 77 | ऐसा 78 | विकास 79 | अपना 80 | ऐसे 81 | दूसरे 82 | हाथ 83 | भाषा 84 | मेरे 85 | मैंने 86 | तुम 87 | बीच 88 | वाली 89 | बड़े 90 | प्रति 91 | व्यक्ति 92 | उनका 93 | लिये 94 | इसलिए 95 | तीन 96 | इसका 97 | ऐसी 98 | विशेष 99 | बड़ी 100 | अथवा 101 | भाग 102 | क्योंकि 103 | सिंह 104 | ठीक 105 | स्थिति 106 | परन्तु 107 | स्थान 108 | यही 109 | क्यों 110 | गाँव 111 | राज्य 112 | अलग 113 | लेकर 114 | अभी 115 | इसमें 116 | विभिन्न 117 | सी 118 | विचार 119 | जिस 120 | बाहर 121 | ऊपर 122 | बना 123 | तैयार 124 | अनेक 125 | सामने 126 | शिक्षा 127 | शरीर 128 | होकर 129 | दृष्टि 130 | श्री 131 | थीं 132 | दूर 133 | शब्द 134 | ध्यान 135 | चार 136 | मेरी 137 | बड़ा 138 | पता 139 | लगता 140 | आगे 141 | किया 142 | उत्तर 143 | किन्तु 144 | आने 145 | लगे 146 | लगभग 147 | इसे 148 | लाख 149 | बारे 150 | होना 151 | इससे 152 | मात्रा 153 | अध्ययन 154 | वाला 155 | जिसमें 156 | नीचे 157 | अर्थ 158 | लोक 159 | आवश्यक 160 | हो 161 | माँ 162 | छोटे 163 | प्रतिशत 164 | शुरू 165 | अगर 166 | इतना 167 | आया 168 | होगी 169 | मिल 170 | स्वयं 171 | रात 172 | बिना 173 | हमें 174 | उपयोग 175 | किए 176 | महत्वपूर्ण 177 | मुख्य 178 | साल 179 | ज्यादा 180 | साहित्य 181 | पूर्व 182 | निर्माण 183 | विषय 184 | जिससे 185 | देख 186 | चित्र 187 | लगी 188 | प्रत्येक 189 | मनुष्य 190 | गई 191 | स्पष्ट 192 | दिनों 193 | रंग 194 | इसकी 195 | स्तर 196 | मेरा 197 | दूसरी 198 | अच्छा 199 | रोग 200 | काल 201 | -------------------------------------------------------------------------------- /data/word_lists/nn.txt: -------------------------------------------------------------------------------- 1 | i 2 | og 3 | som 4 | er 5 | det 6 | av 7 | på 8 | til 9 | ein 10 | å 11 | for 12 | dei 13 | med 14 | at 15 | har 16 | var 17 | den 18 | han 19 | om 20 | eit 21 | frå 22 | ikkje 23 | ei 24 | kan 25 | eller 26 | eg 27 | seg 28 | men 29 | vart 30 | dette 31 | hjå 32 | hadde 33 | ut 34 | etter 35 | andre 36 | så 37 | ved 38 | mellom 39 | blir 40 | vi 41 | der 42 | ho 43 | skal 44 | denne 45 | fleire 46 | kva 47 | over 48 | mange 49 | då 50 | meir 51 | noko 52 | du 53 | vil 54 | opp 55 | alle 56 | vere 57 | berre 58 | vert 59 | inn 60 | ulike 61 | ha 62 | fram 63 | desse 64 | vore 65 | gjennom 66 | både 67 | enn 68 | få 69 | sjølv 70 | når 71 | anna 72 | under 73 | kunne 74 | fekk 75 | slik 76 | nokre 77 | her 78 | mot 79 | sin 80 | før 81 | sjå 82 | blei 83 | må 84 | kom 85 | mykje 86 | første 87 | skulle 88 | hans 89 | hennar 90 | bli 91 | del 92 | sidan 93 | korleis 94 | sitt 95 | store 96 | si 97 | ofte 98 | dag 99 | sine 100 | går 101 | sett 102 | seier 103 | kjem 104 | tid 105 | saman 106 | ser 107 | heile 108 | medan 109 | ta 110 | no 111 | meg 112 | stor 113 | rundt 114 | gjekk 115 | mest 116 | nye 117 | litt 118 | heilt 119 | gjer 120 | får 121 | seinare 122 | blitt 123 | kanskje 124 | vera 125 | siste 126 | likevel 127 | kalla 128 | ligg 129 | viser 130 | står 131 | land 132 | tok 133 | folk 134 | brukt 135 | fordi 136 | ville 137 | større 138 | vidare 139 | kor 140 | mindre 141 | alt 142 | nok 143 | særleg 144 | veldig 145 | godt 146 | utan 147 | kvar 148 | finst 149 | bruk 150 | gå 151 | igjen 152 | gong 153 | ned 154 | lag 155 | deira 156 | gjere 157 | ingen 158 | nytta 159 | byrja 160 | blant 161 | fått 162 | god 163 | like 164 | finn 165 | sa 166 | oss 167 | største 168 | først 169 | tilbake 170 | framleis 171 | dokker 172 | nokon 173 | jo 174 | måte 175 | rett 176 | gjort 177 | lite 178 | gjorde 179 | måtte 180 | dersom 181 | innan 182 | langt 183 | dykk 184 | hatt 185 | slike 186 | gjerne 187 | kvart 188 | de 189 | heller 190 | halde 191 | ny 192 | alltid 193 | gav 194 | altså 195 | døme 196 | fleste 197 | difor 198 | betre 199 | svært 200 | mogleg -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for your interest in contributing to Keypunch! Most of the information you're looking for can likely be found in Keypunch's [contribution guide](https://welcome.gnome.org/app/Keypunch) on the Welcome to GNOME website. This document contains information specific to Keypunch that cannot be found in said contribution guide. 4 | 5 | ## Adding a Language 6 | 7 | This is the technical procedure for adding a text language to Keypunch. To request a language and help with the non-technical aspects, [create a language request](https://github.com/bragefuglseth/keypunch/issues/new?assignees=&labels=new+language&projects=&template=language_request.yaml&title=%5BLanguage+Request%5D%3A+) instead. To translate the UI, refer to the section above. 8 | 9 | 1. Add a word list with approximately 200 words to `data/word_lists/{code}.txt`. Replace `{code}` with the code of your language (e.g. `en` or `nb`). If the language has a corresponding list in [Monkeytype's language directory](https://github.com/monkeytypegame/monkeytype/tree/master/frontend/static/languages), you can download that, rename it and run `scripts/json_to_word_list.sh {file_path}` to generate a plain word list. Replace `{file_path}` with a path to the file. You'll need to have `jq` installed for the script to work. 10 | 3. Locate and open `src/text_generation.rs`. This is where all language work takes place. 11 | 4. Add the language to the `Language` enum at the alphabetical position of its English name. Use its English name as the variant name, and annotate it with the necessary metadata: 12 | 13 | ```rust 14 | #[strum(message = "{native_name}", to_string = "{code}")] 15 | LanguageName, 16 | ``` 17 | 18 | Replace `{native_name}` with the native name of the language, and `{code}` with the language code. 19 | 20 | 5. If the language has punctuation or spacing that deviates from the default (words separated by spaces, punctuation inserted before and after words, and Western Arabic numerals), add it to the match statements of the `simple` and `advanced` functions. Existing language entries can be used as examples. 21 | 22 | 6. Build the app and test the implementation. 23 | -------------------------------------------------------------------------------- /data/word_lists/he.txt: -------------------------------------------------------------------------------- 1 | של 2 | את 3 | על 4 | לא 5 | הוא 6 | עם 7 | כי 8 | היה 9 | זה 10 | גם 11 | כל 12 | בין 13 | אל 14 | יותר 15 | לאחר 16 | אבל 17 | הייתה 18 | עד 19 | בשנת 20 | ביותר 21 | רבים 22 | בית 23 | מספר 24 | העיר 25 | כדי 26 | אותו 27 | דבר 28 | כאשר 29 | ברית 30 | ידי 31 | לפני 32 | עולם 33 | במהלך 34 | שלו 35 | מאוד 36 | ניתן 37 | אחרים 38 | דרך 39 | חלק 40 | אותה 41 | אולם 42 | מאה 43 | נגד 44 | אנשי 45 | אותם 46 | שונים 47 | מלחמה 48 | בשל 49 | גדול 50 | היום 51 | אלא 52 | זמן 53 | יהודים 54 | נוספים 55 | ללא 56 | מקום 57 | ים 58 | חיים 59 | מדינה 60 | ארגון 61 | אחרי 62 | שנה 63 | בעלי 64 | ראש 65 | מלחמת 66 | אדם 67 | מול 68 | נוספת 69 | שימוש 70 | כגון 71 | באמצעות 72 | ממשלה 73 | לעתים 74 | תחת 75 | כמעט 76 | עיר 77 | בעקבות 78 | ארצות 79 | למשל 80 | הגנה 81 | אזור 82 | כלי 83 | טוב 84 | כוחות 85 | אביב 86 | מים 87 | ספר 88 | נראה 89 | תקופה 90 | עכשיו 91 | חייל 92 | אפשר 93 | צבא 94 | ביניהם 95 | אדמה 96 | זכה 97 | סוף 98 | מסגרת 99 | אנשים 100 | מערכת 101 | שמש 102 | עניינים 103 | קטן 104 | מיליון 105 | קהילה 106 | אחד 107 | כביש 108 | מהפכה 109 | שירים 110 | בשבילך 111 | רוח 112 | שלנו 113 | שחור 114 | מספרה 115 | אחדות 116 | אמריקאי 117 | מנהל 118 | דיסק 119 | קקטוס 120 | תיאוריה 121 | שודד 122 | קשה 123 | סטודנט 124 | תוכי 125 | לימודים 126 | כבוד 127 | בריאות 128 | נעליים 129 | דופן 130 | חבר 131 | הזדהה 132 | עת 133 | כלומר 134 | שיפור 135 | פסיכולוגיה 136 | היסטוריה 137 | נתקל 138 | כיצד 139 | יציאה 140 | אהבה 141 | כוסות 142 | מטבח 143 | ספל 144 | סלון 145 | שקע 146 | משקל 147 | קולנוע 148 | אמרתי 149 | זרם 150 | תמונה 151 | שלום 152 | מדהימה 153 | גביע 154 | מכונית 155 | מיקרופון 156 | חשמל 157 | שוטר 158 | סתם 159 | אירוע 160 | נעים 161 | מספיק 162 | דקדוק 163 | חנות 164 | רחוב 165 | גולן 166 | הקליד 167 | מקלדת 168 | כתב 169 | גזילה 170 | מוזיאון 171 | מחשבון 172 | תפקיד 173 | סוציולוגיה 174 | ברכה 175 | מצחיק 176 | קניון 177 | דירה 178 | פיראט 179 | מחנה 180 | צופה 181 | כללי 182 | כימיה 183 | פיזיקה 184 | חולים 185 | יד 186 | מחשב 187 | קונסולה 188 | שמיים 189 | ענן 190 | בקתה 191 | מרצפת 192 | דשא 193 | אש 194 | אגם 195 | חזיר 196 | עידן 197 | דן 198 | כדור 199 | -------------------------------------------------------------------------------- /data/word_lists/pl.txt: -------------------------------------------------------------------------------- 1 | jego 2 | że 3 | on 4 | dla 5 | na 6 | są 7 | zespół 8 | oni 9 | być 10 | jeden 11 | mieć 12 | tego 13 | gorący 14 | słowo 15 | ale 16 | co 17 | niektóre 18 | jest 19 | to 20 | ty 21 | lub 22 | miał 23 | kilka 24 | stopa 25 | do 26 | i 27 | ciągnąć 28 | puszka 29 | zewnątrz 30 | inne 31 | były 32 | który 33 | ich 34 | czas 35 | jeśli 36 | będzie 37 | powiedział 38 | próba 39 | każda 40 | zestaw 41 | trzy 42 | chcą 43 | powietrze 44 | dobrze 45 | również 46 | grać 47 | mały 48 | koniec 49 | wkładać 50 | strona 51 | czytaj 52 | ręka 53 | port 54 | zaklęcie 55 | dodać 56 | nawet 57 | tutaj 58 | musi 59 | wysoki 60 | takie 61 | śledzić 62 | akt 63 | dlaczego 64 | zapytaj 65 | mężczyźni 66 | zmiana 67 | poszedł 68 | światła 69 | rodzaj 70 | potrzeba 71 | dom 72 | obraz 73 | spróbuj 74 | nas 75 | ponownie 76 | zwierząt 77 | punkt 78 | matka 79 | świat 80 | blisko 81 | budować 82 | własny 83 | ojciec 84 | dowolny 85 | nowy 86 | praca 87 | część 88 | wziąć 89 | dostać 90 | miejsce 91 | wykonane 92 | żyć 93 | gdzie 94 | później 95 | powrotem 96 | mało 97 | okrągły 98 | mężczyzna 99 | rok 100 | spokojnie 101 | pokaż 102 | każdy 103 | dobry 104 | mnie 105 | dać 106 | nasze 107 | pod 108 | nazwa 109 | bardzo 110 | formularz 111 | zdanie 112 | wielki 113 | myśleć 114 | pomoc 115 | niski 116 | linia 117 | różnią 118 | kolej 119 | przyczyna 120 | oznaczać 121 | przed 122 | ruch 123 | prawo 124 | chłopiec 125 | stary 126 | zbyt 127 | sam 128 | ona 129 | wszystko 130 | tam 131 | kiedy 132 | góra 133 | zastosowanie 134 | twój 135 | sposób 136 | o 137 | następnie 138 | im 139 | pisać 140 | byłoby 141 | tak 142 | te 143 | ją 144 | długo 145 | rzecz 146 | zobaczyć 147 | mu 148 | dwa 149 | ma 150 | szukać 151 | więcej 152 | dzień 153 | iść 154 | przyjść 155 | liczba 156 | brzmieć 157 | najbardziej 158 | ludzie 159 | ponad 160 | wiem 161 | woda 162 | niż 163 | wezwanie 164 | pierwszy 165 | kto 166 | dół 167 | bok 168 | teraz 169 | odnaleźć 170 | w 171 | jak 172 | duży 173 | z 174 | ziemia 175 | przez 176 | tylko 177 | powiedzieć 178 | wiele 179 | zrobić 180 | nie 181 | my 182 | może 183 | było 184 | -------------------------------------------------------------------------------- /data/word_lists/fa.txt: -------------------------------------------------------------------------------- 1 | من 2 | تو 3 | او 4 | بود 5 | برای 6 | هست 7 | شهرک 8 | اقلیم 9 | تیغ 10 | پدر 11 | خار 12 | گریزان 13 | پشتکار 14 | نگار 15 | هند 16 | پیراهن 17 | رعایت 18 | سود 19 | شب 20 | نژاد 21 | کوچک 22 | کودک 23 | پرسش 24 | ناچار 25 | لیاقت 26 | ضیافت 27 | پوشاک 28 | امیر 29 | تولید 30 | محاسبه 31 | مسافرت 32 | مدرسه 33 | سطح 34 | مصاحبه 35 | صندلی 36 | شگفت 37 | خواهر 38 | آمار 39 | اسباب 40 | کاخ 41 | شیرینی 42 | کبریت 43 | عروسک 44 | کافی 45 | کارگردان 46 | صبحانه 47 | لبخند 48 | اطمینان 49 | بازی 50 | ریشه 51 | مطالعه 52 | هوا 53 | مخصوص 54 | گل 55 | پایین 56 | دانا 57 | همهمه 58 | دندان 59 | امروز 60 | مرهم 61 | داستان 62 | پزشک 63 | آیینه 64 | شادی 65 | نبرد 66 | ظلم 67 | بیکار 68 | ورزش 69 | سرعت 70 | نامه 71 | پرچم 72 | تمام 73 | بریدن 74 | آموزش 75 | گویش 76 | کاربرد 77 | ترانه 78 | کج 79 | تحقیق 80 | مرحله 81 | بهداشت 82 | بانو 83 | گرفتاری 84 | شکست 85 | آرایه 86 | نوشتن 87 | پیشانی 88 | سلام 89 | عاج 90 | فیل 91 | ماهی 92 | چاه 93 | باید 94 | ژاپن 95 | تراکم 96 | اکتشاف 97 | غذا 98 | سختی 99 | بادبادک 100 | دولت 101 | پیام 102 | علی 103 | شکوفه 104 | قلّه 105 | آبادی 106 | صلاحدید 107 | بهار 108 | اسب 109 | ققنوس 110 | منش 111 | عامیانه 112 | مار 113 | آزادی 114 | توانایی 115 | ظرف 116 | خطا 117 | آماده 118 | عرصه 119 | شروع 120 | چرا 121 | حیوانات 122 | گوناگون 123 | رویش 124 | پاییز 125 | ادبیات 126 | بازرگانی 127 | تلفن 128 | فردا 129 | دنباله 130 | گردش 131 | روشنایی 132 | برگ 133 | پشتوانه 134 | استثنا 135 | فراخ 136 | چشم 137 | سایه 138 | اندیشه 139 | چطور 140 | جانور 141 | مادر 142 | درباره 143 | سال 144 | ساحل 145 | استرداد 146 | چرخه 147 | سفید 148 | صحبت 149 | متفاوت 150 | قالب 151 | کرانه 152 | ترجمه 153 | راز 154 | رمز 155 | و 156 | آلو 157 | به 158 | در 159 | خنده 160 | نیاز 161 | دادگاه 162 | دقیقه 163 | انقباض 164 | غروب 165 | تنگی 166 | ارسلان 167 | برخوردار 168 | نرگس 169 | ضوابط 170 | باد 171 | ماشین 172 | بها 173 | طرح 174 | سیلی 175 | مرموز 176 | کثیف 177 | زبان 178 | وزیر 179 | شاه 180 | ملکه 181 | گنجایش 182 | آسمان 183 | نوشیدنی 184 | برشته 185 | حمله 186 | اساس 187 | عشق 188 | طبس 189 | پند 190 | پیوند 191 | کاسه 192 | انسان 193 | برق 194 | عنوان 195 | که 196 | خود 197 | -------------------------------------------------------------------------------- /data/word_lists/en.txt: -------------------------------------------------------------------------------- 1 | the 2 | be 3 | of 4 | and 5 | a 6 | to 7 | in 8 | he 9 | have 10 | it 11 | that 12 | for 13 | they 14 | I 15 | with 16 | as 17 | not 18 | on 19 | she 20 | at 21 | by 22 | this 23 | we 24 | you 25 | do 26 | but 27 | from 28 | or 29 | which 30 | one 31 | would 32 | all 33 | will 34 | there 35 | say 36 | who 37 | make 38 | when 39 | can 40 | more 41 | if 42 | no 43 | man 44 | out 45 | other 46 | so 47 | what 48 | time 49 | up 50 | go 51 | about 52 | than 53 | into 54 | could 55 | state 56 | only 57 | new 58 | year 59 | some 60 | take 61 | come 62 | these 63 | know 64 | see 65 | use 66 | get 67 | like 68 | then 69 | first 70 | any 71 | work 72 | now 73 | may 74 | such 75 | give 76 | over 77 | think 78 | most 79 | even 80 | find 81 | day 82 | also 83 | after 84 | way 85 | many 86 | must 87 | look 88 | before 89 | great 90 | back 91 | through 92 | long 93 | where 94 | much 95 | should 96 | well 97 | people 98 | down 99 | own 100 | just 101 | because 102 | good 103 | each 104 | those 105 | feel 106 | seem 107 | how 108 | high 109 | too 110 | place 111 | little 112 | world 113 | very 114 | still 115 | nation 116 | hand 117 | old 118 | life 119 | tell 120 | write 121 | become 122 | here 123 | show 124 | house 125 | both 126 | between 127 | need 128 | mean 129 | call 130 | develop 131 | under 132 | last 133 | right 134 | move 135 | thing 136 | general 137 | school 138 | never 139 | same 140 | another 141 | begin 142 | while 143 | number 144 | part 145 | turn 146 | real 147 | leave 148 | might 149 | want 150 | point 151 | form 152 | off 153 | child 154 | few 155 | small 156 | since 157 | against 158 | ask 159 | late 160 | home 161 | interest 162 | large 163 | person 164 | end 165 | open 166 | public 167 | follow 168 | during 169 | present 170 | without 171 | again 172 | hold 173 | govern 174 | around 175 | possible 176 | head 177 | consider 178 | word 179 | program 180 | problem 181 | however 182 | lead 183 | system 184 | set 185 | order 186 | eye 187 | plan 188 | run 189 | keep 190 | face 191 | fact 192 | group 193 | play 194 | stand 195 | increase 196 | early 197 | course 198 | change 199 | help 200 | line 201 | -------------------------------------------------------------------------------- /data/resources/gtk/help-overlay.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | 6 | 7 | shortcuts 8 | 10 9 | 10 | 11 | General 12 | 13 | 14 | Text Language 15 | win.text-language-dialog 16 | 17 | 18 | 19 | 20 | Cancel Session 21 | win.cancel-test 22 | 23 | 24 | 25 | 26 | Keyboard Shortcuts 27 | win.show-help-overlay 28 | 29 | 30 | 31 | 32 | Close Window 33 | window.close 34 | 35 | 36 | 37 | 38 | Quit 39 | app.quit 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /data/word_lists/cs.txt: -------------------------------------------------------------------------------- 1 | být 2 | a 3 | se 4 | v 5 | na 6 | ten 7 | on 8 | že 9 | s 10 | z 11 | který 12 | mít 13 | do 14 | já 15 | o 16 | k 17 | i 18 | jeho 19 | ale 20 | svůj 21 | jako 22 | za 23 | moci 24 | rok 25 | pro 26 | tak 27 | po 28 | tento 29 | co 30 | když 31 | všechen 32 | už 33 | jak 34 | aby 35 | od 36 | nebo 37 | říci 38 | jeden 39 | jen 40 | můj 41 | jenž 42 | člověk 43 | ty 44 | stát 45 | u 46 | muset 47 | velký 48 | chtít 49 | také 50 | až 51 | než 52 | ještě 53 | při 54 | jít 55 | pak 56 | před 57 | dva 58 | však 59 | ani 60 | vědět 61 | nový 62 | hodně 63 | podle 64 | další 65 | celý 66 | jiný 67 | první 68 | mezi 69 | dát 70 | tady 71 | den 72 | tam 73 | kde 74 | doba 75 | každý 76 | druhý 77 | místo 78 | dobrý 79 | takový 80 | strana 81 | protože 82 | nic 83 | začít 84 | něco 85 | život 86 | vidět 87 | říkat 88 | země 89 | dítě 90 | malý 91 | ne 92 | sám 93 | bez 94 | ruka 95 | či 96 | svět 97 | dostat 98 | práce 99 | nějaký 100 | proto 101 | pod 102 | tři 103 | kdy 104 | město 105 | přijít 106 | dobře 107 | žena 108 | muž 109 | teď 110 | kdo 111 | již 112 | nad 113 | asi 114 | starý 115 | například 116 | případ 117 | vysoký 118 | žádný 119 | společnost 120 | několik 121 | některý 122 | tedy 123 | cesta 124 | pokud 125 | dělat 126 | hlava 127 | čas 128 | poslední 129 | oko 130 | právě 131 | tvůj 132 | Praha 133 | věc 134 | voda 135 | český 136 | proti 137 | velmi 138 | jaký 139 | přes 140 | dům 141 | dnes 142 | pan 143 | část 144 | třeba 145 | kdyby 146 | brzy 147 | lze 148 | firma 149 | oba 150 | slovo 151 | tenhle 152 | vlastní 153 | nikdy 154 | koruna 155 | možný 156 | chvíle 157 | udělat 158 | pouze 159 | proč 160 | systém 161 | konec 162 | kolem 163 | málo 164 | myslit 165 | stejně 166 | moc 167 | problém 168 | milión 169 | nikdo 170 | stále 171 | totiž 172 | někdo 173 | tisíc 174 | vůbec 175 | zákon 176 | nechat 177 | najít 178 | což 179 | cena 180 | rád 181 | škola 182 | hlavní 183 | skupina 184 | mladý 185 | způsob 186 | často 187 | řada 188 | jediný 189 | mluvit 190 | vrátit 191 | různý 192 | hrát 193 | snad 194 | zůstat 195 | vzít 196 | dlouhý 197 | čekat 198 | patřit 199 | vláda 200 | úl 201 | účel 202 | ústrk 203 | baňka 204 | kůň 205 | déšť 206 | ať 207 | šťáva -------------------------------------------------------------------------------- /data/word_lists/de.txt: -------------------------------------------------------------------------------- 1 | der 2 | die 3 | und 4 | in 5 | den 6 | von 7 | zu 8 | das 9 | mit 10 | sich 11 | des 12 | auf 13 | für 14 | ist 15 | im 16 | dem 17 | nicht 18 | ein 19 | eine 20 | als 21 | auch 22 | es 23 | an 24 | werden 25 | aus 26 | er 27 | hat 28 | dass 29 | sie 30 | nach 31 | wird 32 | bei 33 | einer 34 | um 35 | am 36 | sind 37 | noch 38 | wie 39 | einem 40 | über 41 | einen 42 | so 43 | Sie 44 | zum 45 | war 46 | haben 47 | nur 48 | oder 49 | aber 50 | vor 51 | zur 52 | bis 53 | mehr 54 | durch 55 | man 56 | sein 57 | wurde 58 | sei 59 | Prozent 60 | hatte 61 | kann 62 | gegen 63 | vom 64 | können 65 | schon 66 | wenn 67 | habe 68 | seine 69 | Euro 70 | ihre 71 | dann 72 | unter 73 | wir 74 | soll 75 | ich 76 | eines 77 | Jahr 78 | zwei 79 | Jahren 80 | diese 81 | dieser 82 | wieder 83 | keine 84 | Uhr 85 | seiner 86 | worden 87 | will 88 | zwischen 89 | immer 90 | Millionen 91 | was 92 | sagte 93 | gibt 94 | alle 95 | diesem 96 | seit 97 | muss 98 | wurden 99 | beim 100 | doch 101 | jetzt 102 | waren 103 | drei 104 | Jahre 105 | neue 106 | neuen 107 | damit 108 | bereits 109 | da 110 | ihr 111 | seinen 112 | müssen 113 | ab 114 | ihrer 115 | ohne 116 | sondern 117 | selbst 118 | ersten 119 | nun 120 | etwa 121 | heute 122 | ihren 123 | weil 124 | ihm 125 | seien 126 | Menschen 127 | Deutschland 128 | anderen 129 | werde 130 | sagt 131 | rund 132 | ihn 133 | Ende 134 | jedoch 135 | Zeit 136 | sollen 137 | ins 138 | seinem 139 | uns 140 | Stadt 141 | geht 142 | sehr 143 | hier 144 | ganz 145 | erst 146 | wollen 147 | Berlin 148 | vor allem 149 | sowie 150 | hatten 151 | deutschen 152 | machen 153 | lassen 154 | Unternehmen 155 | andere 156 | ob 157 | dieses 158 | steht 159 | dabei 160 | wegen 161 | weiter 162 | denn 163 | beiden 164 | einmal 165 | etwas 166 | nichts 167 | allerdings 168 | vier 169 | gut 170 | viele 171 | wo 172 | viel 173 | dort 174 | alles 175 | wäre 176 | kommt 177 | denen 178 | vergangenen 179 | fast 180 | fünf 181 | könnte 182 | nicht nur 183 | hätten 184 | Frau 185 | dafür 186 | kommen 187 | diesen 188 | letzten 189 | zwar 190 | großen 191 | dazu 192 | Mann 193 | sollte 194 | würde 195 | also 196 | bisher 197 | Leben 198 | Welt 199 | konnte 200 | ihrem 201 | -------------------------------------------------------------------------------- /data/word_lists/de_CH.txt: -------------------------------------------------------------------------------- 1 | der 2 | die 3 | und 4 | in 5 | den 6 | von 7 | zu 8 | das 9 | mit 10 | sich 11 | des 12 | auf 13 | für 14 | ist 15 | im 16 | dem 17 | nicht 18 | ein 19 | eine 20 | als 21 | auch 22 | es 23 | an 24 | werden 25 | aus 26 | er 27 | hat 28 | dass 29 | sie 30 | nach 31 | wird 32 | bei 33 | einer 34 | um 35 | am 36 | sind 37 | noch 38 | wie 39 | einem 40 | über 41 | einen 42 | so 43 | Sie 44 | zum 45 | war 46 | haben 47 | nur 48 | oder 49 | aber 50 | vor 51 | zur 52 | bis 53 | mehr 54 | durch 55 | man 56 | sein 57 | wurde 58 | sei 59 | Prozent 60 | hatte 61 | kann 62 | gegen 63 | vom 64 | können 65 | schon 66 | wenn 67 | habe 68 | seine 69 | Euro 70 | ihre 71 | dann 72 | unter 73 | wir 74 | soll 75 | ich 76 | eines 77 | Jahr 78 | zwei 79 | Jahren 80 | diese 81 | dieser 82 | wieder 83 | keine 84 | Uhr 85 | seiner 86 | worden 87 | will 88 | zwischen 89 | immer 90 | Millionen 91 | was 92 | sagte 93 | gibt 94 | alle 95 | diesem 96 | seit 97 | muss 98 | wurden 99 | beim 100 | doch 101 | jetzt 102 | waren 103 | drei 104 | Jahre 105 | neue 106 | neuen 107 | damit 108 | bereits 109 | da 110 | ihr 111 | seinen 112 | müssen 113 | ab 114 | ihrer 115 | ohne 116 | sondern 117 | selbst 118 | ersten 119 | nun 120 | etwa 121 | heute 122 | ihren 123 | weil 124 | ihm 125 | seien 126 | Menschen 127 | Deutschland 128 | anderen 129 | werde 130 | sagt 131 | rund 132 | ihn 133 | Ende 134 | jedoch 135 | Zeit 136 | sollen 137 | ins 138 | seinem 139 | uns 140 | Stadt 141 | geht 142 | sehr 143 | hier 144 | ganz 145 | erst 146 | wollen 147 | Berlin 148 | vor allem 149 | sowie 150 | hatten 151 | deutschen 152 | machen 153 | lassen 154 | Unternehmen 155 | andere 156 | ob 157 | dieses 158 | steht 159 | dabei 160 | wegen 161 | weiter 162 | denn 163 | beiden 164 | einmal 165 | etwas 166 | nichts 167 | allerdings 168 | vier 169 | gut 170 | viele 171 | wo 172 | viel 173 | dort 174 | alles 175 | wäre 176 | kommt 177 | denen 178 | vergangenen 179 | fast 180 | fünf 181 | könnte 182 | nicht nur 183 | hätten 184 | Frau 185 | dafür 186 | kommen 187 | diesen 188 | letzten 189 | zwar 190 | grossen 191 | dazu 192 | Mann 193 | sollte 194 | würde 195 | also 196 | bisher 197 | Leben 198 | Welt 199 | konnte 200 | ihrem 201 | -------------------------------------------------------------------------------- /data/word_lists/ar.txt: -------------------------------------------------------------------------------- 1 | أتمنى 2 | أثق 3 | الاثنين 4 | أخرى 5 | أخشى 6 | الأرض 7 | الأسبوع 8 | أستطيع 9 | الأسئلة 10 | الأشياء 11 | أصدقاء 12 | إضافة 13 | أعتقد 14 | أعرف 15 | الأفضل 16 | أنا 17 | أنت 18 | الانتظار 19 | انتظر 20 | انتهى 21 | انظروا 22 | الأولاد 23 | أيضا 24 | بالطبع 25 | بالمناسبة 26 | ببعض 27 | بخصوص 28 | بخير 29 | برنامج 30 | بعضهم 31 | البقاء 32 | بمجرد 33 | بؤرة 34 | بينما 35 | تاريخ 36 | تبحث 37 | تبقى 38 | تتصل 39 | تصوير 40 | تفضل 41 | الثالثة 42 | ثانوي 43 | ثعلب 44 | جاء 45 | جزيرة 46 | جميلة 47 | جيد 48 | حادثة 49 | حجم 50 | الحديث 51 | حسنا 52 | حقيبة 53 | الحقيقة 54 | حقيقية 55 | الحياة 56 | خائف 57 | خائفة 58 | خشب 59 | خلال 60 | دائما 61 | درجة 62 | دكتور 63 | ذاكرتك 64 | الذراع 65 | ذكاء 66 | ذلك 67 | الذهاب 68 | ذئب 69 | رائع 70 | رغم 71 | رفاق 72 | رؤية 73 | رئيس 74 | زواج 75 | ساعة 76 | سعيد 77 | سنوات 78 | سيارة 79 | شاطئ 80 | شخص 81 | شخصية 82 | شمس 83 | شؤون 84 | شيء 85 | الشيء 86 | صحيح 87 | صديقي 88 | صغير 89 | صفحة 90 | صندوق 91 | ضابط 92 | الضرورة 93 | الضوء 94 | ضوضاء 95 | الطاقة 96 | الطائرة 97 | طبيب 98 | ظلام 99 | العالم 100 | عائلتي 101 | العربية 102 | عزيزتي 103 | العشاء 104 | عظيم 105 | على 106 | غاضب 107 | الغداء 108 | غرفة 109 | الفتاة 110 | فخور 111 | فريق 112 | الفضاء 113 | فضلك 114 | فقط 115 | فوائد 116 | في 117 | القادمة 118 | قائد 119 | قائمة 120 | القبض 121 | قبل 122 | قراءة 123 | قصة 124 | قضية 125 | قليلا 126 | قليلة 127 | كتاب 128 | كثير 129 | كيف 130 | لا 131 | اللحم 132 | لطيف 133 | لعبة 134 | اللقاء 135 | لقد 136 | للغاية 137 | لوحة 138 | لؤلؤ 139 | الليلة 140 | ماذا 141 | الماضي 142 | مجموعة 143 | محظوظ 144 | المدرسة 145 | مدهش 146 | مرحبا 147 | مريض 148 | مساء 149 | مساعدة 150 | مستشفى 151 | المستقبل 152 | مسرور 153 | مسؤولية 154 | مشاهدة 155 | مشكلة 156 | مضاعفة 157 | مطعم 158 | مع 159 | معلومات 160 | مغناطيس 161 | مفاتيح 162 | مفاجئ 163 | المفضل 164 | مقروء 165 | مكان 166 | ممارسة 167 | من 168 | منخفض 169 | المنزل 170 | مؤدب 171 | موسيقى 172 | موضوع 173 | مؤقتة 174 | مؤمن 175 | ميناء 176 | الناس 177 | نافذة 178 | نصائح 179 | الهاتف 180 | هادئ 181 | هدوء 182 | هذا 183 | هل 184 | هنالك 185 | هو 186 | هؤلاء 187 | هي 188 | هيئة 189 | واحدة 190 | واضحة 191 | وضع 192 | وظيفة 193 | الوقت 194 | إلى 195 | يبدو 196 | يحدث 197 | يعتقدون 198 | يفترض 199 | يمكنني -------------------------------------------------------------------------------- /data/word_lists/nl.txt: -------------------------------------------------------------------------------- 1 | als 2 | zijn 3 | dat 4 | hij 5 | was 6 | voor 7 | op 8 | met 9 | ze 10 | bij 11 | hebben 12 | deze 13 | door 14 | heet 15 | woord 16 | maar 17 | wat 18 | sommige 19 | is 20 | het 21 | u 22 | of 23 | had 24 | de 25 | van 26 | aan 27 | en 28 | in 29 | we 30 | kan 31 | uit 32 | andere 33 | waren 34 | die 35 | doen 36 | hun 37 | tijd 38 | indien 39 | zal 40 | hoe 41 | zei 42 | een 43 | elk 44 | vertellen 45 | doet 46 | drie 47 | willen 48 | lucht 49 | goed 50 | ook 51 | spelen 52 | klein 53 | zetten 54 | thuis 55 | lezen 56 | hand 57 | poort 58 | toevoegen 59 | zelfs 60 | land 61 | hier 62 | moet 63 | grote 64 | hoog 65 | dergelijke 66 | volgen 67 | waarom 68 | vragen 69 | mannen 70 | verandering 71 | ging 72 | licht 73 | soort 74 | uitgeschakeld 75 | nodig 76 | huis 77 | afbeelding 78 | proberen 79 | ons 80 | weer 81 | dier 82 | punt 83 | moeder 84 | wereld 85 | dichtbij 86 | bouwen 87 | zelf 88 | aarde 89 | vader 90 | nieuwe 91 | werk 92 | nemen 93 | krijgen 94 | plaats 95 | gemaakt 96 | wonen 97 | waar 98 | na 99 | terug 100 | weinig 101 | alleen 102 | ronde 103 | man 104 | jaar 105 | kwam 106 | elke 107 | mij 108 | geven 109 | onze 110 | onder 111 | naam 112 | zeer 113 | gewoon 114 | vorm 115 | zin 116 | denken 117 | zeggen 118 | helpen 119 | laag 120 | lijn 121 | verschillen 122 | beurt 123 | oorzaak 124 | veel 125 | betekenen 126 | verhuizing 127 | rechts 128 | jongen 129 | oude 130 | hetzelfde 131 | alle 132 | er 133 | wanneer 134 | omhoog 135 | gebruiken 136 | uw 137 | manier 138 | over 139 | dan 140 | hen 141 | schrijven 142 | zou 143 | zoals 144 | dus 145 | haar 146 | lang 147 | maken 148 | ding 149 | zien 150 | hem 151 | twee 152 | heeft 153 | kijken 154 | meer 155 | dag 156 | kon 157 | gaan 158 | komen 159 | deed 160 | aantal 161 | klinken 162 | geen 163 | meest 164 | mensen 165 | mijn 166 | weten 167 | water 168 | naar 169 | roep 170 | eerste 171 | beneden 172 | kant 173 | geweest 174 | nu 175 | vinden 176 | kunnen 177 | bos 178 | daar 179 | duur 180 | foto 181 | kleur 182 | week 183 | deel 184 | meter 185 | ruimte 186 | kamer 187 | buiten 188 | binnen 189 | staan 190 | verbinding 191 | kans 192 | verwijderen 193 | achter 194 | maand 195 | dijk 196 | druk 197 | gezondheid 198 | kat 199 | hond 200 | -------------------------------------------------------------------------------- /data/word_lists/uk.txt: -------------------------------------------------------------------------------- 1 | і 2 | на 3 | у 4 | в 5 | не 6 | що 7 | з 8 | бути 9 | до 10 | який 11 | та 12 | це 13 | я 14 | а 15 | за 16 | як 17 | про 18 | й 19 | вони 20 | ми 21 | для 22 | цей 23 | свій 24 | від 25 | він 26 | його 27 | такий 28 | але 29 | рік 30 | вона 31 | із 32 | один 33 | могти 34 | так 35 | мати 36 | людина 37 | чи 38 | ви 39 | той 40 | ще 41 | час 42 | її 43 | коли 44 | воно 45 | український 46 | ти 47 | вже 48 | щоб 49 | ж 50 | інший 51 | то 52 | під 53 | все 54 | по 55 | себе 56 | також 57 | всі 58 | якщо 59 | тому 60 | те 61 | або 62 | лише 63 | сказати 64 | наш 65 | питання 66 | право 67 | день 68 | закон 69 | можна 70 | після 71 | хто 72 | тільки 73 | країна 74 | де 75 | знати 76 | мій 77 | дуже 78 | державний 79 | навіть 80 | через 81 | щодо 82 | слово 83 | життя 84 | голова 85 | тут 86 | б 87 | саме 88 | місце 89 | великий 90 | бо 91 | перший 92 | справа 93 | новий 94 | зі 95 | при 96 | рада 97 | раз 98 | держава 99 | там 100 | багато 101 | дитина 102 | сьогодні 103 | кожний 104 | влада 105 | місто 106 | світ 107 | більше 108 | депутат 109 | ні 110 | тоді 111 | рішення 112 | особа 113 | без 114 | система 115 | треба 116 | зараз 117 | національний 118 | казати 119 | народний 120 | два 121 | президент 122 | проблема 123 | просити 124 | усі 125 | політичний 126 | зробити 127 | мова 128 | їхній 129 | хотіти 130 | частина 131 | працювати 132 | між 133 | рука 134 | діяльність 135 | розвиток 136 | процес 137 | просто 138 | самий 139 | область 140 | якийсь 141 | робити 142 | робота 143 | шановний 144 | бачити 145 | би 146 | зміна 147 | сила 148 | суд 149 | говорити 150 | вважати 151 | умова 152 | потім 153 | історія 154 | тепер 155 | колега 156 | кілька 157 | група 158 | соціальний 159 | перед 160 | можливість 161 | ситуація 162 | увага 163 | жінка 164 | результат 165 | зокрема 166 | організація 167 | давати 168 | уже 169 | партія 170 | міжнародний 171 | комітет 172 | чоловік 173 | допомога 174 | немає 175 | орган 176 | ніж 177 | дякувати 178 | дія 179 | отримати 180 | почати 181 | повинний 182 | думка 183 | верховний 184 | земля 185 | останній 186 | око 187 | щось 188 | інформація 189 | тисяча 190 | війна 191 | серед 192 | нічого 193 | власний 194 | законопроєкт 195 | певний 196 | уряд 197 | хоча 198 | випадок 199 | бік 200 | -------------------------------------------------------------------------------- /data/word_lists/es.txt: -------------------------------------------------------------------------------- 1 | como 2 | su 3 | que 4 | él 5 | era 6 | para 7 | en 8 | son 9 | con 10 | ellos 11 | ser 12 | uno 13 | tener 14 | este 15 | desde 16 | por 17 | caliente 18 | palabra 19 | pero 20 | qué 21 | algunos 22 | es 23 | lo 24 | usted 25 | o 26 | tenido 27 | la 28 | de 29 | a 30 | y 31 | un 32 | nos 33 | lata 34 | otros 35 | eran 36 | hacer 37 | tiempo 38 | si 39 | cómo 40 | dicho 41 | cada 42 | decir 43 | hace 44 | conjunto 45 | tres 46 | querer 47 | aire 48 | así 49 | también 50 | jugar 51 | pequeño 52 | fin 53 | poner 54 | leer 55 | mano 56 | puerto 57 | grande 58 | deletrear 59 | añadir 60 | incluso 61 | tierra 62 | aquí 63 | debe 64 | alto 65 | tal 66 | siga 67 | acto 68 | hierro 69 | preguntar 70 | hombres 71 | cambio 72 | porque 73 | luz 74 | tipo 75 | fuego 76 | imagen 77 | tratar 78 | nosotros 79 | animal 80 | punto 81 | madre 82 | mundo 83 | cerca 84 | construir 85 | auto 86 | padre 87 | cualquier 88 | nuevo 89 | trabajo 90 | parte 91 | tomar 92 | conseguir 93 | lugar 94 | hecho 95 | vivir 96 | donde 97 | después 98 | atrás 99 | poco 100 | ronda 101 | hombre 102 | años 103 | vino 104 | buena 105 | me 106 | dar 107 | nuestro 108 | bajo 109 | nombre 110 | muy 111 | forma 112 | frase 113 | gran 114 | pensar 115 | ayudar 116 | línea 117 | caja 118 | causa 119 | mucho 120 | ciudad 121 | antes 122 | movimiento 123 | derecho 124 | niño 125 | viejo 126 | demasiado 127 | misma 128 | ella 129 | todo 130 | hay 131 | cuando 132 | hasta 133 | uso 134 | camino 135 | acerca 136 | muchos 137 | entonces 138 | escribir 139 | haría 140 | éstos 141 | largo 142 | cosa 143 | ver 144 | dos 145 | tiene 146 | buscar 147 | más 148 | día 149 | podía 150 | ir 151 | venir 152 | hizo 153 | número 154 | sonar 155 | no 156 | personas 157 | mi 158 | sobre 159 | saber 160 | agua 161 | llamada 162 | primero 163 | puede 164 | abajo 165 | lado 166 | estado 167 | ahora 168 | encontrar 169 | bien 170 | siempre 171 | mayor 172 | menor 173 | mientras 174 | quien 175 | ayer 176 | pasado 177 | medio 178 | nunca 179 | poder 180 | veces 181 | fiesta 182 | grupo 183 | cuenta 184 | noche 185 | gente 186 | cuerpo 187 | semana 188 | segundo 189 | varios 190 | libro 191 | persona 192 | fuera 193 | casa 194 | solo 195 | mujer 196 | sistema 197 | vida 198 | hola 199 | adiós 200 | hablar -------------------------------------------------------------------------------- /data/word_lists/bg.txt: -------------------------------------------------------------------------------- 1 | а 2 | аз 3 | ако 4 | ами 5 | баща 6 | без 7 | беше 8 | би 9 | бил 10 | бих 11 | благодаря 12 | бъде 13 | бях 14 | в 15 | вас 16 | веднага 17 | вече 18 | вечер 19 | ви 20 | видим 21 | видя 22 | вие 23 | виж 24 | винаги 25 | време 26 | все 27 | всеки 28 | всички 29 | всичко 30 | всъщност 31 | във 32 | ги 33 | го 34 | говоря 35 | години 36 | да 37 | дай 38 | дали 39 | две 40 | ден 41 | днес 42 | до 43 | добър 44 | дойде 45 | докато 46 | дори 47 | доста 48 | достатъчно 49 | друг 50 | друго 51 | е 52 | един 53 | една 54 | едно 55 | ей 56 | ела 57 | ето 58 | жена 59 | живот 60 | за 61 | заедно 62 | заради 63 | затова 64 | защо 65 | защото 66 | здравей 67 | знае 68 | знаете 69 | знаеш 70 | знам 71 | значи 72 | и 73 | изглежда 74 | или 75 | им 76 | има 77 | имам 78 | имаме 79 | имате 80 | имаш 81 | иска 82 | каза 83 | казах 84 | казвам 85 | как 86 | каква 87 | какво 88 | каквото 89 | както 90 | какъв 91 | като 92 | когато 93 | което 94 | които 95 | кой 96 | който 97 | кола 98 | колко 99 | която 100 | къде 101 | към 102 | ли 103 | майка 104 | малко 105 | ме 106 | между 107 | мен 108 | ми 109 | мисля 110 | много 111 | мога 112 | може 113 | моля 114 | момиче 115 | моя 116 | му 117 | място 118 | на 119 | наистина 120 | нали 121 | направи 122 | направя 123 | наред 124 | нас 125 | начин 126 | не 127 | него 128 | нека 129 | неща 130 | нещо 131 | нея 132 | ни 133 | ние 134 | никога 135 | никой 136 | нищо 137 | но 138 | нощ 139 | нужда 140 | някой 141 | няколко 142 | няма 143 | нямам 144 | обичам 145 | от 146 | отново 147 | още 148 | пак 149 | пари 150 | по 151 | повече 152 | под 153 | после 154 | правя 155 | пред 156 | предвид 157 | преди 158 | през 159 | при 160 | приятел 161 | проблем 162 | просто 163 | път 164 | работа 165 | разбирам 166 | с 167 | са 168 | сам 169 | само 170 | се 171 | себе 172 | сега 173 | си 174 | сигурен 175 | скъпа 176 | след 177 | случи 178 | сме 179 | става 180 | сте 181 | стига 182 | съжалявам 183 | съм 184 | със 185 | също 186 | тази 187 | така 188 | там 189 | татко 190 | те 191 | теб 192 | тези 193 | ти 194 | това 195 | тогава 196 | този 197 | той 198 | толкова 199 | точно 200 | три 201 | трябва 202 | тук 203 | тя 204 | тях 205 | утре 206 | хайде 207 | харесвам 208 | хора 209 | хората 210 | чакай 211 | че 212 | човек 213 | ще 214 | я -------------------------------------------------------------------------------- /data/word_lists/ne.txt: -------------------------------------------------------------------------------- 1 | अघि 2 | अथवा 3 | अनि 4 | अनिरुद्र 5 | अनुभव 6 | अन्तमा 7 | अभियान 8 | अमूल्य 9 | अरू 10 | अवधि 11 | अवस्था 12 | अविनव 13 | असलपन 14 | आम्दानी 15 | आयोजना 16 | आर्य 17 | आविष्कार 18 | आशिश 19 | उत्साह 20 | उपलब्ध 21 | उपायले 22 | एक 23 | एक्लै 24 | ओछ्यान 25 | कथा 26 | कपाल 27 | कपास 28 | कम्पनी 29 | काँध 30 | काट्ने 31 | काठमाडौँ 32 | काम 33 | किन 34 | किनेको 35 | कोट 36 | खल्ती 37 | खानेकुरा 38 | खासगरि 39 | खेतीयोग्य 40 | ख्याल 41 | गए 42 | गएर 43 | गति 44 | गरे 45 | गर्नु 46 | गाईवस्तुका 47 | घटना 48 | घटाउनु 49 | चिट्ठी 50 | चिसोपन 51 | छ 52 | छाडेका 53 | छिट्टै 54 | छेउछाउ 55 | जंगल 56 | जनता 57 | जन्म 58 | जरा 59 | जिम्मेवारी 60 | जुत्ता 61 | जो 62 | जोगाउन 63 | टोपी 64 | ठाउँ 65 | त 66 | तर 67 | तालिम 68 | ती 69 | त्यसपछि 70 | त्यसले 71 | त्यसैले 72 | थान 73 | थाल्यो 74 | थुप्रै 75 | दश 76 | दाउरा 77 | दाबी 78 | दिन 79 | दुईवटा 80 | न 81 | नजिकै 82 | नमस्कार 83 | नरहेपछि 84 | नर्सरी 85 | नसक्ने 86 | निकेश 87 | निर्धारित 88 | नेतृत्व 89 | नेपाल 90 | नै 91 | पछि 92 | पत्नी 93 | पनि 94 | पन्ध्र 95 | परिवर्तन 96 | परेवा 97 | पहिले 98 | पाउनु 99 | पिच 100 | पुरस्कार 101 | पुस्तक 102 | पृथ्वी 103 | पौडी 104 | प्रत्येक 105 | प्रदान 106 | प्रयास 107 | प्रयोग 108 | प्रस्ताव 109 | फाइदा 110 | फैलियो 111 | बढी 112 | बढीको 113 | बन्न 114 | बर्खा 115 | बाहिर 116 | बिना 117 | विप्लप 118 | बिरूवा 119 | बिहान 120 | बीजहरू 121 | बेच्न 122 | भए 123 | भएको 124 | भनि 125 | भयो 126 | भाग 127 | भाग्य 128 | भात 129 | भाइ 130 | भिजाउने 131 | म 132 | मन 133 | मरूभूमि 134 | मरे 135 | मन्दिर 136 | मह 137 | महादेशमा 138 | महिना 139 | महिला 140 | माटो 141 | माटोको 142 | मिल्ने 143 | याम 144 | यी 145 | यो 146 | र 147 | रकम 148 | रखेदेख 149 | रमाइलो 150 | राष्ट्रिय 151 | रिस 152 | रूख 153 | रोपेका 154 | रोपेको 155 | लक्ष्य 156 | लगाउने 157 | लाख 158 | लागि 159 | ल्याइए 160 | ल्याएर 161 | वन 162 | वरिपरि 163 | विद्यालय 164 | विपरीत 165 | विभाग 166 | विशेष 167 | वेहोरेर 168 | व्यक्ति 169 | व्यवस्था 170 | व्यवस्थापन 171 | शिविर 172 | शुभम 173 | सक्छन् 174 | सक्दैन 175 | सज्जा 176 | सफलता 177 | सबै 178 | समय 179 | समाज 180 | समूह 181 | सम्झौता 182 | सम्माना 183 | सय 184 | साँझ 185 | साथ 186 | साधारण 187 | सानै 188 | सामूहिक 189 | सार्वजनिक 190 | सुख्खा 191 | सुधार्न 192 | सुरूमा 193 | सौन्दर्य 194 | स्याहार 195 | हाम्रो 196 | हावाहुरी 197 | हुन 198 | हुर्किने 199 | हेरचाह 200 | हैन 201 | -------------------------------------------------------------------------------- /data/word_lists/tr.txt: -------------------------------------------------------------------------------- 1 | ağaç 2 | ağız 3 | aile 4 | akşam 5 | ama 6 | ancak 7 | anne 8 | araba 9 | arada 10 | arasında 11 | arkadaş 12 | artık 13 | asker 14 | aslında 15 | aşk 16 | ateş 17 | ay 18 | ayak 19 | aynı 20 | baba 21 | bahçe 22 | balık 23 | bana 24 | başka 25 | bazı 26 | beden 27 | belki 28 | ben 29 | bence 30 | bile 31 | bilim 32 | bir 33 | biraz 34 | biri 35 | biz 36 | bu 37 | bulut 38 | buna 39 | bunu 40 | burası 41 | burun 42 | cadde 43 | çay 44 | çıkmak 45 | çiçek 46 | çocuk 47 | çok 48 | çünkü 49 | da 50 | dağ 51 | daha 52 | dakika 53 | de 54 | dedi 55 | değil 56 | dek 57 | deniz 58 | dışında 59 | dil 60 | din 61 | diş 62 | diye 63 | doğru 64 | doktor 65 | dost 66 | durum 67 | durumda 68 | eczane 69 | el 70 | en 71 | ev 72 | fazla 73 | felsefe 74 | film 75 | gece 76 | geçen 77 | gerekiyor 78 | gibi 79 | göl 80 | gölge 81 | göz 82 | gün 83 | güneş 84 | hafta 85 | hala 86 | hastane 87 | hava 88 | hayat 89 | hayvan 90 | hemen 91 | hemşire 92 | hep 93 | her 94 | herkes 95 | ışık 96 | için 97 | içinde 98 | ile 99 | ilk 100 | ilkbahar 101 | ister 102 | iş 103 | iyi 104 | kadar 105 | kafa 106 | kahve 107 | kalp 108 | kar 109 | karşı 110 | kedi 111 | kendi 112 | kış 113 | ki 114 | kim 115 | kimin 116 | kimse 117 | kitap 118 | köpek 119 | köy 120 | kulak 121 | kuş 122 | kütüphane 123 | mahalle 124 | mevsim 125 | mutluluk 126 | müze 127 | müzik 128 | ne 129 | neden 130 | neyse 131 | okul 132 | olabilir 133 | olan 134 | oldu 135 | olmaz 136 | onu 137 | orada 138 | orman 139 | öğrenci 140 | öğretmen 141 | önce 142 | öyle 143 | park 144 | polis 145 | ruh 146 | rüya 147 | rüzgar 148 | saat 149 | sabah 150 | saç 151 | sadece 152 | sana 153 | sanat 154 | saniye 155 | sen 156 | ses 157 | sevgi 158 | sinema 159 | siz 160 | sokak 161 | son 162 | sonbahar 163 | sonra 164 | sonunda 165 | sorun 166 | su 167 | şehir 168 | şekilde 169 | şey 170 | şimdi 171 | şimdiye 172 | şu 173 | şunu 174 | takvim 175 | tam 176 | tamam 177 | tamamen 178 | tek 179 | tiyatro 180 | toprak 181 | uçak 182 | uyku 183 | üzerinde 184 | üzerine 185 | üzüntü 186 | var 187 | vardı 188 | ve 189 | yağmur 190 | yanında 191 | yaz 192 | yazar 193 | yemek 194 | yeni 195 | yeterli 196 | yıl 197 | yok 198 | yol 199 | yüz 200 | yüzünden 201 | zaman 202 | pijamalı 203 | hasta 204 | yağız 205 | şoföre 206 | çabucak 207 | güvendi 208 | -------------------------------------------------------------------------------- /data/word_lists/sw.txt: -------------------------------------------------------------------------------- 1 | kama 2 | mimi 3 | yake 4 | kwamba 5 | yeye 6 | mara 7 | kwa 8 | juu ya 9 | wako 10 | kwa 11 | wao 12 | kuwa 13 | katika 14 | moja 15 | na 16 | hii 17 | kutoka 18 | na 19 | moto 20 | neno 21 | lakini 22 | nini 23 | baadhi 24 | ni 25 | yake 26 | ninyi 27 | au 28 | alikuwa 29 | akaonekana 30 | ya 31 | kwa 32 | na 33 | a 34 | katika 35 | sisi 36 | unaweza 37 | nje 38 | nyingine 39 | walikuwa 40 | ambayo 41 | kufanya 42 | yao 43 | wakati 44 | kama 45 | mapenzi 46 | jinsi 47 | alisema 48 | an 49 | kila 50 | kuwaambia 51 | gani 52 | kuweka 53 | tatu 54 | wanataka 55 | hewa 56 | vizuri 57 | pia 58 | kucheza 59 | ndogo 60 | mwisho 61 | kuweka 62 | nyumbani 63 | kusoma 64 | mkono 65 | bandari 66 | kubwa 67 | kuongeza 68 | hata 69 | ardhi 70 | hapa 71 | lazima 72 | kubwa 73 | high 74 | kama 75 | kufuata 76 | tendo 77 | kwa nini 78 | kuuliza 79 | wanaume 80 | mabadiliko ya 81 | akaenda 82 | mwanga 83 | aina 84 | mbali 85 | haja 86 | nyumba 87 | picha 88 | kujaribu 89 | sisi 90 | tena 91 | mnyama 92 | uhakika 93 | mama 94 | dunia 95 | karibu 96 | kujenga 97 | binafsi 98 | dunia 99 | baba 100 | yoyote 101 | mpya 102 | kazi 103 | sehemu 104 | kuchukua 105 | kupata 106 | mahali 107 | alifanya 108 | kuishi 109 | ambapo 110 | baada ya 111 | nyuma 112 | kidogo 113 | tu 114 | pande zote 115 | mtu 116 | mwaka 117 | alikuja 118 | onyesha 119 | kila 120 | nzuri 121 | mimi 122 | kutoa 123 | wetu 124 | chini ya 125 | jina 126 | sana 127 | kupitia 128 | tu 129 | aina 130 | hukumu 131 | kubwa 132 | kufikiri 133 | kusema 134 | msaada 135 | chini 136 | line 137 | tofauti 138 | upande 139 | sababu 140 | kiasi 141 | maana 142 | kabla ya 143 | hoja 144 | haki 145 | mvulana 146 | umri wa 147 | pia 148 | sawa 149 | yeye 150 | kila 151 | huko 152 | wakati 153 | up 154 | kutumia 155 | yako 156 | njia 157 | kuhusu 158 | wengi 159 | kisha 160 | yao 161 | kuandika 162 | ingekuwa 163 | kama 164 | hivyo 165 | haya 166 | yake 167 | muda mrefu 168 | kufanya 169 | kitu 170 | kuona 171 | naye 172 | mbili 173 | ina 174 | kuangalia 175 | zaidi 176 | siku 177 | inaweza 178 | kwenda 179 | kuja 180 | alifanya 181 | simu 182 | sauti 183 | hakuna 184 | zaidi 185 | watu 186 | yangu 187 | juu ya 188 | kujua 189 | maji 190 | kuliko 191 | simu 192 | kwanza 193 | ambao 194 | inaweza 195 | chini 196 | upande 197 | imekuwa 198 | sasa 199 | kupata -------------------------------------------------------------------------------- /data/word_lists/rw.txt: -------------------------------------------------------------------------------- 1 | nka 2 | ibye 3 | ibyo 4 | we 5 | yari 6 | kuri 7 | ku 8 | ni 9 | hamwe na 10 | bo 11 | be 12 | kuri 13 | imwe 14 | kugira 15 | iyi 16 | kuva 17 | na 18 | ashyushye 19 | ijambo 20 | ariko 21 | iki 22 | bimwe 23 | nb 24 | ni 25 | wowe 26 | cyangwa 27 | yagize 28 | i 29 | bya 30 | kuri 31 | na 32 | a 33 | in 34 | twe 35 | irashobora 36 | hanze 37 | ikindi 38 | bari 39 | bikaba 40 | kora 41 | yabo 42 | igihe 43 | niba 44 | ubushake 45 | gute 46 | ati 47 | an 48 | buri umwe 49 | bwira 50 | ikora 51 | gushiraho 52 | bitatu 53 | bakeneye 54 | umwuka 55 | neza 56 | na 57 | gukina 58 | nto 59 | iherezo 60 | shyira 61 | urugo 62 | soma 63 | ukuboko 64 | icyambu 65 | binini 66 | amarozi 67 | ongeraho 68 | ndetse 69 | butaka 70 | hano 71 | igomba 72 | binini 73 | muremure 74 | nkibyo 75 | kurikira 76 | gukora 77 | kubera iki 78 | baza 79 | abagabo 80 | impinduka 81 | yagiye 82 | urumuri 83 | ubwoko 84 | kuzimya 85 | bikenewe 86 | inzu 87 | ishusho 88 | gerageza 89 | twe 90 | na none 91 | inyamaswa 92 | ingingo 93 | nyina 94 | isi 95 | hafi 96 | kubaka 97 | wenyine 98 | isi 99 | se 100 | icyaricyo cyose 101 | gishya 102 | akazi 103 | igice 104 | fata 105 | kubona 106 | ikibanza 107 | yakozwe 108 | kubaho 109 | he 110 | nyuma 111 | inyuma 112 | bike 113 | gusa 114 | kuzenguruka 115 | umuntu 116 | umwaka 117 | yaje 118 | kwerekana 119 | buri 120 | byiza 121 | njye 122 | tanga 123 | yacu 124 | munsi 125 | izina 126 | cyane 127 | binyuze 128 | gusa 129 | ifishi 130 | interuro 131 | bikomeye 132 | tekereza 133 | vuga 134 | ubufasha 135 | hasi 136 | umurongo 137 | bitandukanye 138 | hindukira 139 | impamvu 140 | byinshi 141 | bivuze 142 | mbere 143 | kwimuka 144 | iburyo 145 | umuhungu 146 | kera 147 | na 148 | kimwe 149 | we 150 | byose 151 | ngaho 152 | ryari 153 | hejuru 154 | koresha 155 | yawe 156 | inzira 157 | hafi 158 | benshi 159 | hanyuma 160 | bo 161 | andika 162 | ese 163 | nka 164 | bityo 165 | ibi 166 | we 167 | kirekire 168 | gukora 169 | ikintu 170 | reba 171 | we 172 | bibiri 173 | ifite 174 | reba 175 | byinshi 176 | umunsi 177 | ashoboye 178 | genda 179 | ngwino 180 | yakoze 181 | nimero 182 | ijwi 183 | oya 184 | byinshi 185 | abantu 186 | my 187 | hejuru 188 | menya 189 | amazi 190 | kuruta 191 | hamagara 192 | mbere 193 | ninde 194 | gicurasi 195 | hasi 196 | ruhande 197 | yabaye 198 | ubungubu 199 | shakisha -------------------------------------------------------------------------------- /data/word_lists/pt.txt: -------------------------------------------------------------------------------- 1 | o 2 | de 3 | e 4 | em 5 | um 6 | que 7 | a 8 | ser 9 | para 10 | não 11 | com 12 | por 13 | ter 14 | se 15 | seu 16 | eu 17 | ele 18 | fazer 19 | mais 20 | este 21 | ou 22 | poder 23 | estar 24 | esse 25 | mas 26 | ir 27 | todo 28 | outro 29 | meu 30 | muito 31 | dizer 32 | ano 33 | isso 34 | ela 35 | também 36 | grande 37 | bom 38 | nós 39 | pessoa 40 | saber 41 | como 42 | sobre 43 | algum 44 | ver 45 | eles 46 | nosso 47 | ficar 48 | dia 49 | quando 50 | querer 51 | dever 52 | vida 53 | sem 54 | mesmo 55 | ainda 56 | coisa 57 | porque 58 | bem 59 | tempo 60 | entre 61 | sempre 62 | passar 63 | dois 64 | novo 65 | aquele 66 | quem 67 | falar 68 | tudo 69 | onde 70 | vir 71 | deixar 72 | apenas 73 | primeiro 74 | vigilante 75 | fervente 76 | circuito 77 | imprudente 78 | uma 79 | aqui 80 | mundo 81 | qualquer 82 | organizar 83 | trabalho 84 | detalhe 85 | país 86 | conseguir 87 | tu 88 | depois 89 | usar 90 | achar 91 | parte 92 | homem 93 | qual 94 | chegar 95 | haver 96 | começar 97 | conhecer 98 | agora 99 | assim 100 | gostar 101 | problema 102 | cada 103 | caso 104 | mulher 105 | elas 106 | tão 107 | encontrar 108 | hoje 109 | nada 110 | levar 111 | livro 112 | pequeno 113 | empresa 114 | precisar 115 | acontecer 116 | momento 117 | viver 118 | nunca 119 | pouco 120 | pois 121 | do 122 | nem 123 | tipo 124 | história 125 | parecer 126 | sentir 127 | contra 128 | vez 129 | casa 130 | antes 131 | filho 132 | verdade 133 | ler 134 | social 135 | importante 136 | criar 137 | escrever 138 | continuar 139 | cidade 140 | receber 141 | acabar 142 | então 143 | informação 144 | nome 145 | colocar 146 | processo 147 | diferente 148 | gente 149 | sair 150 | tentar 151 | isto 152 | direito 153 | pai 154 | lugar 155 | trabalhar 156 | durante 157 | criança 158 | valor 159 | governo 160 | mostrar 161 | ponto 162 | palavra 163 | hora 164 | certo 165 | perder 166 | possível 167 | apresentar 168 | voltar 169 | situação 170 | mês 171 | jogo 172 | existir 173 | sistema 174 | ajudar 175 | serviço 176 | público 177 | tanto 178 | blog 179 | entrar 180 | nenhum 181 | três 182 | tomar 183 | questão 184 | amor 185 | tal 186 | grupo 187 | através 188 | amigo 189 | comentário 190 | seguir 191 | contar 192 | acreditar 193 | alto 194 | filme 195 | esperar 196 | tornar 197 | semana 198 | texto 199 | abrir 200 | quase 201 | realizar 202 | é 203 | são -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | desktop_conf = configuration_data() 2 | desktop_conf.set('icon', app_id) 3 | 4 | desktop_file = i18n.merge_file( 5 | input: configure_file( 6 | input: 'dev.bragefuglseth.Keypunch.desktop.in.in', 7 | output: '@BASENAME@', 8 | configuration: desktop_conf 9 | ), 10 | output: '@0@.desktop'.format(app_id), 11 | type: 'desktop', 12 | po_dir: '../po', 13 | install: true, 14 | install_dir: get_option('datadir') / 'applications' 15 | ) 16 | 17 | desktop_utils = find_program('desktop-file-validate', required: false) 18 | if desktop_utils.found() 19 | test('Validate desktop file', desktop_utils, args: [desktop_file]) 20 | endif 21 | 22 | run_command('cp', 'dev.bragefuglseth.Keypunch.metainfo.xml.in.in', 'dev.bragefuglseth.Keypunch.metainfo.xml.in', check: true) 23 | 24 | # Sed is used as a poor man's `configure_file` here because we need access to it in the src dir 25 | sed = find_program('sed', required: true) 26 | run_command(sed, '-i', 's/@app-id@/' + app_id + '/g', 'dev.bragefuglseth.Keypunch.metainfo.xml.in', check: true) 27 | 28 | appstream_file = i18n.merge_file( 29 | input: 'dev.bragefuglseth.Keypunch.metainfo.xml.in', 30 | output: 'dev.bragefuglseth.Keypunch.metainfo.xml', 31 | po_dir: '../po', 32 | type: 'xml', 33 | install: true, 34 | install_dir: get_option('datadir') / 'metainfo' 35 | ) 36 | 37 | appstreamcli = find_program('appstreamcli', required: false, disabler: true) 38 | test('Validate appstream file', appstreamcli, 39 | args: ['validate', '--no-net', '--explain', appstream_file]) 40 | 41 | # Setup a translated metainfo file in the resources dir as well 42 | # for use by the about dialog 43 | msgfmt = find_program('msgfmt', required: true) 44 | run_command(msgfmt, 45 | '--xml', 46 | '-d' + meson.project_source_root() / 'po', 47 | '--template=dev.bragefuglseth.Keypunch.metainfo.xml.in', 48 | '--output-file=' + 'resources' / 'dev.bragefuglseth.Keypunch.metainfo.xml', 49 | check: true, 50 | ) 51 | 52 | install_data('dev.bragefuglseth.Keypunch.gschema.xml', 53 | install_dir: get_option('datadir') / 'glib-2.0' / 'schemas' 54 | ) 55 | 56 | compile_schemas = find_program('glib-compile-schemas', required: false, disabler: true) 57 | test('Validate schema file', 58 | compile_schemas, 59 | args: ['--strict', '--dry-run', meson.current_source_dir()]) 60 | 61 | subdir('artwork' / 'icon') 62 | -------------------------------------------------------------------------------- /data/word_lists/ar_advanced.txt: -------------------------------------------------------------------------------- 1 | أتمنى 2 | أثق 3 | الاثنين 4 | أخرى 5 | أخشى 6 | الأرض 7 | الأسبوع 8 | أستطيع 9 | الأسئلة 10 | الأشياء 11 | أصدقاء 12 | إضافة 13 | أعتقد 14 | أعرف 15 | الأفضل 16 | أنا 17 | أنت 18 | الانتظار 19 | انتظر 20 | انتهى 21 | انظروا 22 | الأولاد 23 | أيضا 24 | بالطبع 25 | بالمناسبة 26 | ببعض 27 | بخصوص 28 | بخير 29 | برنامج 30 | بعضهم 31 | البقاء 32 | بمجرد 33 | بؤرة 34 | بينما 35 | تاريخ 36 | تبحث 37 | تبقى 38 | تتصل 39 | تصوير 40 | تفضل 41 | الثالثة 42 | ثانوي 43 | ثعلب 44 | جاء 45 | جزيرة 46 | جميلة 47 | جيد 48 | حادثة 49 | حجم 50 | الحديث 51 | حسنا 52 | حقيبة 53 | الحقيقة 54 | حقيقية 55 | الحياة 56 | خائف 57 | خائفة 58 | خشب 59 | خلال 60 | دائما 61 | درجة 62 | دكتور 63 | ذاكرتك 64 | الذراع 65 | ذكاء 66 | ذلك 67 | الذهاب 68 | ذئب 69 | رائع 70 | رغم 71 | رفاق 72 | رؤية 73 | رئيس 74 | زواج 75 | ساعة 76 | سعيد 77 | سنوات 78 | سيارة 79 | شاطئ 80 | شخص 81 | شخصية 82 | شمس 83 | شؤون 84 | شيء 85 | الشيء 86 | صحيح 87 | صديقي 88 | صغير 89 | صفحة 90 | صندوق 91 | ضابط 92 | الضرورة 93 | الضوء 94 | ضوضاء 95 | الطاقة 96 | الطائرة 97 | طبيب 98 | ظلام 99 | العالم 100 | عائلتي 101 | العربية 102 | عزيزتي 103 | العشاء 104 | عظيم 105 | على 106 | غاضب 107 | الغداء 108 | غرفة 109 | الفتاة 110 | فخور 111 | فريق 112 | الفضاء 113 | فضلك 114 | فقط 115 | فوائد 116 | في 117 | القادمة 118 | قائد 119 | قائمة 120 | القبض 121 | قبل 122 | قراءة 123 | قصة 124 | قضية 125 | قليلا 126 | قليلة 127 | كتاب 128 | كثير 129 | كيف 130 | لا 131 | اللحم 132 | لطيف 133 | لعبة 134 | اللقاء 135 | لقد 136 | للغاية 137 | لوحة 138 | لؤلؤ 139 | الليلة 140 | ماذا 141 | الماضي 142 | مجموعة 143 | محظوظ 144 | المدرسة 145 | مدهش 146 | مرحبا 147 | مريض 148 | مساء 149 | مساعدة 150 | مستشفى 151 | المستقبل 152 | مسرور 153 | مسؤولية 154 | مشاهدة 155 | مشكلة 156 | مضاعفة 157 | مطعم 158 | مع 159 | معلومات 160 | مغناطيس 161 | مفاتيح 162 | مفاجئ 163 | المفضل 164 | مقروء 165 | مكان 166 | ممارسة 167 | من 168 | منخفض 169 | المنزل 170 | مؤدب 171 | موسيقى 172 | موضوع 173 | مؤقتة 174 | مؤمن 175 | ميناء 176 | الناس 177 | نافذة 178 | نصائح 179 | الهاتف 180 | هادئ 181 | هدوء 182 | هذا 183 | هل 184 | هنالك 185 | هو 186 | هؤلاء 187 | هي 188 | هيئة 189 | واحدة 190 | واضحة 191 | وضع 192 | وظيفة 193 | الوقت 194 | إلى 195 | يبدو 196 | يحدث 197 | يعتقدون 198 | يفترض 199 | يمكنني 200 | عَلَم 201 | تحمّل 202 | عزّ 203 | خسّ 204 | كُرُنب 205 | قلِق 206 | مستنِد 207 | ملوّن 208 | عُمان 209 | راعٍ 210 | رامٍ 211 | شهّر 212 | راسَل 213 | مراسِلة 214 | سُنّة 215 | صوّر 216 | جمّل 217 | هاتِف 218 | مُبَسّط 219 | حرّف -------------------------------------------------------------------------------- /data/word_lists/it.txt: -------------------------------------------------------------------------------- 1 | come 2 | io 3 | nostro 4 | sono 5 | con 6 | uno 7 | è 8 | avevamo 9 | questo 10 | quello 11 | da 12 | caldo 13 | parola 14 | però 15 | cosa 16 | alcuni 17 | vostro 18 | posto 19 | altro 20 | era 21 | no 22 | fare 23 | sì 24 | preso 25 | chiesto 26 | fatto 27 | tempo 28 | ogni 29 | dire 30 | tre 31 | quattro 32 | chiedere 33 | bene 34 | anche 35 | giocare 36 | piccolo 37 | male 38 | morto 39 | mettere 40 | finire 41 | leggere 42 | mano 43 | casa 44 | grande 45 | più 46 | terra 47 | giovane 48 | vecchio 49 | tipo 50 | bisogno 51 | provare 52 | mamma 53 | papà 54 | vicino 55 | nuovo 56 | indietro 57 | anno 58 | treno 59 | pensiero 60 | turno 61 | molte 62 | troppo 63 | italiano 64 | quando 65 | sarebbe 66 | lungo 67 | guardare 68 | andare 69 | potuto 70 | numero 71 | giorno 72 | mio 73 | sapere 74 | acqua 75 | trovare 76 | fondare 77 | risposta 78 | scuola 79 | ancora 80 | qualche 81 | chiamare 82 | chiudere 83 | portare 84 | idea 85 | colore 86 | legno 87 | bianco 88 | nero 89 | camminare 90 | alleviare 91 | secondo 92 | abbastanza 93 | primo 94 | misurare 95 | metà 96 | capire 97 | comprendere 98 | prendere 99 | studiare 100 | mancare 101 | lontano 102 | sicuramente 103 | veloce 104 | velocemente 105 | giustamente 106 | intelligente 107 | oceano 108 | matematica 109 | mente 110 | ricordo 111 | interessante 112 | parole 113 | nuvole 114 | cielo 115 | pace 116 | amore 117 | fratello 118 | sorella 119 | famiglia 120 | massa 121 | palla 122 | cuore 123 | venire 124 | inverno 125 | strano 126 | viaggio 127 | musica 128 | melodia 129 | pausa 130 | salire 131 | giardino 132 | giusto 133 | bambino 134 | latte 135 | ordinare 136 | povero 137 | metallo 138 | legge 139 | per 140 | a 141 | anello 142 | raggio 143 | atomo 144 | umano 145 | pasta 146 | pizza 147 | pianoforte 148 | maggiore 149 | minore 150 | scale 151 | corrente 152 | pranzo 153 | mangiare 154 | uscire 155 | cane 156 | gatto 157 | elefante 158 | mucca 159 | albero 160 | fiore 161 | vincere 162 | perdere 163 | baciare 164 | vediamo 165 | chiacchierare 166 | video 167 | canzone 168 | vento 169 | contro 170 | serpente 171 | presto 172 | mentre 173 | durante 174 | dentro 175 | completamente 176 | chimica 177 | fisica 178 | latino 179 | viaggiare 180 | loro 181 | bicicletta 182 | automobile 183 | pensare 184 | curare 185 | lago 186 | aperto 187 | sentire 188 | cavallo 189 | notte 190 | bello 191 | brutto 192 | oggi 193 | domani 194 | ieri 195 | dormire 196 | sognare 197 | divano 198 | arrogante 199 | ballare 200 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | /* main.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | mod application; 21 | mod config; 22 | mod discord_rpc; 23 | mod settings; 24 | mod text_generation; 25 | mod text_utils; 26 | mod typing_test_utils; 27 | mod widgets; 28 | 29 | use self::application::KpApplication; 30 | 31 | use config::{APP_ID, GETTEXT_PACKAGE, LOCALEDIR}; 32 | use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain}; 33 | use gtk::prelude::*; 34 | use gtk::{gio, glib}; 35 | 36 | static GRESOURCE_BYTES: &[u8] = 37 | gvdb_macros::include_gresource_from_dir!("/dev/bragefuglseth/Keypunch", "data/resources"); 38 | 39 | fn main() -> glib::ExitCode { 40 | // Set up gettext translations 41 | bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain"); 42 | bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8") 43 | .expect("Unable to set the text domain encoding"); 44 | textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain"); 45 | 46 | // Load resources 47 | gio::resources_register( 48 | &gio::Resource::from_data(&glib::Bytes::from_static(GRESOURCE_BYTES)).unwrap(), 49 | ); 50 | 51 | // Create a new GtkApplication. The application manages our main loop, 52 | // application windows, integration with the window manager/compositor, and 53 | // desktop features such as file opening and single-instance applications. 54 | let app = KpApplication::new(APP_ID, &gio::ApplicationFlags::empty()); 55 | 56 | // Run the application. This function will block until the application 57 | // exits. Upon return, we have our exit code to return to the shell. (This 58 | // is the code you see when you do `echo $?` after running a command in a 59 | // terminal. 60 | app.run() 61 | } 62 | -------------------------------------------------------------------------------- /data/word_lists/fi.txt: -------------------------------------------------------------------------------- 1 | mies 2 | nainen 3 | poika 4 | tyttö 5 | hallitus 6 | mökki 7 | Suomi 8 | maailma 9 | Eurooppa 10 | hali 11 | rakkaus 12 | teko 13 | murha 14 | koe 15 | raha 16 | tappelu 17 | siili 18 | tuuletin 19 | ihminen 20 | allas 21 | baari 22 | ravintola 23 | kuolema 24 | pako 25 | vankila 26 | mahdollisuus 27 | suklaa 28 | karkki 29 | pilkku 30 | piste 31 | silmä 32 | lasi 33 | tunneli 34 | kotka 35 | lisko 36 | veri 37 | lohi 38 | sauna 39 | peruna 40 | sana 41 | vene 42 | järvi 43 | mokkapala 44 | muffinssi 45 | salasana 46 | testi 47 | kaakao 48 | palapeli 49 | peli 50 | suola 51 | sokeri 52 | armeija 53 | kala 54 | meri 55 | joki 56 | kuohu 57 | matelija 58 | kilpikonna 59 | saari 60 | maa 61 | sänky 62 | sarvi 63 | taulu 64 | matto 65 | nuoli 66 | ase 67 | teoria 68 | koomikko 69 | raamattu 70 | tietokone 71 | mato 72 | insinööri 73 | ohjelmoija 74 | fyysikko 75 | matemaatikko 76 | laatikko 77 | maksalaatikko 78 | seteli 79 | näyttö 80 | kaula 81 | vampyyri 82 | viikate 83 | viikatemies 84 | sankari 85 | timantti 86 | louhos 87 | kulta 88 | hopea 89 | kauha 90 | lettu 91 | hillo 92 | sitruuna 93 | nuudeli 94 | pasta 95 | rauha 96 | totta 97 | valhe 98 | veteraani 99 | ruoka 100 | marmeladi 101 | ruotsalainen 102 | suomalainen 103 | pelto 104 | kaupunki 105 | maaseutu 106 | lukio 107 | yliopisto 108 | tehdas 109 | päästöt 110 | vakava 111 | rasva 112 | nahka 113 | salmi 114 | pilvi 115 | aurinko 116 | yritys 117 | konkurssi 118 | pörssi 119 | he 120 | nauraa 121 | tuote 122 | jäte 123 | hiukset 124 | lapsi 125 | rituaali 126 | symboli 127 | risti 128 | patonki 129 | markka 130 | sota 131 | ukkonen 132 | lokki 133 | juhla 134 | uhri 135 | liekki 136 | rautatie 137 | maito 138 | rauta 139 | sinkki 140 | hana 141 | vesi 142 | makkara 143 | ketsuppi 144 | lauta 145 | tatti 146 | kamera 147 | yksityiskohta 148 | pensas 149 | tie 150 | kauppa 151 | hylly 152 | olut 153 | lepakko 154 | nunna 155 | erakko 156 | tuore 157 | sielu 158 | parta 159 | tähti 160 | video 161 | matka 162 | rahka 163 | tilata 164 | klassikko 165 | kappale 166 | linkki 167 | kuulokkeet 168 | ajatus 169 | nurkka 170 | ahdistus 171 | lastenvahti 172 | isä 173 | perhe 174 | vanhemmat 175 | hevonen 176 | leipä 177 | luola 178 | teatteri 179 | sohva 180 | nilkka 181 | mekko 182 | juoma 183 | limonadi 184 | uhkaava 185 | nuori 186 | korva 187 | nenä 188 | asunto 189 | lukko 190 | posti 191 | aula 192 | puhelin 193 | lattia 194 | selkä 195 | pää 196 | rinta 197 | sairaala 198 | sydän 199 | kyyti 200 | aita 201 | aika 202 | tulevaisuus 203 | peikko 204 | pelko 205 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | # meson.build 2 | # 3 | # SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name() 20 | 21 | conf = configuration_data() 22 | conf.set_quoted('APP_ID', app_id) 23 | conf.set_quoted('VERSION', meson.project_version()) 24 | conf.set_quoted('GETTEXT_PACKAGE', 'keypunch') 25 | conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir')) 26 | conf.set_quoted('PKGDATADIR', pkgdatadir) 27 | 28 | configure_file( 29 | input: 'config.rs.in', 30 | output: 'config.rs', 31 | configuration: conf 32 | ) 33 | 34 | # Copy the config.rs output to the source directory. 35 | run_command( 36 | 'cp', 37 | meson.project_build_root() / 'src' / 'config.rs', 38 | meson.project_source_root() / 'src' / 'config.rs', 39 | check: true 40 | ) 41 | 42 | cargo_bin = find_program('cargo') 43 | cargo_opt = [ '--manifest-path', meson.project_source_root() / 'Cargo.toml' ] 44 | cargo_opt += [ '--target-dir', meson.project_build_root() / 'src' ] 45 | 46 | if get_option('sandboxed') 47 | # This is the path used by flatpak-cargo-generator in flatpak-builder-tools 48 | cargo_env = [ 'CARGO_HOME=' + meson.project_source_root() / 'cargo' ] 49 | else 50 | cargo_env = [ 'CARGO_HOME=' + meson.project_build_root() / 'cargo-home' ] 51 | endif 52 | 53 | if get_option('buildtype') == 'release' 54 | cargo_opt += [ '--release' ] 55 | rust_target = 'release' 56 | else 57 | rust_target = 'debug' 58 | endif 59 | 60 | cargo_build = custom_target( 61 | 'cargo-build', 62 | build_by_default: true, 63 | build_always_stale: true, 64 | output: meson.project_name(), 65 | console: true, 66 | install: true, 67 | install_dir: get_option('bindir'), 68 | command: [ 69 | 'env', cargo_env, 70 | cargo_bin, 'build', 71 | cargo_opt, '&&', 'cp', 'src' / rust_target / meson.project_name(), '@OUTPUT@', 72 | ] 73 | ) 74 | -------------------------------------------------------------------------------- /data/word_lists/el.txt: -------------------------------------------------------------------------------- 1 | άρθρο 2 | στέψη 3 | βασικό 4 | εγώ 5 | εβδομάδα 6 | αστείο 7 | διάφορα 8 | πηγαίνω 9 | άσχημος 10 | εταιρεία 11 | νύχτα 12 | λουλούδι 13 | εφεύρεση 14 | κρεβάτι 15 | γελάω 16 | ζωή 17 | νόστιμο 18 | μπορώ 19 | έχει 20 | βουνό 21 | διαγωνισμός 22 | ειδικό 23 | μηχανικός 24 | τηλεόραση 25 | κάθε 26 | πλύση 27 | μαύρο 28 | όχι 29 | υπάρχω 30 | γιορτή 31 | άγριο 32 | εικόνα 33 | μητέρα 34 | πρόβατο 35 | κόκκινο 36 | στέγη 37 | μυστήριο 38 | ψάρι 39 | μπορεί 40 | ποδήλατο 41 | έργο 42 | ελπίδα 43 | πρέπει 44 | αδερφός 45 | κακός 46 | όμορφος 47 | πατέρας 48 | αρχαίο 49 | τρία 50 | λάμπα 51 | ιστορία 52 | χθες 53 | θα 54 | πτήση 55 | ώρα 56 | βλέπω 57 | τον 58 | ψηφιακός 59 | φως 60 | πρώτο 61 | χειμώνας 62 | πρωί 63 | αυτή 64 | κεφάλι 65 | άρωμα 66 | πιάτο 67 | τραγούδι 68 | κάνω 69 | αστυνόμος 70 | πριν 71 | γρήγορα 72 | κλήση 73 | ύπαρξη 74 | πράξη 75 | άνοιξη 76 | κόρη 77 | ομιλία 78 | ομάδα 79 | ένα 80 | δευτερόλεπτο 81 | φθινόπωρο 82 | εκείνη 83 | υπάρχεις 84 | την 85 | χτίσιμο 86 | η 87 | λαιμός 88 | καληνύχτα 89 | καλός 90 | ζυμαρικά 91 | οργανισμός 92 | φώκια 93 | κύριο 94 | στήθος 95 | νερό 96 | βαρετό 97 | χοιρινό 98 | χώρα 99 | ταξίδι 100 | έχω 101 | πολυθρόνα 102 | θάλασσα 103 | φτιάχνω 104 | σήμερα 105 | κοτόπουλο 106 | δίσκος 107 | μακριά 108 | εμπειρία 109 | σώμα 110 | επιτυχία 111 | γεύση 112 | σπουδές 113 | θέλεις 114 | υγεία 115 | γιος 116 | ήταν 117 | στομάχι 118 | όταν 119 | καλημέρα 120 | επιστήμη 121 | δύο 122 | τελευταίο 123 | κοινότητα 124 | χέρι 125 | καπέλο 126 | εκείνο 127 | φρούτο 128 | αγρότης 129 | ναι 130 | τυρί 131 | εκείνος 132 | βέλος 133 | μήνας 134 | πάγος 135 | θέλω 136 | δάκτυλο 137 | κλειστό 138 | αργά 139 | αυτός 140 | ορειβασία 141 | γεια 142 | αέρας 143 | είσαι 144 | φορητό 145 | διεθνής 146 | μάγειρας 147 | φτάνω 148 | αύριο 149 | κάνει 150 | καταγραφικό 151 | όξινο 152 | ψυχή 153 | φιλικό 154 | μονοπάτι 155 | μαχαίρι 156 | σκοτώνω 157 | βράδυ 158 | χρήσιμο 159 | καρέκλα 160 | άστρο 161 | έτος 162 | εποχή 163 | έπιπλο 164 | μεσημέρι 165 | κινητό 166 | διδάσκω 167 | χημικό 168 | πόλη 169 | πέψη 170 | του 171 | αγάπη 172 | ευχαριστώ 173 | καλησπέρα 174 | πωλητής 175 | οδηγός 176 | αρνί 177 | πλοίο 178 | ευτυχία 179 | εγγραφή 180 | ξενώνας 181 | νησί 182 | κωμωδία 183 | βρίσκομαι 184 | πλάτη 185 | υπάλληλος 186 | θάνατος 187 | τραγωδία 188 | αιώνια 189 | αυτό 190 | πρωταθλητής 191 | χρησιμοποιώ 192 | λίγο 193 | διάστημα 194 | κάνουμε 195 | φόρεμα 196 | ζωγραφιά 197 | πίνω 198 | ξεκούραση 199 | ανακάλυψη 200 | πόδι 201 | παιδί 202 | λεπτό 203 | είμαι 204 | ποιότητα 205 | επιπλέον 206 | καλοκαίρι 207 | ποδόσφαιρο 208 | φριχτό 209 | ήλιος 210 | -------------------------------------------------------------------------------- /data/word_lists/pt_advanced.txt: -------------------------------------------------------------------------------- 1 | o 2 | de 3 | e 4 | em 5 | um 6 | que 7 | a 8 | ser 9 | para 10 | não 11 | com 12 | por 13 | ter 14 | se 15 | seu 16 | eu 17 | ele 18 | fazer 19 | mais 20 | este 21 | ou 22 | poder 23 | estar 24 | esse 25 | mas 26 | ir 27 | todo 28 | outro 29 | meu 30 | muito 31 | dizer 32 | ano 33 | isso 34 | ela 35 | também 36 | grande 37 | bom 38 | nós 39 | pessoa 40 | saber 41 | como 42 | sobre 43 | algum 44 | ver 45 | eles 46 | nosso 47 | ficar 48 | dia 49 | quando 50 | querer 51 | dever 52 | vida 53 | sem 54 | mesmo 55 | ainda 56 | coisa 57 | porque 58 | bem 59 | tempo 60 | entre 61 | sempre 62 | passar 63 | dois 64 | novo 65 | aquele 66 | quem 67 | falar 68 | tudo 69 | onde 70 | vir 71 | deixar 72 | apenas 73 | primeiro 74 | vigilante 75 | fervente 76 | circuito 77 | imprudente 78 | uma 79 | aqui 80 | mundo 81 | qualquer 82 | organizar 83 | trabalho 84 | detalhe 85 | país 86 | conseguir 87 | tu 88 | depois 89 | usar 90 | achar 91 | parte 92 | homem 93 | qual 94 | chegar 95 | haver 96 | começar 97 | conhecer 98 | agora 99 | assim 100 | gostar 101 | problema 102 | cada 103 | caso 104 | mulher 105 | elas 106 | tão 107 | encontrar 108 | hoje 109 | nada 110 | levar 111 | livro 112 | pequeno 113 | empresa 114 | precisar 115 | acontecer 116 | momento 117 | viver 118 | nunca 119 | pouco 120 | pois 121 | do 122 | nem 123 | tipo 124 | história 125 | parecer 126 | sentir 127 | contra 128 | vez 129 | casa 130 | antes 131 | filho 132 | verdade 133 | ler 134 | social 135 | importante 136 | criar 137 | escrever 138 | continuar 139 | cidade 140 | receber 141 | acabar 142 | então 143 | informação 144 | nome 145 | colocar 146 | processo 147 | diferente 148 | gente 149 | sair 150 | tentar 151 | isto 152 | direito 153 | pai 154 | lugar 155 | trabalhar 156 | durante 157 | criança 158 | valor 159 | governo 160 | mostrar 161 | ponto 162 | palavra 163 | hora 164 | certo 165 | perder 166 | possível 167 | apresentar 168 | voltar 169 | situação 170 | mês 171 | jogo 172 | existir 173 | sistema 174 | ajudar 175 | serviço 176 | público 177 | tanto 178 | blog 179 | entrar 180 | nenhum 181 | três 182 | tomar 183 | questão 184 | amor 185 | tal 186 | grupo 187 | através 188 | amigo 189 | comentário 190 | seguir 191 | contar 192 | acreditar 193 | alto 194 | filme 195 | esperar 196 | tornar 197 | semana 198 | texto 199 | abrir 200 | quase 201 | realizar 202 | é 203 | são 204 | hà 205 | às 206 | dê 207 | vô 208 | pós 209 | você 210 | além 211 | tédio 212 | sábio 213 | ótimo 214 | série 215 | atrás 216 | tóxico 217 | alguém 218 | hilário 219 | tráfico 220 | diversão 221 | saudável 222 | orgânico 223 | impossível 224 | benção 225 | seções 226 | ligação 227 | poluição 228 | condições 229 | imediações 230 | concepções -------------------------------------------------------------------------------- /src/widgets/custom_text_dialog.blp: -------------------------------------------------------------------------------- 1 | /* custom_text_dialog.blp 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | using Gtk 4.0; 21 | using Adw 1; 22 | 23 | template $KpCustomTextDialog: Adw.Dialog { 24 | title: _("Custom Text"); 25 | content-width: 450; 26 | content-height: 500; 27 | 28 | Adw.ToolbarView { 29 | [top] 30 | Adw.HeaderBar header_bar { 31 | show-title: false; 32 | } 33 | 34 | ScrolledWindow scrolled_window { 35 | hscrollbar-policy: never; 36 | propagate-natural-height: true; 37 | 38 | Box { 39 | orientation: vertical; 40 | margin-start: 12; 41 | margin-end: 12; 42 | margin-bottom: 12; 43 | 44 | Label { 45 | label: _("Custom Text"); 46 | margin-bottom: 24; 47 | 48 | styles [ 49 | "title-1" 50 | ] 51 | } 52 | 53 | Overlay { 54 | [overlay] 55 | Label placeholder { 56 | label: _("Insert custom text…"); 57 | valign: start; 58 | halign: start; 59 | margin-top: 12; 60 | margin-start: 12; 61 | margin-end: 12; 62 | 63 | styles [ 64 | "dim-label" 65 | ] 66 | } 67 | 68 | TextView text_view { 69 | vexpand: true; 70 | wrap-mode: word_char; 71 | accepts-tab: false; 72 | 73 | accessibility { 74 | labelled-by: placeholder; 75 | } 76 | 77 | styles [ 78 | "card", 79 | "card-text-view" 80 | ] 81 | } 82 | } 83 | } 84 | } 85 | 86 | [bottom] 87 | Box { 88 | halign: center; 89 | valign: center; 90 | 91 | Button save_button { 92 | label: _("_Save"); 93 | use-underline: true; 94 | 95 | styles [ 96 | "pill", 97 | "suggested-action" 98 | ] 99 | } 100 | 101 | styles [ 102 | "toolbar-thick" 103 | ] 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /data/word_lists/et.txt: -------------------------------------------------------------------------------- 1 | olema 2 | ja 3 | see 4 | et 5 | ei 6 | mina 7 | kui 8 | tema 9 | saama 10 | ka 11 | aga 12 | tema 13 | või 14 | mis 15 | on 16 | meie 17 | teie 18 | nad 19 | mina 20 | kas 21 | kes 22 | mida 23 | kuidas 24 | millal 25 | miks 26 | sest 27 | seal 28 | siin 29 | kus 30 | selline 31 | nii 32 | väga 33 | ainult 34 | rohkem 35 | vähem 36 | alati 37 | mitte 38 | mõnikord 39 | täna 40 | eile 41 | homme 42 | varsti 43 | pärast 44 | enne 45 | kohe 46 | peale 47 | juures 48 | lähedal 49 | kaugemal 50 | sees 51 | väljas 52 | üle 53 | alla 54 | ees 55 | taga 56 | paremal 57 | vasakul 58 | üles 59 | alla 60 | sisse 61 | välja 62 | võtma 63 | andma 64 | saama 65 | tegema 66 | minema 67 | tulema 68 | jääma 69 | nägema 70 | kuulma 71 | tundma 72 | rääkima 73 | kirjutama 74 | lugema 75 | mõtlema 76 | uskuma 77 | armastama 78 | meeldima 79 | vihkama 80 | töötama 81 | õppima 82 | mäletama 83 | unustama 84 | hakkama 85 | peatama 86 | jätkama 87 | mängima 88 | jooksma 89 | hüppama 90 | istuma 91 | seisma 92 | lamama 93 | magama 94 | äratama 95 | sööma 96 | jooma 97 | ostma 98 | maksma 99 | võitma 100 | kaotama 101 | leidma 102 | kaotama 103 | kandma 104 | viskama 105 | võtma 106 | tooma 107 | viima 108 | küsima 109 | vastama 110 | lubama 111 | keelama 112 | avama 113 | sulgema 114 | algama 115 | lõppema 116 | pidama 117 | arvama 118 | uskuma 119 | ootama 120 | abielluma 121 | lahutama 122 | sündima 123 | surema 124 | elama 125 | kasvama 126 | vananema 127 | noorenema 128 | tunduma 129 | olema 130 | saama 131 | võima 132 | peab 133 | tuleb 134 | võib 135 | kindlasti 136 | muidugi 137 | tõenäoliselt 138 | kindel 139 | ebakindel 140 | hea 141 | halb 142 | ilus 143 | kole 144 | tark 145 | rumal 146 | kiire 147 | aeglane 148 | suur 149 | väike 150 | pikk 151 | lühike 152 | raske 153 | kerge 154 | külm 155 | soe 156 | kuum 157 | märg 158 | kuiv 159 | pehme 160 | kõva 161 | kerge 162 | tume 163 | hele 164 | uus 165 | vana 166 | täis 167 | tühi 168 | tõsi 169 | vale 170 | õige 171 | vale 172 | lähedal 173 | kaugel 174 | ees 175 | taga 176 | seal 177 | siin 178 | kusagil 179 | midagi 180 | kõik 181 | ükski 182 | mitte keegi 183 | keegi 184 | inimene 185 | laps 186 | mees 187 | naine 188 | poiss 189 | tüdruk 190 | vend 191 | õde 192 | ema 193 | isa 194 | vanaema 195 | vanaisa 196 | sõber 197 | tuttav 198 | kaaslane 199 | külaline 200 | pereliige 201 | õpetaja 202 | arst 203 | tööline 204 | juht 205 | müüja 206 | kirjanik 207 | kunstnik 208 | näitleja 209 | muusik 210 | sportlane 211 | kokk 212 | insener 213 | programmeerima 214 | õpilane 215 | tudeng 216 | professor 217 | direktor 218 | poliitik 219 | ametnik 220 | sepp 221 | pagar 222 | kellassepp 223 | juuksur 224 | õmbleja 225 | aeg 226 | päev 227 | öö 228 | hommik 229 | õhtu 230 | minut 231 | tund 232 | nädal 233 | kuu 234 | aasta 235 | ilm 236 | päike 237 | vihm 238 | tuul 239 | lumi 240 | jää 241 | soojus 242 | külmus 243 | pilv 244 | udu 245 | torm 246 | vaikne 247 | rahulik 248 | tormine 249 | kantseliit 250 | hunnitu 251 | jäääär -------------------------------------------------------------------------------- /data/word_lists/ro.txt: -------------------------------------------------------------------------------- 1 | acasă 2 | același 3 | acest 4 | acum 5 | aer 6 | ai 7 | ajută 8 | ajutor 9 | al 10 | ale 11 | alerga 12 | alte 13 | ani 14 | apă 15 | apoi 16 | aproape 17 | ar 18 | așa 19 | asemenea 20 | asta 21 | astfel 22 | asupra 23 | atunci 24 | au 25 | avut 26 | aur 27 | băiat 28 | bani 29 | bărbat 30 | barca 31 | pix 32 | bine 33 | bucăți 34 | București 35 | bun 36 | carte 37 | că 38 | câine 39 | cald 40 | când 41 | cântec 42 | cap 43 | capabil 44 | capăt 45 | care 46 | casă 47 | cât 48 | cauză 49 | caz 50 | ce 51 | ceea 52 | cei 53 | cele 54 | cere 55 | chiar 56 | cine 57 | citit 58 | copil 59 | cred 60 | cu 61 | cuib 62 | cum 63 | cutie 64 | cuvânt 65 | da 66 | dacă 67 | dar 68 | de 69 | deal 70 | decât 71 | deoarece 72 | despre 73 | devreme 74 | diferite 75 | dimineață 76 | din 77 | dintre 78 | doar 79 | doi 80 | două 81 | dreapta 82 | drum 83 | după 84 | ei 85 | el 86 | ele 87 | emoții 88 | este 89 | era 90 | etaj 91 | eu 92 | exemplu 93 | există 94 | face 95 | familie 96 | fată 97 | femeie 98 | ferestre 99 | fi 100 | fie 101 | fiecare 102 | flori 103 | foarte 104 | foc 105 | formă 106 | fost 107 | frate 108 | găsi 109 | grup 110 | guvern 111 | haină 112 | hârtie 113 | ia 114 | iar 115 | iarbă 116 | iată 117 | iepure 118 | imagine 119 | în 120 | înainte 121 | înapoi 122 | încă 123 | început 124 | încercați 125 | inel 126 | întoarce 127 | între 128 | într-un 129 | joc 130 | jos 131 | la 132 | lângă 133 | lapte 134 | lasă 135 | le 136 | lemn 137 | linie 138 | loc 139 | lor 140 | lucrează 141 | lucru 142 | lui 143 | lume 144 | lung 145 | luni 146 | mai 147 | mama 148 | mână 149 | mare 150 | masă 151 | mașină 152 | mea 153 | mere 154 | mi 155 | mic 156 | mijloc 157 | mine 158 | mingea 159 | minute 160 | mod 161 | mult 162 | Mureș 163 | nevoie 164 | nici 165 | niciodată 166 | noapte 167 | noastre 168 | noi 169 | nu 170 | numai 171 | număr 172 | nume 173 | oamenii 174 | obține 175 | ochi 176 | oi 177 | om 178 | ori 179 | orice 180 | ou 181 | pâine 182 | până 183 | pantofi 184 | păpușă 185 | par 186 | părinți 187 | parte 188 | pasăre 189 | pat 190 | pe 191 | pentru 192 | persoană 193 | peste 194 | pește 195 | pisică 196 | ploaie 197 | poate 198 | pom 199 | pernă 200 | pot 201 | primul 202 | prin 203 | proprii 204 | punct 205 | puțin 206 | răspuns 207 | rață 208 | rău 209 | repede 210 | rog 211 | România 212 | sare 213 | să 214 | săptămână 215 | sau 216 | scăzută 217 | stilou 218 | școală 219 | scrie 220 | se 221 | semințe 222 | și 223 | simt 224 | singur 225 | soare 226 | soră 227 | spre 228 | spune 229 | stânga 230 | știu 231 | stradă 232 | străin 233 | sunt 234 | sus 235 | suc 236 | tare 237 | țară 238 | târziu 239 | tata 240 | televizor 241 | teren 242 | timp 243 | toate 244 | tort 245 | toți 246 | trebuie 247 | trei 248 | uite 249 | ultimul 250 | un 251 | unde 252 | unor 253 | unui 254 | următor 255 | urs 256 | ușă 257 | utilizare 258 | va 259 | vă 260 | vacă 261 | vânt 262 | vechi 263 | veveriță 264 | viață 265 | vin 266 | vor 267 | vrei 268 | zăpadă 269 | zi 270 | ziua 271 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/language_request.yaml: -------------------------------------------------------------------------------- 1 | name: Language Request 2 | description: Request for a new text language to be added to Keypunch 3 | title: '[Language Request]: ' 4 | labels: 5 | - new language 6 | body: 7 | - type: input 8 | id: english-name 9 | attributes: 10 | label: English Name 11 | description: The name of the language as spelled in English 12 | placeholder: Norwegian Bokmaal 13 | validations: 14 | required: true 15 | - type: input 16 | id: native-name 17 | attributes: 18 | label: Native Name 19 | description: The name of the language as spelled natively 20 | placeholder: Norsk bokmål 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: punctuation 25 | attributes: 26 | label: Orthography 27 | description: >- 28 | Briefly explain the alphabet, word separation, and punctuation 29 | conventions of the language, in the context of typing on a keyboard. If 30 | it's hard to put into words initially, try comparing it to English. 31 | placeholder: >- 32 | Norwegian Bokmaal is pretty similar to other Western languages. Its 33 | alphabet is almost identical to the English one, except that it has 34 | three extra letters: Æ, Ø and Å. Sentences and proper nouns begin with a 35 | capitalized letter. The punctuation marks used are , ; : to break up 36 | sentences, and . ! ? to end them. Punctuation marks come directly after 37 | their corresponding words, and are followed by a space before the next 38 | word. Expressions can be wrapped in parentheses ( ) or typewriter 39 | quotation marks " ". 40 | validations: 41 | required: true 42 | - type: checkboxes 43 | id: assistance 44 | attributes: 45 | label: Implementation Assistance 46 | description: >- 47 | To get the best possible implementation of the language, we'll need some 48 | help from you! This does not require any significant technical 49 | experience, but you will have to follow a few simple instructions to run 50 | a development version of the app and perform testing. Please read and 51 | check the checkboxes below. If you can't confidently check all of them, 52 | consider finding someone else who can assist with the implementation 53 | instead. 54 | options: 55 | - label: >- 56 | I am proficient enough in this language to spot mistakes and 57 | unnatural words 58 | required: false 59 | - label: I can assist with testing and reviewing the language implementation 60 | required: false 61 | - type: textarea 62 | id: additional-info 63 | attributes: 64 | label: Additional Information 65 | description: Is there anything else that would be good to know? 66 | placeholder: >- 67 | Norwegian has two written variants; Norwegian Bokmaal and Norwegian 68 | Nynorsk. These are pretty similar, and given a word list for Norwegian 69 | Nynorsk, I can assist with testing that as well. -------------------------------------------------------------------------------- /data/word_lists/vn.txt: -------------------------------------------------------------------------------- 1 | là 2 | rất 3 | câu 4 | đâu 5 | đầu 6 | sướng 7 | trước 8 | bếp 9 | dùng 10 | đồ 11 | phải 12 | khóa 13 | toán 14 | hóa 15 | mình 16 | hạnh 17 | phúc 18 | công 19 | việc 20 | nắng 21 | kính 22 | bao 23 | cậu 24 | tớ 25 | tức 26 | bực 27 | trường 28 | thật 29 | học 30 | nghỉ 31 | nghĩ 32 | thi 33 | hành 34 | nhà 35 | loài 36 | vật 37 | cười 38 | giúp 39 | đấu 40 | do 41 | tôi 42 | nhạc 43 | bơi 44 | lịch 45 | quê 46 | đất 47 | ngọt 48 | mùa 49 | bay 50 | ngày 51 | tỉnh 52 | lũ 53 | đỉnh 54 | định 55 | tham 56 | xa 57 | cơm 58 | gạo 59 | cầu 60 | đường 61 | phương 62 | xin 63 | rằng 64 | lỗi 65 | mà 66 | giáo 67 | thương 68 | trong 69 | đó 70 | xây 71 | dựng 72 | bà 73 | trình 74 | hoài 75 | hay 76 | nói 77 | suối 78 | đỏ 79 | chấm 80 | điểm 81 | trần 82 | làm 83 | hà 84 | nước 85 | chăm 86 | bánh 87 | xanh 88 | sống 89 | thế 90 | giới 91 | hướng 92 | kinh 93 | chị 94 | quá 95 | viết 96 | tia 97 | gửi 98 | phép 99 | sợ 100 | tháng 101 | hợp 102 | cô 103 | giấy 104 | tờ 105 | trí 106 | xinh 107 | an 108 | quả 109 | đẹp 110 | quảng 111 | nam 112 | báo 113 | ngoài 114 | cảm 115 | trang 116 | đợi 117 | chi 118 | xã 119 | hội 120 | im 121 | vui 122 | vẻ 123 | khó 124 | khăn 125 | màu 126 | tình 127 | yêu 128 | nhân 129 | dân 130 | giành 131 | ba 132 | thành 133 | ơn 134 | biển 135 | hãy 136 | chim 137 | khóc 138 | điện 139 | gì 140 | trời 141 | chú 142 | lành 143 | đánh 144 | sinh 145 | vì 146 | em 147 | da 148 | theo 149 | hả 150 | bóng 151 | nào 152 | ký 153 | tên 154 | bão 155 | dạ 156 | vâng 157 | ẩm 158 | thực 159 | áo 160 | quần 161 | nội 162 | chính 163 | minh 164 | chia 165 | sẻ 166 | nghệ 167 | thư 168 | huế 169 | huyện 170 | dũng 171 | thang 172 | cuộc 173 | đời 174 | thay 175 | mặt 176 | dạy 177 | sơ 178 | chào 179 | lại 180 | đi 181 | món 182 | ăn 183 | đàn 184 | sáo 185 | gió 186 | quốc 187 | ngữ 188 | văn 189 | tin 190 | cao 191 | anh 192 | tay 193 | bình 194 | con 195 | người 196 | khánh 197 | mưa 198 | tuổi 199 | đơn 200 | phần 201 | dễ 202 | dàng 203 | ngủ 204 | hạt 205 | bướm 206 | hoàn 207 | toàn 208 | mẹ 209 | phố 210 | kĩ 211 | thuật 212 | năm 213 | nga 214 | cổ 215 | tích 216 | giờ 217 | nay 218 | hôm 219 | sao 220 | bác 221 | thầy 222 | thấy 223 | có 224 | cha 225 | bố 226 | xe 227 | nhưng 228 | ta 229 | nếu 230 | như 231 | giả 232 | mắt 233 | tai 234 | mì 235 | không 236 | hồng 237 | ông 238 | cho 239 | trên 240 | trắng 241 | ở 242 | dưới 243 | với 244 | cả 245 | họ 246 | được 247 | tại 248 | một 249 | này 250 | từ 251 | bởi 252 | nóng 253 | lạnh 254 | uống 255 | những 256 | số 257 | hai 258 | nhất 259 | nó 260 | hoặc 261 | cố 262 | các 263 | vừa 264 | của 265 | để 266 | chúng 267 | ra 268 | khác 269 | sẽ 270 | mỗi 271 | muốn 272 | cũng 273 | chơi 274 | nhỏ 275 | lớn 276 | lá 277 | cây 278 | thử 279 | hỏi 280 | nhé 281 | cuối 282 | đặt 283 | đọc 284 | ảnh 285 | thêm 286 | mực 287 | bút 288 | trái 289 | thấp 290 | bé 291 | vậy 292 | thì 293 | nên 294 | loại 295 | tắt 296 | đành 297 | cần 298 | hình 299 | lần 300 | nữa 301 | y 302 | còn 303 | chẳng 304 | gần 305 | mới 306 | cũ 307 | lâu 308 | nơi 309 | sau 310 | khi 311 | đến 312 | tốt 313 | tivi 314 | máy 315 | tính 316 | cộng 317 | trừ 318 | đúng 319 | sai 320 | -------------------------------------------------------------------------------- /data/dev.bragefuglseth.Keypunch.gschema.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 900 20 | Window Width 21 | 22 | 23 | 450 24 | Window Height 25 | 26 | 27 | false 28 | Window Maximization 29 | 30 | 31 | "Simple" 32 | Session Type 33 | 34 | 35 | "Sec30" 36 | Session Duration 37 | The duration of time-based sessions 38 | 39 | 40 | 41 | "en" 42 | Text Language 43 | The code of the language used for automatically generated text 44 | 45 | 46 | [] 47 | Recent Languages 48 | Languages shown in the list of recent ones in the text language dialog 49 | 50 | 51 | 52 | "The quick brown fox jumps over the lazy dog." 53 | Custom Text 54 | Text displayed when “Custom” is chosen from the session menu 55 | 56 | 57 | [] 58 | Personal Best 59 | The current highest amount of WPM received for each session type / duration and language 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /data/word_lists/id.txt: -------------------------------------------------------------------------------- 1 | abu 2 | ada 3 | adalah 4 | agar 5 | ahli 6 | air 7 | akan 8 | akar 9 | akibat 10 | aku 11 | alami 12 | amarah 13 | anak 14 | anda 15 | aneka 16 | angin 17 | angka 18 | antara 19 | apa 20 | apalagi 21 | arah 22 | arus 23 | asal 24 | astaga 25 | atau 26 | atas 27 | ayah 28 | ayo 29 | baca 30 | bagai 31 | bagaikan 32 | bagaimana 33 | bagi 34 | bagian 35 | bahasa 36 | bahkan 37 | bahwa 38 | baik 39 | baku 40 | banjir 41 | bantu 42 | banyak 43 | bapak 44 | bawah 45 | beberapa 46 | belajar 47 | beliau 48 | belum 49 | benar 50 | bentuk 51 | berapa 52 | berarti 53 | berbagi 54 | berbeda 55 | berharap 56 | berhenti 57 | bermain 58 | bersih 59 | besar 60 | besok 61 | biar 62 | biarpun 63 | bicara 64 | bila 65 | bisa 66 | buka 67 | buku 68 | bukan 69 | cahaya 70 | cantik 71 | cara 72 | cari 73 | cinta 74 | cipta 75 | ciri 76 | coba 77 | contoh 78 | cukup 79 | dalam 80 | dan 81 | dapat 82 | dari 83 | dekat 84 | demi 85 | demikian 86 | dengan 87 | depan 88 | desa 89 | detik 90 | di 91 | dia 92 | dingin 93 | dulu 94 | ganti 95 | gila 96 | guna 97 | habis 98 | hanya 99 | hari 100 | harus 101 | hati 102 | hidup 103 | hilang 104 | hingga 105 | huruf 106 | ibu 107 | ingin 108 | ini 109 | itu 110 | jadi 111 | jam 112 | jarak 113 | jarang 114 | jika 115 | jumlah 116 | jari 117 | kadang 118 | kalah 119 | kalau 120 | kalian 121 | kalimat 122 | kami 123 | kamu 124 | kanan 125 | kapan 126 | karena 127 | kasih 128 | kata 129 | kau 130 | ke 131 | kecil 132 | kecuali 133 | kemarin 134 | kembali 135 | kemudian 136 | keras 137 | kerja 138 | kertas 139 | ketika 140 | kiri 141 | kita 142 | kota 143 | kotor 144 | kurang 145 | lagi 146 | lagipula 147 | lalu 148 | lari 149 | layanan 150 | lebih 151 | lekas 152 | lewat 153 | libur 154 | lupa 155 | lusa 156 | maaf 157 | macam 158 | maha 159 | mampu 160 | mana 161 | marah 162 | mari 163 | masalah 164 | mati 165 | maupun 166 | melainkan 167 | melakukan 168 | melalui 169 | membaca 170 | membuat 171 | memerlukan 172 | memiliki 173 | mencuri 174 | menang 175 | mengapa 176 | mengatakan 177 | mengenai 178 | menit 179 | menjadi 180 | menjual 181 | menulis 182 | merasa 183 | mereka 184 | meski 185 | meskipun 186 | milik 187 | mohon 188 | muda 189 | mulai 190 | muncul 191 | mungkin 192 | naik 193 | nama 194 | namun 195 | nikmat 196 | oleh 197 | orang 198 | pada 199 | paham 200 | panas 201 | para 202 | pendek 203 | percaya 204 | pergi 205 | perlu 206 | pertama 207 | pohon 208 | pria 209 | publik 210 | pulang 211 | radius 212 | ragam 213 | ramah 214 | ras 215 | rasa 216 | rasio 217 | rasional 218 | rayu 219 | rendah 220 | rumah 221 | rusa 222 | rusak 223 | rusuk 224 | sabar 225 | sakit 226 | saku 227 | salah 228 | sama 229 | sambil 230 | sampai 231 | samping 232 | sana 233 | sangat 234 | sapa 235 | saya 236 | sebab 237 | sebagai 238 | sebelum 239 | sebuah 240 | secara 241 | sedang 242 | sedangkan 243 | sedikit 244 | sehingga 245 | sejak 246 | sekali 247 | sekarang 248 | sekolah 249 | selain 250 | selalu 251 | selama 252 | selamat 253 | selanjutnya 254 | seperti 255 | sering 256 | serta 257 | seru 258 | serupa 259 | setelah 260 | setiap 261 | siapa 262 | sini 263 | situ 264 | suara 265 | suatu 266 | sudah 267 | sulit 268 | sungguh 269 | supaya 270 | tahu 271 | takut 272 | taman 273 | tambah 274 | tanaman 275 | tangkap 276 | tanya 277 | tempat 278 | tenang 279 | terampil 280 | terasa 281 | terbang 282 | terima 283 | terjadi 284 | terlalu 285 | ternyata 286 | tetapi 287 | tiba 288 | tidak 289 | tinggal 290 | tinggi 291 | tolong 292 | tua 293 | tumbuh 294 | tunas 295 | tunggu 296 | turun 297 | tutup 298 | udara 299 | untuk 300 | wahai 301 | wajah 302 | wajar 303 | waktu 304 | walau 305 | walaupun 306 | wanita 307 | yaitu 308 | yakin 309 | yakni 310 | yang 311 | -------------------------------------------------------------------------------- /src/widgets/results_view.blp: -------------------------------------------------------------------------------- 1 | /* results_view.blp 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | using Gtk 4.0; 21 | 22 | template $KpResultsView: Widget{ 23 | Box { 24 | orientation: vertical; 25 | spacing: 36; 26 | halign: center; 27 | 28 | Box wpm_accuracy_box { 29 | orientation: horizontal; 30 | spacing: 12; 31 | 32 | Box { 33 | orientation: vertical; 34 | width-request: 200; 35 | 36 | Box { 37 | spacing: 6; 38 | halign: center; 39 | 40 | // For the sake of alignment 41 | Image personal_best_balancer { 42 | accessible-role: presentation; 43 | visible: bind template.show-personal-best; 44 | } 45 | 46 | Label wpm_label { 47 | styles [ 48 | "key-number" 49 | ] 50 | } 51 | 52 | Image personal_best { 53 | tooltip-text: _("New Personal Best for Configuration"); 54 | icon-name: "arrow3-up-symbolic"; 55 | visible: bind template.show-personal-best; 56 | 57 | styles [ 58 | "accent" 59 | ] 60 | } 61 | } 62 | 63 | Label { 64 | label: _("Words per Minute"); 65 | 66 | styles [ 67 | "dim-label" 68 | ] 69 | } 70 | } 71 | 72 | Separator separator {} 73 | 74 | Box { 75 | orientation: vertical; 76 | width-request: 200; 77 | 78 | Label accuracy_label { 79 | styles [ 80 | "key-number" 81 | ] 82 | } 83 | 84 | Label { 85 | label: _("Accuracy"); 86 | 87 | styles [ 88 | "dim-label" 89 | ] 90 | } 91 | } 92 | } 93 | 94 | Box test_info_box { 95 | halign: center; 96 | homogeneous: true; 97 | 98 | Box { 99 | halign: center; 100 | spacing: 6; 101 | tooltip-text: _("Test Type"); 102 | 103 | Image { 104 | icon-name: "quotation-symbolic"; 105 | accessible-role: presentation; 106 | } 107 | 108 | Label test_type_label {} 109 | } 110 | 111 | Box { 112 | halign: center; 113 | spacing: 6; 114 | tooltip-text: _("Test Duration"); 115 | 116 | Image { 117 | icon-name: "timer-symbolic"; 118 | accessible-role: presentation; 119 | } 120 | 121 | Label duration_label {} 122 | } 123 | 124 | Box language_box { 125 | halign: center; 126 | spacing: 6; 127 | tooltip-text: _("Text Language"); 128 | 129 | Image { 130 | icon-name: "language-symbolic"; 131 | accessible-role: presentation; 132 | } 133 | 134 | Label language_label {} 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /data/word_lists/ko.txt: -------------------------------------------------------------------------------- 1 | 것 2 | 하다 3 | 있다 4 | 수 5 | 나 6 | 그 7 | 없다 8 | 않다 9 | 사람 10 | 우리 11 | 이 12 | 아니다 13 | 보다 14 | 등 15 | 때 16 | 거 17 | 같다 18 | 주다 19 | 대하다 20 | 가다 21 | 년 22 | 한 23 | 말 24 | 일 25 | 때문 26 | 말하다 27 | 위하다 28 | 그러나 29 | 오다 30 | 알다 31 | 씨 32 | 그렇다 33 | 크다 34 | 또 35 | 사회 36 | 많다 37 | 안 38 | 좋다 39 | 더 40 | 받다 41 | 그것 42 | 집 43 | 나오다 44 | 따르다 45 | 그리고 46 | 문제 47 | 그런 48 | 살다 49 | 저 50 | 못하다 51 | 생각하다 52 | 모르다 53 | 속 54 | 만들다 55 | 데 56 | 두 57 | 앞 58 | 경우 59 | 중 60 | 어떤 61 | 잘 62 | 그녀 63 | 먹다 64 | 자신 65 | 문화 66 | 원 67 | 생각 68 | 어떻다 69 | 명 70 | 통하다 71 | 그러다 72 | 소리 73 | 다시 74 | 다른 75 | 이런 76 | 여자 77 | 개 78 | 정도 79 | 뒤 80 | 듣다 81 | 다 82 | 좀 83 | 들다 84 | 싶다 85 | 보이다 86 | 가지다 87 | 함께 88 | 아이 89 | 지나다 90 | 많이 91 | 시간 92 | 너 93 | 인간 94 | 사실 95 | 나다 96 | 이렇다 97 | 어머니 98 | 눈 99 | 뭐 100 | 점 101 | 의하다 102 | 시대 103 | 다음 104 | 이러하다 105 | 누구 106 | 전 107 | 곳 108 | 여러 109 | 하나 110 | 세계 111 | 버리다 112 | 위 113 | 운동 114 | 퍼센트 115 | 학교 116 | 자기 117 | 가장 118 | 대통령 119 | 가지 120 | 시작하다 121 | 바로 122 | 어느 123 | 그래서 124 | 무엇 125 | 정부 126 | 모든 127 | 번 128 | 그거 129 | 돈 130 | 국가 131 | 그런데 132 | 날 133 | 여기 134 | 모두 135 | 여성 136 | 친구 137 | 마음 138 | 후 139 | 놓다 140 | 관계 141 | 아버지 142 | 남자 143 | 어디 144 | 몸 145 | 얼굴 146 | 들어가다 147 | 왜 148 | 나타나다 149 | 말다 150 | 지역 151 | 다르다 152 | 모습 153 | 물 154 | 만나다 155 | 내다 156 | 이것 157 | 없이 158 | 이번 159 | 길 160 | 생활 161 | 쓰다 162 | 지금 163 | 뿐 164 | 사이 165 | 방법 166 | 새롭다 167 | 우리나라 168 | 앉다 169 | 처음 170 | 손 171 | 몇 172 | 그때 173 | 과정 174 | 삶 175 | 갖다 176 | 찾다 177 | 특히 178 | 시 179 | 이상 180 | 나가다 181 | 이야기 182 | 교육 183 | 사다 184 | 경제 185 | 아직 186 | 잡다 187 | 같이 188 | 선생님 189 | 예술 190 | 서다 191 | 못 192 | 역사 193 | 읽다 194 | 이제 195 | 결과 196 | 내용 197 | 물론 198 | 동안 199 | 책 200 | 일어나다 201 | 당신 202 | 시장 203 | 넣다 204 | 중요하다 205 | 무슨 206 | 느끼다 207 | 어렵다 208 | 힘 209 | 너무 210 | 나라 211 | 부르다 212 | 의미 213 | 자리 214 | 밝히다 215 | 죽다 216 | 이미 217 | 쪽 218 | 정치 219 | 국민 220 | 생명 221 | 얘기 222 | 학생 223 | 연구 224 | 엄마 225 | 이름 226 | 내리다 227 | 사건 228 | 및 229 | 쉽다 230 | 짓다 231 | 또한 232 | 이유 233 | 또는 234 | 필요하다 235 | 글 236 | 생기다 237 | 사용하다 238 | 남편 239 | 들어오다 240 | 밖 241 | 세상 242 | 작다 243 | 타다 244 | 대학 245 | 작품 246 | 상황 247 | 가운데 248 | 보내다 249 | 두다 250 | 즉 251 | 따라서 252 | 상태 253 | 이후 254 | 당시 255 | 문학 256 | 더욱 257 | 아주 258 | 지방 259 | 밤 260 | 높다 261 | 최근 262 | 채 263 | 현실 264 | 환경 265 | 컴퓨터 266 | 먼저 267 | 다니다 268 | 얼마나 269 | 자체 270 | 열다 271 | 머리 272 | 묻다 273 | 남다 274 | 부분 275 | 기업 276 | 거기 277 | 변화 278 | 아들 279 | 뜻 280 | 아 281 | 기다리다 282 | 떨어지다 283 | 선거 284 | 관하다 285 | 그냥 286 | 나누다 287 | 이용하다 288 | 거의 289 | 곧 290 | 중심 291 | 활동 292 | 오늘 293 | 서로 294 | 관심 295 | 역시 296 | 이거 297 | 애 298 | 광고 299 | 방 300 | 정신 301 | 이르다 302 | 땅 303 | 이루다 304 | 아침 305 | 웃다 306 | 현상 307 | 떠나다 308 | 기술 309 | 전체 310 | 그래 311 | 얻다 312 | 분 313 | 아름답다 314 | 끝 315 | 민족 316 | 간 317 | 조사 318 | 듯 319 | 입 320 | 그대로 321 | 영화 322 | 필요 323 | 줄 324 | 하늘 325 | 년대 326 | 과학 327 | 듯하다 328 | 자연 329 | 정말 330 | 구조 331 | 결국 332 | 밥 333 | 입다 334 | 오히려 335 | 프로그램 336 | 네 337 | 이루어지다 338 | 남 339 | 하루 340 | 그림 341 | 적 342 | 터 343 | 마시다 344 | 치다 345 | 혼자 346 | 교수 347 | 술 348 | 사랑 349 | 의식 350 | 전화 351 | 끝나다 352 | 돌아오다 353 | 맞다 354 | 아빠 355 | 걸리다 356 | 지키다 357 | 한번 358 | 커피 359 | 가슴 360 | 길다 361 | 바라보다 362 | 알아보다 363 | 회사 364 | 맛 365 | 대부분 366 | 산업 367 | 매우 368 | 오르다 369 | 음식 370 | 표정 371 | 꼭 372 | 일부 373 | 요즘 374 | 계획 375 | 느낌 376 | 얼마 377 | 고개 378 | 성격 379 | 계속 380 | 세기 381 | 세우다 382 | 아내 383 | 가족 384 | 현재 385 | 세 386 | 발전 387 | 차 388 | 놀다 389 | 향하다 390 | 관련 391 | 형태 392 | 각 393 | 도시 394 | 작업 395 | 분위기 396 | 그러하다 397 | 나이 398 | 우선 399 | 믿다 400 | 바꾸다 401 | 낳다 402 | 바 403 | 정보 404 | 열리다 405 | 좋아하다 406 | 그리다 407 | 만큼 408 | 배우다 409 | 역할 410 | 옆 411 | 행동 412 | 어 413 | 국내 414 | 비하다 415 | 기관 416 | 입장 417 | 만하다 418 | 예 419 | 아래 420 | 방식 421 | 영향 422 | 그럼 423 | 나서다 424 | 흐르다 425 | 깊다 426 | 배 427 | 내 428 | 모양 429 | 산 430 | 새 431 | 하지만 432 | 조건 433 | 문 434 | 꽃 435 | 단계 436 | 올리다 437 | 그동안 438 | 교사 439 | 갑자기 440 | 넘다 441 | 지니다 442 | 바람 443 | 잘하다 444 | 마을 445 | 어리다 446 | 대표 447 | 가능성 448 | 방향 449 | 대회 450 | 목소리 451 | 노래 452 | 바다 453 | 힘들다 454 | 공부 455 | 움직이다 456 | 의원 457 | 노력 458 | 전혀 459 | 언니 460 | 단체 461 | 알려지다 462 | 가능하다 463 | 능력 464 | 주장하다 465 | 자식 466 | 돌리다 467 | 불 468 | 주민 469 | 모으다 470 | 자료 471 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![icon](/data/artwork/icon/dev.bragefuglseth.Keypunch.svg) 2 | 3 | # Keypunch 4 | 5 | [![Available on Flathub](https://img.shields.io/flathub/downloads/dev.bragefuglseth.Keypunch?logo=flathub&labelColor=77767b&color=4a90d9)](https://flathub.org/apps/dev.bragefuglseth.Keypunch) 6 | [![Chat on Matrix](https://img.shields.io/badge/chat-%23keypunch%3Agnome.org-mediumorchid?style=flat&logo=matrix)](https://matrix.to/#/#keypunch:gnome.org) 7 | [![Proudly part of GNOME Circle](https://circle.gnome.org/assets/button/badge.svg)](https://circle.gnome.org) 8 | [![Please do not theme this app](https://stopthemingmy.app/badge.svg)](https://stopthemingmy.app) 9 | 10 | ![screenshot](/data/screenshots/2-ready.png) 11 | 12 | There is no doubt that typing on a keyboard is an essential skill in the digital age. Typing fast and accurately gives you more opportunities, more time for what matters to you, and a sense of self-accomplishment. 13 | 14 | Keypunch lets you practice typing. Thanks to fast-paced sessions with instant feedback afterwards and a plethora of available languages, you might even have a little fun doing so. With determination, proper technique and some time, you will experience a noticeable increase in both the speed and the accuracy of which your thoughts and ideas are put into words on the screen. 15 | 16 | If you are already a racer at typing, Keypunch still has something for you. Try practicing with numbers and punctuation, or choose your own text to type out as fast as you can. 17 | 18 | Get ready to accelerate your typing! 19 | 20 | ## Installation 21 | 22 | Keypunch is available on Flathub. 23 | 24 | [Download on Flathub](https://flathub.org/apps/dev.bragefuglseth.Keypunch) 25 | 26 | ## GNOME Circle 27 | 28 | Keypunch is proudly part of GNOME Circle, an initiative that champions the 29 | great software that is available for the GNOME platform. For more information, 30 | visit the GNOME Circle website. 31 | 32 | [](https://circle.gnome.org) 33 | 34 | ## Contributing 35 | 36 | Contributions are extremely welcome. To see how you can help with issue reporting, development, and translations, consult Keypunch's [contribution guide](https://welcome.gnome.org/app/Keypunch). For project-specific documentation, such as how to add a new text language, see [CONTRIBUTING.md](CONTRIBUTING.md). 37 | 38 | Please take this into consideration as well: 39 | 40 | - This project follows the [GNOME Code of Conduct](https://conduct.gnome.org). 41 | - Only Flatpak is officially supported. 42 | - If you want to contribute major changes, please discuss them beforehand to verify that they are suitable for the project. 43 | 44 | ## Name 45 | 46 | In addition to sounding neat, "Keypunch" is the name of an [actual keyboard device](https://en.wikipedia.org/wiki/Keypunch) used for creating punched cards. It might have gone out of fashion, but the fun of typing has not! 47 | 48 | ## Roadmap 49 | 50 | - Caps Lock indication 51 | - Logging of typing speed/accuracy over time, and a nice statistics dialog 52 | to view / export these statistics 53 | - Break reminders (displayed after sessions if the app has been continuously 54 | in use for a long time, to avoid finger strain) 55 | - Frustration relief (stop the session and suggest taking a break when people 56 | are obviously mashing keys randomly in frustration) 57 | - Practice mode / typing guide (?) 58 | - Local-first p2p multiplayer mode (?) 59 | 60 | ## Join the Community 61 | 62 | Any questions about the app? Or do you just want to hang out and share your typing results? Join the [Keypunch room](https://matrix.to/#/#keypunch:gnome.org) on Matrix! We can't wait to see you there. 63 | 64 | ## Support Keypunch 65 | 66 | If you're enjoying Keypunch, I'm glad to hear that! Tag me on Mastodon and let me know! I don't accept donations through a lot of platforms at the moment, but if you happen to live in a Nordic country and have access to Vipps or MobilePay, feel free to throw some money into my virtual tip jar: 67 | 68 | [![Donate with Vipps](/data/assets/vipps_button.svg)](https://qr.vipps.no/box/c18bade5-d2c3-48a2-91ec-2eb235590bea/pay-in) 69 | [![Donate with MobilePay](/data/assets/mobilepay_button.svg)](https://qr.mobilepay.dk/box/c18bade5-d2c3-48a2-91ec-2eb235590bea/pay-in) 70 | -------------------------------------------------------------------------------- /src/application.rs: -------------------------------------------------------------------------------- 1 | /* application.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use crate::discord_rpc::RpcWrapper; 21 | use adw::subclass::prelude::*; 22 | use gtk::prelude::*; 23 | use gtk::{gio, glib}; 24 | use std::cell::OnceCell; 25 | 26 | use crate::widgets::KpWindow; 27 | 28 | mod imp { 29 | use super::*; 30 | 31 | #[derive(Default)] 32 | pub struct KpApplication { 33 | pub settings: OnceCell, 34 | pub discord_rpc: RpcWrapper, 35 | } 36 | 37 | #[glib::object_subclass] 38 | impl ObjectSubclass for KpApplication { 39 | const NAME: &'static str = "KpApplication"; 40 | type Type = super::KpApplication; 41 | type ParentType = adw::Application; 42 | } 43 | 44 | impl ObjectImpl for KpApplication { 45 | fn constructed(&self) { 46 | self.parent_constructed(); 47 | let obj = self.obj(); 48 | obj.set_resource_base_path(Some("/dev/bragefuglseth/Keypunch/")); 49 | 50 | obj.setup_gactions(); 51 | 52 | obj.set_accels_for_action("win.text-language-dialog", &["comma"]); 53 | obj.set_accels_for_action("win.cancel-test", &["Escape"]); 54 | obj.set_accels_for_action("window.close", &["w"]); 55 | obj.set_accels_for_action("app.quit", &["q"]); 56 | } 57 | } 58 | 59 | impl ApplicationImpl for KpApplication { 60 | // We connect to the activate callback to create a window when the application 61 | // has been launched. Additionally, this callback notifies us when the user 62 | // tries to launch a "second instance" of the application. When they try 63 | // to do that, we'll just present any existing window. 64 | fn activate(&self) { 65 | let application = self.obj(); 66 | // Get the current window or create one if necessary 67 | let window = application.active_window().unwrap_or_else(|| { 68 | let window = KpWindow::new(&*application); 69 | window.upcast() 70 | }); 71 | 72 | // Ask the window manager/compositor to present the window 73 | window.present(); 74 | } 75 | } 76 | 77 | impl GtkApplicationImpl for KpApplication {} 78 | impl AdwApplicationImpl for KpApplication {} 79 | } 80 | 81 | glib::wrapper! { 82 | pub struct KpApplication(ObjectSubclass) 83 | @extends gio::Application, gtk::Application, adw::Application, 84 | @implements gio::ActionGroup, gio::ActionMap; 85 | } 86 | 87 | impl KpApplication { 88 | pub fn new(application_id: &str, flags: &gio::ApplicationFlags) -> Self { 89 | glib::Object::builder() 90 | .property("application-id", application_id) 91 | .property("flags", flags) 92 | .build() 93 | } 94 | 95 | fn setup_gactions(&self) { 96 | let actions = [gio::ActionEntry::builder("quit") 97 | .activate(move |app: &Self, _, _| app.quit()) 98 | .build()]; 99 | 100 | self.add_action_entries(actions); 101 | 102 | let text_language_action = self.settings().create_action("text-language"); 103 | 104 | self.add_action(&text_language_action); 105 | } 106 | 107 | pub fn settings(&self) -> &gio::Settings { 108 | self.imp() 109 | .settings 110 | .get_or_init(|| gio::Settings::new("dev.bragefuglseth.Keypunch")) 111 | } 112 | 113 | pub fn discord_rpc(&self) -> &RpcWrapper { 114 | &self.imp().discord_rpc 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/widgets/text_view/scrolling.rs: -------------------------------------------------------------------------------- 1 | /* scrolling.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use super::*; 21 | use crate::text_utils::line_offset_with_replacements; 22 | use unicode_segmentation::UnicodeSegmentation; 23 | 24 | impl imp::KpTextView { 25 | pub(super) fn scroll_animation(&self) -> adw::TimedAnimation { 26 | self.scroll_animation 27 | .get_or_init(|| { 28 | let text_view = self.text_view.get(); 29 | let vadjustment = self 30 | .text_view 31 | .vadjustment() 32 | .expect("text view has vadjustment"); 33 | 34 | adw::TimedAnimation::builder() 35 | .duration(300) 36 | .widget(&text_view) 37 | .target(&adw::PropertyAnimationTarget::new(&vadjustment, "value")) 38 | .build() 39 | }) 40 | .clone() 41 | } 42 | 43 | // Updates the scroll position according to the text view and the length of the typed text so far. 44 | // If `force` is true, the change will be made unconditionally and without an animation. 45 | pub(super) fn update_scroll_position(&self, force: bool) { 46 | let obj = self.obj(); 47 | 48 | let original = self.original_text.borrow(); 49 | let typed = self.typed_text.borrow(); 50 | 51 | let input_context = self.input_context.borrow(); 52 | let (preedit, _, _) = input_context.as_ref().unwrap().preedit_string(); 53 | 54 | // Validation is performed on typed text with one added character, to get the start index 55 | // of the next character. 56 | let (caret_line, caret_idx) = 57 | line_offset_with_replacements(&original, &typed, preedit.graphemes(true).count()); 58 | 59 | let text_view = self.text_view.get(); 60 | let buf = text_view.buffer(); 61 | 62 | let iter = buf 63 | .iter_at_line_index(caret_line as i32, caret_idx as i32) 64 | .unwrap_or(buf.end_iter()); 65 | let location = text_view.iter_location(&iter); 66 | 67 | let snap_to_top = { 68 | let mut control_iter = iter; 69 | 70 | // If we can't move the iter backwards two lines, that must mean that we're 71 | // at line 1 or 2. To prevent any form of slight scrolling when moving from line 1 to 2, 72 | // we snap the text view to the top in that case. This is necessary because some scripts 73 | // can have very tall letters. 74 | text_view.backward_display_line(&mut control_iter); 75 | 76 | !text_view.backward_display_line(&mut control_iter) || typed.is_empty() 77 | }; 78 | 79 | let y = if snap_to_top { 80 | 0. 81 | } else { 82 | (location.y() + location.height() / 2) 83 | .checked_sub(obj.height() / 2) 84 | .unwrap_or(0) as f64 85 | }; 86 | 87 | let current_position = self 88 | .text_view 89 | .vadjustment() 90 | .expect("text view always has vadjustment") 91 | .value(); 92 | 93 | let scroll_animation = self.scroll_animation(); 94 | if force { 95 | self.text_view 96 | .vadjustment() 97 | .expect("text view should have vadjustment") 98 | .set_value(y); 99 | } else { 100 | let line_has_changed = (scroll_animation.value_to() - y).abs() > 10.; 101 | 102 | if line_has_changed { 103 | scroll_animation.set_value_from(current_position); 104 | scroll_animation.set_value_to(y); 105 | scroll_animation.play(); 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/widgets/window/focus.rs: -------------------------------------------------------------------------------- 1 | /* focus.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use super::*; 21 | 22 | const UNFOCUSED_TIMEOUT_MILLIS: u64 = 2000; 23 | 24 | impl imp::KpWindow { 25 | pub(super) fn setup_focus(&self) { 26 | self.focus_button.connect_clicked(glib::clone!( 27 | #[weak(rename_to = imp)] 28 | self, 29 | move |_| { 30 | imp.focus_text_view(); 31 | } 32 | )); 33 | 34 | self.obj().connect_focus_widget_notify(glib::clone!( 35 | #[weak(rename_to = imp)] 36 | self, 37 | move |_| { 38 | let text_view = imp.text_view.get(); 39 | let bottom_stack_empty = imp.bottom_stack_empty.get(); 40 | let just_start_typing = imp.just_start_typing.get(); 41 | let focus_button = imp.focus_button.get(); 42 | let bottom_stack = imp.bottom_stack.get(); 43 | 44 | match (imp.text_view_focused(), imp.is_running()) { 45 | (true, true) => { 46 | bottom_stack.set_visible_child(&bottom_stack_empty); 47 | text_view.remove_css_class("unfocused"); 48 | } 49 | (true, false) => { 50 | bottom_stack.set_visible_child(&just_start_typing); 51 | text_view.remove_css_class("unfocused"); 52 | } 53 | (false, _) => { 54 | let timeout = glib::timeout_add_local_once( 55 | Duration::from_millis(UNFOCUSED_TIMEOUT_MILLIS), 56 | glib::clone!( 57 | #[weak] 58 | bottom_stack, 59 | #[weak] 60 | focus_button, 61 | #[weak] 62 | imp, 63 | move || { 64 | if !imp.text_view_focused() 65 | && imp.obj().visible_dialog().is_none() 66 | && imp.main_stack.visible_child_name().unwrap() == "test" 67 | { 68 | bottom_stack.set_visible_child(&focus_button); 69 | text_view.add_css_class("unfocused"); 70 | } 71 | } 72 | ), 73 | ); 74 | 75 | let Some(previous_event) = imp.last_unfocus_event.replace(Some(timeout)) 76 | else { 77 | return; 78 | }; 79 | 80 | let Some(previous_timestamp) = 81 | imp.last_unfocus_timestamp.replace(Some(Instant::now())) 82 | else { 83 | return; 84 | }; 85 | 86 | if (Instant::now() - previous_timestamp).as_millis() 87 | < UNFOCUSED_TIMEOUT_MILLIS.into() 88 | { 89 | previous_event.remove(); 90 | } 91 | } 92 | }; 93 | } 94 | )); 95 | } 96 | 97 | pub(super) fn text_view_focused(&self) -> bool { 98 | if let Some(focus) = self.obj().focus() { 99 | focus == self.text_view.get() 100 | } else { 101 | false 102 | } 103 | } 104 | 105 | pub(super) fn focus_text_view(&self) { 106 | self.obj().set_focus(Some(&self.text_view.get())); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /data/resources/icons/scalable/apps/dev.bragefuglseth.Fretboard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/typing_test_utils.rs: -------------------------------------------------------------------------------- 1 | /* session_enums.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use crate::text_generation::Language; 21 | use crate::text_utils::calculate_wpm; 22 | use gettextrs::gettext; 23 | use gtk::gio; 24 | use gtk::prelude::*; 25 | use std::str::FromStr; 26 | use std::time::{Duration, Instant, SystemTime}; 27 | use strum_macros::{Display as EnumDisplay, EnumIter, EnumString}; 28 | 29 | #[derive(Clone, Copy, PartialEq, EnumString, EnumDisplay)] 30 | pub enum GeneratedTestDifficulty { 31 | Simple, 32 | Advanced, 33 | } 34 | 35 | impl GeneratedTestDifficulty { 36 | pub fn from_settings_string(s: &str) -> Option { 37 | match s { 38 | "simple" => Some(GeneratedTestDifficulty::Simple), 39 | "advanced" => Some(GeneratedTestDifficulty::Advanced), 40 | _ => None, 41 | } 42 | } 43 | } 44 | 45 | #[derive(Clone, Copy, PartialEq)] 46 | pub enum TestConfig { 47 | Finite, 48 | Generated { 49 | language: Language, 50 | difficulty: GeneratedTestDifficulty, 51 | duration: TestDuration, 52 | }, 53 | } 54 | 55 | impl TestConfig { 56 | pub fn from_settings(settings: &gio::Settings) -> Self { 57 | match settings.string("session-type").as_str() { 58 | difficulty_string @ ("Simple" | "Advanced") => TestConfig::Generated { 59 | language: Language::from_str(&settings.string("text-language")) 60 | .unwrap_or(Language::English), 61 | difficulty: GeneratedTestDifficulty::from_str(&difficulty_string).unwrap(), 62 | duration: TestDuration::from_str(&settings.string("session-duration")).unwrap(), 63 | }, 64 | "Custom" => TestConfig::Finite, 65 | _ => panic!("invalid settings value for `session-type` key"), 66 | } 67 | } 68 | } 69 | 70 | #[derive(Copy, Clone, Default, PartialEq, EnumString, EnumDisplay, EnumIter)] 71 | pub enum TestDuration { 72 | #[default] 73 | Sec15, 74 | Sec30, 75 | Min1, 76 | Min5, 77 | Min10, 78 | } 79 | 80 | impl TestDuration { 81 | pub fn ui_string(&self) -> String { 82 | match self { 83 | TestDuration::Sec15 => gettext("15 seconds"), 84 | TestDuration::Sec30 => gettext("30 seconds"), 85 | TestDuration::Min1 => gettext("1 minute"), 86 | TestDuration::Min5 => gettext("5 minutes"), 87 | TestDuration::Min10 => gettext("10 minutes"), 88 | } 89 | } 90 | 91 | pub fn english_string(&self) -> &str { 92 | match self { 93 | TestDuration::Sec15 => "15 seconds", 94 | TestDuration::Sec30 => "30 seconds", 95 | TestDuration::Min1 => "1 minute", 96 | TestDuration::Min5 => "5 minutes", 97 | TestDuration::Min10 => "10 minutes", 98 | } 99 | } 100 | } 101 | 102 | #[derive(Copy, Clone)] 103 | pub enum PresenceState { 104 | Ready, 105 | Typing, 106 | Results, 107 | } 108 | 109 | impl PresenceState { 110 | pub fn english_string(&self) -> &str { 111 | match self { 112 | PresenceState::Ready => "Ready to start", 113 | PresenceState::Typing => "Typing", 114 | PresenceState::Results => "Viewing results", 115 | } 116 | } 117 | } 118 | 119 | #[derive(Clone, Copy)] 120 | pub struct TypingTest { 121 | pub config: TestConfig, 122 | pub start_instant: Instant, 123 | pub start_system_time: SystemTime, 124 | } 125 | 126 | impl TypingTest { 127 | pub fn new(config: TestConfig) -> Self { 128 | TypingTest { 129 | config, 130 | start_instant: Instant::now(), 131 | start_system_time: SystemTime::now(), 132 | } 133 | } 134 | } 135 | 136 | #[derive(Clone, Copy)] 137 | pub struct TestSummary { 138 | pub config: TestConfig, 139 | pub real_duration: Duration, 140 | pub wpm: f64, 141 | pub start_timestamp: SystemTime, 142 | pub accuracy: f64, 143 | } 144 | 145 | impl TestSummary { 146 | pub fn new( 147 | start_timestamp: SystemTime, 148 | start_instant: Instant, 149 | end_instant: Instant, 150 | config: TestConfig, 151 | original: &str, 152 | typed: &str, 153 | keystrokes: &Vec<(Instant, bool)>, 154 | ) -> Self { 155 | let real_duration = end_instant.duration_since(start_instant); 156 | let correct_keystrokes = keystrokes.iter().filter(|(_, correct)| *correct).count(); 157 | let total_keystrokes = keystrokes.len(); 158 | 159 | TestSummary { 160 | config, 161 | real_duration, 162 | wpm: calculate_wpm(real_duration, &original, &typed), 163 | start_timestamp, 164 | accuracy: correct_keystrokes as f64 / total_keystrokes as f64, 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/discord_rpc.rs: -------------------------------------------------------------------------------- 1 | /* discord_rpc.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024–2025 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use crate::typing_test_utils::*; 21 | use discord_presence::models::rich_presence::Activity; 22 | use discord_presence::Client; 23 | use std::sync::mpsc; 24 | use std::sync::mpsc::Sender; 25 | use std::thread; 26 | use std::time::SystemTime; 27 | 28 | const DISCORD_CLIENT_ID: u64 = 1320106636743802923; 29 | 30 | enum RpcMessage { 31 | SendStored, 32 | Change(TestConfig, PresenceState), 33 | UpdateStats(f64, f64), 34 | } 35 | 36 | pub struct RpcWrapper { 37 | sender: Sender, 38 | } 39 | 40 | impl Default for RpcWrapper { 41 | fn default() -> Self { 42 | let (sender, receiver) = mpsc::channel(); 43 | 44 | let sender_clone = sender.clone(); 45 | 46 | thread::spawn(move || { 47 | let start_time = SystemTime::now() 48 | .duration_since(SystemTime::UNIX_EPOCH) 49 | .ok() 50 | .map(|d| d.as_millis() as u64); 51 | 52 | let mut stored_activity = Activity::new(); 53 | let mut stored_stats: Option<(f64, f64)> = None; // WPM & accuracy 54 | 55 | let mut client = Client::new(DISCORD_CLIENT_ID); 56 | 57 | client 58 | .on_connected(move |_ctx| { 59 | sender_clone 60 | .send(RpcMessage::SendStored) 61 | .expect("channel exists until app shuts down"); 62 | }) 63 | .persist(); 64 | 65 | client.start(); 66 | 67 | for msg in receiver.iter() { 68 | if let RpcMessage::Change(session_config, state) = msg { 69 | let details_string = match session_config { 70 | TestConfig::Finite => "Custom text".to_string(), 71 | TestConfig::Generated { 72 | difficulty: GeneratedTestDifficulty::Simple, 73 | duration, 74 | .. 75 | } => format!("Simple, {}", duration.english_string()), 76 | TestConfig::Generated { 77 | difficulty: GeneratedTestDifficulty::Advanced, 78 | duration, 79 | .. 80 | } => format!("Advanced, {}", duration.english_string()), 81 | }; 82 | 83 | stored_activity = Activity::new() 84 | .state(state.english_string()) 85 | .details(details_string); 86 | } else if let RpcMessage::UpdateStats(wpm, accuracy) = msg { 87 | stored_stats = Some((wpm, accuracy)); 88 | } 89 | 90 | if let Some(time) = start_time { 91 | stored_activity = stored_activity.timestamps(|t| t.start(time)); 92 | } 93 | 94 | if let Some((wpm, accuracy)) = stored_stats { 95 | let display_accuracy = (accuracy * 100.).floor() as usize; 96 | 97 | stored_activity = stored_activity.assets(|a| { 98 | a.large_image("main") 99 | .large_text("Keypunch") 100 | .small_image(wpm_to_image(wpm)) 101 | .small_text(format!( 102 | "{:.0} WPM, {:.0}% correctness", 103 | wpm.floor(), 104 | display_accuracy 105 | )) 106 | }); 107 | } else { 108 | stored_activity = 109 | stored_activity.assets(|a| a.large_image("main").large_text("Keypunch")); 110 | }; 111 | 112 | let _ = client.set_activity(|mut a| { 113 | a.clone_from(&stored_activity); 114 | a 115 | }); 116 | } 117 | }); 118 | 119 | RpcWrapper { sender } 120 | } 121 | } 122 | 123 | impl RpcWrapper { 124 | pub fn set_activity(&self, session_config: TestConfig, state: PresenceState) { 125 | self.sender 126 | .send(RpcMessage::Change(session_config, state)) 127 | .expect("channel exists until app shuts down"); 128 | } 129 | 130 | pub fn set_stats(&self, wpm: f64, accuracy: f64) { 131 | self.sender 132 | .send(RpcMessage::UpdateStats(wpm, accuracy)) 133 | .expect("channel exists until app shuts down"); 134 | } 135 | } 136 | 137 | fn wpm_to_image(wpm: f64) -> &'static str { 138 | const WPM_IMAGES: &'static [(f64, &'static str)] = &[ 139 | (10., "0-wpm"), 140 | (20., "10-wpm"), 141 | (30., "20-wpm"), 142 | (40., "30-wpm"), 143 | (50., "40-wpm"), 144 | (60., "50-wpm"), 145 | (70., "60-wpm"), 146 | (80., "70-wpm"), 147 | (90., "80-wpm"), 148 | (100., "90-wpm"), 149 | (110., "100-wpm"), 150 | (120., "110-wpm"), 151 | (130., "120-wpm"), 152 | (140., "130-wpm"), 153 | (150., "140-wpm"), 154 | (160., "150-wpm"), 155 | (170., "160-wpm"), 156 | (180., "170-wpm"), 157 | (190., "180-wpm"), 158 | (200., "190-wpm"), 159 | ]; 160 | 161 | for (threshold, image) in WPM_IMAGES { 162 | if wpm < *threshold { 163 | return image; 164 | } 165 | } 166 | 167 | "200-wpm" 168 | } 169 | -------------------------------------------------------------------------------- /src/widgets/custom_text_dialog.rs: -------------------------------------------------------------------------------- 1 | /* custom_text_dialog.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use adw::prelude::*; 21 | use adw::subclass::prelude::*; 22 | use glib::subclass::Signal; 23 | use gtk::{gio, glib}; 24 | use std::cell::{Cell, RefCell}; 25 | use std::sync::OnceLock; 26 | 27 | mod imp { 28 | use super::*; 29 | 30 | #[derive(Default, gtk::CompositeTemplate, glib::Properties)] 31 | #[template(file = "src/widgets/custom_text_dialog.blp")] 32 | #[properties(wrapper_type = super::KpCustomTextDialog)] 33 | pub struct KpCustomTextDialog { 34 | #[template_child] 35 | pub header_bar: TemplateChild, 36 | #[template_child] 37 | pub scrolled_window: TemplateChild, 38 | #[template_child] 39 | pub placeholder: TemplateChild, 40 | #[template_child] 41 | pub text_view: TemplateChild, 42 | #[template_child] 43 | pub save_button: TemplateChild, 44 | 45 | pub apply_changes: Cell, 46 | 47 | #[property(get, construct_only, nullable)] 48 | pub settings: RefCell>, 49 | } 50 | 51 | #[glib::object_subclass] 52 | impl ObjectSubclass for KpCustomTextDialog { 53 | const NAME: &'static str = "KpCustomTextDialog"; 54 | type Type = super::KpCustomTextDialog; 55 | type ParentType = adw::Dialog; 56 | 57 | fn class_init(klass: &mut Self::Class) { 58 | klass.bind_template(); 59 | } 60 | 61 | fn instance_init(obj: &glib::subclass::InitializingObject) { 62 | obj.init_template(); 63 | } 64 | } 65 | 66 | #[glib::derived_properties] 67 | impl ObjectImpl for KpCustomTextDialog { 68 | fn signals() -> &'static [Signal] { 69 | static SIGNALS: OnceLock> = OnceLock::new(); 70 | SIGNALS.get_or_init(|| { 71 | vec![Signal::builder("discard") 72 | .param_types([str::static_type()]) 73 | .build()] 74 | }) 75 | } 76 | 77 | fn constructed(&self) { 78 | self.parent_constructed(); 79 | 80 | let header_bar = self.header_bar.get(); 81 | self.scrolled_window 82 | .vadjustment() 83 | .bind_property("value", &header_bar, "show-title") 84 | .transform_to(|_, scroll_position: f64| Some(scroll_position > 0.)) 85 | .sync_create() 86 | .build(); 87 | 88 | self.text_view 89 | .buffer() 90 | .bind_property("text", &self.placeholder.get(), "visible") 91 | .transform_to(|_, text: String| Some(text.is_empty())) 92 | .sync_create() 93 | .build(); 94 | 95 | let save_button = self.save_button.get(); 96 | self.text_view 97 | .buffer() 98 | .bind_property("text", &save_button, "sensitive") 99 | .transform_to(|_, text: String| { 100 | let has_content = text.chars().any(|c| !c.is_whitespace()); 101 | Some(has_content) 102 | }) 103 | .sync_create() 104 | .build(); 105 | 106 | save_button.connect_clicked(glib::clone!( 107 | #[weak(rename_to = imp)] 108 | self, 109 | move |_| { 110 | imp.apply_changes.set(true); 111 | imp.obj() 112 | .settings() 113 | .unwrap() 114 | .set_string("custom-text", &imp.text()) 115 | .unwrap(); 116 | imp.obj().close(); 117 | } 118 | )); 119 | } 120 | } 121 | impl WidgetImpl for KpCustomTextDialog {} 122 | impl AdwDialogImpl for KpCustomTextDialog { 123 | fn closed(&self) { 124 | if self.changed() && !self.apply_changes.get() { 125 | self.obj() 126 | .emit_by_name_with_values("discard", &[self.text().into()]); 127 | } 128 | } 129 | } 130 | 131 | impl KpCustomTextDialog { 132 | fn changed(&self) -> bool { 133 | self.obj() 134 | .settings() 135 | .unwrap() 136 | .string("custom-text") 137 | .as_str() 138 | != self.text() 139 | } 140 | 141 | fn text(&self) -> String { 142 | let buf = self.text_view.buffer(); 143 | buf.text(&buf.start_iter(), &buf.end_iter(), false) 144 | .to_string() 145 | } 146 | } 147 | } 148 | 149 | glib::wrapper! { 150 | pub struct KpCustomTextDialog(ObjectSubclass) 151 | @extends gtk::Widget, adw::Dialog; 152 | } 153 | 154 | impl KpCustomTextDialog { 155 | pub fn new(settings: &gio::Settings, initial_override: Option<&str>) -> Self { 156 | let obj: Self = glib::Object::builder() 157 | .property("settings", settings.clone()) 158 | .build(); 159 | 160 | let imp = obj.imp(); 161 | 162 | let current_text = settings.string("custom-text"); 163 | let initial_text = match initial_override { 164 | Some(s) => s, 165 | None => current_text.as_str(), 166 | }; 167 | imp.text_view.buffer().set_text(initial_text); 168 | 169 | imp.text_view 170 | .emit_by_name_with_values("select-all", &[true.into()]); 171 | 172 | obj 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/widgets/text_view/caret.rs: -------------------------------------------------------------------------------- 1 | /* caret.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use super::*; 21 | use crate::text_utils::line_offset_with_replacements; 22 | 23 | impl imp::KpTextView { 24 | pub(super) fn set_caret_x(&self, caret_x: f64) { 25 | self.caret_x.set(caret_x); 26 | self.obj().queue_draw(); 27 | } 28 | 29 | pub(super) fn set_caret_y(&self, caret_y: f64) { 30 | self.caret_y.set(caret_y); 31 | self.obj().queue_draw(); 32 | } 33 | 34 | pub(super) fn caret_x_animation(&self) -> adw::TimedAnimation { 35 | self.caret_x_animation 36 | .get_or_init(|| { 37 | let obj = self.obj().to_owned(); 38 | 39 | adw::TimedAnimation::builder() 40 | .duration(150) 41 | .widget(&obj) 42 | .target(&adw::PropertyAnimationTarget::new(&obj, "caret-x")) 43 | .build() 44 | }) 45 | .clone() 46 | } 47 | 48 | pub(super) fn caret_y_animation(&self) -> adw::TimedAnimation { 49 | self.caret_y_animation 50 | .get_or_init(|| { 51 | let obj = self.obj().to_owned(); 52 | 53 | adw::TimedAnimation::builder() 54 | .duration(150) 55 | .widget(&obj) 56 | .target(&adw::PropertyAnimationTarget::new(&obj, "caret-y")) 57 | .build() 58 | }) 59 | .clone() 60 | } 61 | 62 | pub(super) fn caret_stroke_data(&self) -> (gsk::Path, gsk::Stroke, gdk::RGBA) { 63 | let obj = self.obj(); 64 | let (r, g, b) = self.caret_rgb.get(); 65 | let caret_x = obj.caret_x() as f32; 66 | let caret_y = obj.caret_y() as f32; 67 | let caret_height = obj.caret_height() as f32; 68 | let path_builder = gsk::PathBuilder::new(); 69 | 70 | path_builder.move_to(caret_x, caret_y + caret_height); 71 | path_builder.line_to(caret_x, caret_y); 72 | 73 | let path = path_builder.to_path(); 74 | 75 | let stroke = gsk::Stroke::new(1.); 76 | 77 | let color = gdk::RGBA::new(r, g, b, 1.); 78 | 79 | (path, stroke, color) 80 | } 81 | 82 | // Calculates where the caret currently should be, and runs an animation to get it there. 83 | // If `force` is true, the change will happen unconditionally and without an animation. 84 | pub(super) fn update_caret_position(&self, force: bool) { 85 | let obj = self.obj(); 86 | 87 | let input_context = self.input_context.borrow(); 88 | let (preedit, _, _) = input_context.as_ref().unwrap().preedit_string(); 89 | 90 | let (caret_line, caret_idx) = line_offset_with_replacements( 91 | &self.original_text.borrow(), 92 | &self.typed_text.borrow(), 93 | preedit.graphemes(true).count(), 94 | ); 95 | 96 | let text_view = self.text_view.get(); 97 | let buf = text_view.buffer(); 98 | 99 | // Calculate x position 100 | let caret_iter = buf 101 | .iter_at_line_index(caret_line as i32, caret_idx as i32) 102 | .unwrap_or(buf.end_iter()); 103 | let (pos, _) = text_view.cursor_locations(Some(&caret_iter)); 104 | let (mut x, _) = 105 | text_view.buffer_to_window_coords(gtk::TextWindowType::Widget, pos.x(), pos.y()); 106 | 107 | let width = obj.width(); 108 | if text_view.starts_display_line(&caret_iter) { 109 | let mut rtl_check_iter = caret_iter.clone(); 110 | rtl_check_iter.set_line_index(0); 111 | let line_is_rtl = text_view.iter_location(&rtl_check_iter).x() > 0; 112 | 113 | x = match (self.running.get(), line_is_rtl) { 114 | (false, false) => -2, 115 | (false, true) => width + 2, 116 | (true, false) => 1, 117 | (true, true) => width - 1, 118 | }; 119 | } 120 | 121 | // Calculate y position 122 | 123 | // If we can't move the iter backwards one display line, that must mean 124 | // we're at the first one 125 | let is_first_line = !text_view.backward_display_line(&mut caret_iter.clone()); 126 | 127 | let y = if is_first_line { 128 | text_view.cursor_locations(Some(&buf.start_iter())).1.y() 129 | } else { 130 | let mut line_1_iter = buf.start_iter(); 131 | text_view.forward_display_line(&mut line_1_iter); 132 | text_view.cursor_locations(Some(&line_1_iter)).1.y() 133 | }; 134 | 135 | self.caret_height.set(pos.height() as f64); 136 | 137 | if force { 138 | self.caret_x.set(x as f64); 139 | self.caret_y.set(y as f64); 140 | obj.queue_draw(); 141 | } else { 142 | let caret_x_animation = self.caret_x_animation(); 143 | caret_x_animation.set_value_from(obj.caret_x()); 144 | caret_x_animation.set_value_to(x as f64); 145 | caret_x_animation.play(); 146 | 147 | let caret_y_animation = self.caret_y_animation(); 148 | caret_y_animation.set_value_from(obj.caret_y()); 149 | caret_y_animation.set_value_to(y as f64); 150 | caret_y_animation.play(); 151 | 152 | // Update virtual caret to accomodate software input methods (e.g. Pinyin) 153 | if let Some(input_context) = &*self.input_context.borrow() { 154 | let caret_rect = gdk::Rectangle::new(x, y, 1, pos.height()); 155 | input_context.set_cursor_location(&caret_rect); 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /data/assets/vipps_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 36 | -------------------------------------------------------------------------------- /src/widgets/text_view/input.rs: -------------------------------------------------------------------------------- 1 | /* input.rs 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | use super::*; 21 | use crate::text_utils::{end_alias, pop_grapheme_in_place, pop_word_in_place}; 22 | 23 | impl imp::KpTextView { 24 | pub(super) fn setup_input_handling(&self) { 25 | let obj = self.obj(); 26 | let input_context = gtk::IMMulticontext::new(); 27 | 28 | input_context.set_client_widget(Some(&*obj.upcast_ref::())); 29 | 30 | input_context.connect_commit(glib::clone!( 31 | #[weak(rename_to = imp)] 32 | self, 33 | move |_, text| { 34 | let obj = imp.obj(); 35 | 36 | if obj.accepts_input() { 37 | if !obj.running() { 38 | obj.set_running(true); 39 | } 40 | 41 | imp.push_typed_text(text); 42 | } 43 | } 44 | )); 45 | 46 | input_context.connect_preedit_changed(glib::clone!( 47 | #[weak(rename_to = imp)] 48 | self, 49 | move |ctx| { 50 | let obj = imp.obj(); 51 | 52 | let (preedit, _, _) = ctx.preedit_string(); 53 | let preedit = preedit.as_str(); 54 | let preedit_has_changed = imp.previous_preedit.borrow().as_str() != preedit; 55 | 56 | if preedit_has_changed && obj.accepts_input() { 57 | if !obj.running() { 58 | obj.set_running(true); 59 | } 60 | 61 | *imp.previous_preedit.borrow_mut() = preedit.to_string(); 62 | imp.typed_text_changed(TextChange::Addition); 63 | } 64 | } 65 | )); 66 | 67 | input_context.connect_retrieve_surrounding(glib::clone!( 68 | #[weak(rename_to = imp)] 69 | self, 70 | #[upgrade_or_default] 71 | move |ctx| { 72 | let current_typed = imp.typed_text.borrow(); 73 | let typed_len = current_typed.len() as i32; 74 | ctx.set_surrounding_with_selection(¤t_typed, typed_len, typed_len); 75 | true 76 | } 77 | )); 78 | 79 | input_context.connect_delete_surrounding(glib::clone!( 80 | #[weak(rename_to = imp)] 81 | self, 82 | #[upgrade_or_default] 83 | move |_, offset, _| { 84 | // The cursor will always be at the end of the typed text, 85 | // so we can safely just pop the {offset} last characters 86 | imp.pop_typed_text(offset.abs() as usize); 87 | true 88 | } 89 | )); 90 | 91 | obj.connect_has_focus_notify(glib::clone!( 92 | #[weak] 93 | input_context, 94 | move |obj| { 95 | if obj.has_focus() { 96 | input_context.focus_in(); 97 | } else { 98 | input_context.focus_out(); 99 | } 100 | } 101 | )); 102 | 103 | input_context.set_input_hints(gtk::InputHints::NO_SPELLCHECK); 104 | 105 | let click_gesture = gtk::GestureClick::new(); 106 | click_gesture.connect_released(glib::clone!( 107 | #[weak] 108 | input_context, 109 | move |controller, _, _, _| { 110 | input_context.activate_osk(controller.current_event()); 111 | } 112 | )); 113 | self.obj().add_controller(click_gesture); 114 | 115 | let event_controller = gtk::EventControllerKey::new(); 116 | event_controller.set_im_context(Some(&input_context)); 117 | 118 | event_controller.connect_key_pressed(glib::clone!( 119 | #[weak(rename_to = imp)] 120 | self, 121 | #[upgrade_or] 122 | glib::signal::Propagation::Proceed, 123 | move |controller, key, _, modifier| { 124 | if imp.typed_text.borrow().is_empty() { 125 | return glib::signal::Propagation::Proceed; 126 | } 127 | 128 | let obj = imp.obj(); 129 | 130 | match (obj.accepts_input(), key) { 131 | (true, gdk::Key::BackSpace) 132 | if modifier.contains(gdk::ModifierType::CONTROL_MASK) => 133 | { 134 | imp.pop_typed_text_word(); 135 | glib::signal::Propagation::Stop 136 | } 137 | (true, gdk::Key::BackSpace) => { 138 | imp.pop_typed_text(1); 139 | glib::signal::Propagation::Stop 140 | } 141 | (true, gdk::Key::Return) => { 142 | controller 143 | .im_context() 144 | .expect("input controller has im context") 145 | .emit_by_name_with_values("commit", &["\n".into()]); 146 | glib::signal::Propagation::Stop 147 | } 148 | _ => glib::signal::Propagation::Proceed, 149 | } 150 | } 151 | )); 152 | 153 | self.obj().add_controller(event_controller); 154 | self.input_context.replace(Some(input_context)); 155 | } 156 | 157 | fn push_typed_text(&self, s: &str) { 158 | self.typed_text.borrow_mut().push_str(s); 159 | 160 | let alias_opt = end_alias(&self.original_text.borrow(), &self.typed_text.borrow()); 161 | if let Some((letter, potential_alias, true)) = alias_opt { 162 | for _ in 0..potential_alias.chars().count() { 163 | self.typed_text.borrow_mut().pop(); 164 | } 165 | self.typed_text.borrow_mut().push_str(&letter); 166 | } 167 | 168 | self.typed_text_changed(TextChange::Addition); 169 | } 170 | 171 | fn pop_typed_text(&self, graphemes: usize) { 172 | pop_grapheme_in_place(&mut self.typed_text.borrow_mut(), graphemes); 173 | 174 | self.typed_text_changed(TextChange::Removal); 175 | } 176 | 177 | fn pop_typed_text_word(&self) { 178 | pop_word_in_place( 179 | &self.original_text.borrow(), 180 | &mut self.typed_text.borrow_mut(), 181 | ); 182 | 183 | self.typed_text_changed(TextChange::Removal); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/widgets/text_language_dialog.blp: -------------------------------------------------------------------------------- 1 | /* text_language_dialog.blp 2 | * 3 | * SPDX-FileCopyrightText: © 2024 Brage Fuglseth 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | using Gtk 4.0; 21 | using Adw 1; 22 | 23 | template $KpTextLanguageDialog: Adw.Dialog { 24 | title: _("Text Language"); 25 | content-width: 450; 26 | content-height: 500; 27 | focus-widget: search_entry; 28 | 29 | Adw.NavigationView { 30 | Adw.NavigationPage { 31 | tag: "choose-language"; 32 | title: _("Text Language"); 33 | 34 | Adw.ToolbarView { 35 | [top] 36 | Adw.HeaderBar header_bar { 37 | [start] 38 | Button { 39 | icon-name: "plus-large-symbolic"; 40 | tooltip-text: _("Add Language"); 41 | action-name: "navigation.push"; 42 | action-target: "'add-language'"; 43 | } 44 | } 45 | 46 | ScrolledWindow scrolled_window { 47 | hscrollbar-policy: never; 48 | propagate-natural-height: true; 49 | vexpand: true; 50 | 51 | Box { 52 | orientation: vertical; 53 | margin-start: 12; 54 | margin-end: 12; 55 | margin-bottom: 12; 56 | 57 | Label { 58 | label: _("Text Language"); 59 | margin-bottom: 24; 60 | 61 | styles [ 62 | "title-1" 63 | ] 64 | } 65 | 66 | Adw.Clamp { 67 | maximum-size: 360; 68 | 69 | SearchEntry search_entry { 70 | placeholder-text: _("Search languages…"); 71 | margin-bottom: 18; 72 | 73 | accessibility { 74 | label: _("Search languages…"); 75 | } 76 | 77 | styles [ 78 | "pill-entry" 79 | ] 80 | } 81 | } 82 | 83 | Stack stack { 84 | vhomogeneous: false; 85 | transition-type: crossfade; 86 | transition-duration: 100; 87 | vexpand: true; 88 | 89 | StackPage { 90 | name: "list"; 91 | 92 | child: Box { 93 | spacing: 24; 94 | orientation: vertical; 95 | 96 | Adw.PreferencesGroup group_recent { 97 | // Translators: Recent languages in text languages list 98 | title: _("Recent"); 99 | } 100 | 101 | Adw.PreferencesGroup group_other { 102 | // Translators: Other languages in text languages list 103 | title: _("Other"); 104 | } 105 | 106 | styles [ 107 | "background" 108 | ] 109 | }; 110 | } 111 | 112 | StackPage { 113 | name: "search-results"; 114 | 115 | child: Box { 116 | orientation: vertical; 117 | vexpand: true; 118 | 119 | ListBox search_list { 120 | selection-mode: none; 121 | 122 | accessibility { 123 | label: _("Search Results"); 124 | } 125 | 126 | styles [ 127 | "boxed-list" 128 | ] 129 | } 130 | }; 131 | } 132 | 133 | StackPage { 134 | name: "no-results"; 135 | 136 | child: Box no_results_box { 137 | orientation: vertical; 138 | vexpand: false; 139 | 140 | Box { 141 | orientation: vertical; 142 | halign: center; 143 | valign: center; 144 | spacing: 12; 145 | vexpand: true; 146 | 147 | Image { 148 | icon-name: "language-symbolic"; 149 | vexpand: false; 150 | accessible-role: presentation; 151 | 152 | styles [ 153 | "status-icon", 154 | "dim-label" 155 | ] 156 | } 157 | 158 | Label { 159 | label: _("No Matches"); 160 | 161 | styles [ 162 | "title-2" 163 | ] 164 | } 165 | 166 | Label { 167 | label: _("Try a different search"); 168 | } 169 | } 170 | }; 171 | } 172 | } 173 | } 174 | } 175 | } 176 | } 177 | 178 | Adw.NavigationPage { 179 | tag: "add-language"; 180 | title: _("Add Language"); 181 | 182 | Adw.ToolbarView { 183 | [top] 184 | Adw.HeaderBar { 185 | show-title: false; 186 | } 187 | 188 | content: ScrolledWindow { 189 | hscrollbar-policy: never; 190 | 191 | Box { 192 | orientation: vertical; 193 | valign: center; 194 | margin-start: 12; 195 | margin-end: 12; 196 | margin-top: 12; 197 | margin-bottom: 12; 198 | 199 | Box { 200 | halign: center; 201 | 202 | Picture { 203 | can-shrink: false; 204 | realize => $load_language_illustration(); 205 | } 206 | } 207 | 208 | Label { 209 | label: _("Add Language"); 210 | margin-top: 24; 211 | 212 | styles [ 213 | "title-1", 214 | ] 215 | } 216 | 217 | Label add_language_desc { 218 | label: _("You can help add a new text language to Keypunch by submitting a language request on GitHub. A GitHub account and some language knowledge is required."); 219 | justify: center; 220 | wrap: true; 221 | margin-top: 12; 222 | } 223 | 224 | Button { 225 | halign: center; 226 | margin-top: 24; 227 | clicked => $language_request_button_clicked(); 228 | 229 | Box { 230 | spacing: 6; 231 | halign: center; 232 | Label { 233 | label: _("_Create Request"); 234 | use-underline: true; 235 | } 236 | 237 | Image { 238 | icon-name: "external-link-symbolic"; 239 | accessible-role: presentation; 240 | } 241 | } 242 | 243 | accessibility { 244 | described-by: add_language_desc; 245 | } 246 | 247 | styles [ 248 | "suggested-action", 249 | "pill", 250 | ] 251 | } 252 | } 253 | }; 254 | } 255 | } 256 | } 257 | } 258 | --------------------------------------------------------------------------------