chore(developer): Merge branch 'master' into test/developer/kmcmplib-compiler-unit-tests-2

# Keyman Conventional Commit suggestions:
#
# - Link to a Sentry issue with git trailer:
#     Fixes: _MODULE_-_ID_
# - Give credit to co-authors:
#     Co-authored-by: _Name_ <_email_>
# - Use imperative, present tense ('attach' not 'attaches', 'attached' etc)
# - Don't include a period at the end of the title
# - Always include a blank line before trailers
# - More: https://github.com/keymanapp/keyman/wiki/Pull-Request-and-Commit-workflow-notes
This commit is contained in:
Dr Mark C. Sinclair 2024-07-08 09:56:50 +01:00
commit 0cdc835c40
60 changed files with 1892 additions and 1112 deletions

View file

@ -1,5 +1,24 @@
# Keyman Version History
## 18.0.69 alpha 2024-07-05
* fix(core): allow to successfully build on Ubuntu 24.04 (#11926)
* chore(windows): correct output file for 64-bit build of keyman32 in build.sh (#11930)
* chore(android,ios): Add Crowdin localization for Polytonic Greek (#11877)
## 18.0.68 alpha 2024-07-04
* refactor(windows): merge keyman64 build into keyman32 (#11906)
* refactor(windows): remove wm_keyman_keydown and wm_keyman_keyup (#11920)
## 18.0.67 alpha 2024-07-03
* refactor(common/models): move TS priority-queue implementation to web-utils (#11867)
## 18.0.66 alpha 2024-07-02
* fix(developer): handle second parameter of index correctly in kmcmplib compiler (#11815)
## 18.0.65 alpha 2024-07-01
* fix(developer): prevent non-BMP characters in key part of rule (#11806)

View file

@ -1 +1 @@
18.0.66
18.0.70

View file

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- app_name removed in 16.0 beta. Set in build.gradle -->
<!-- Context: Menu Action -->
<string name="action_share" comment="Menu action to send text content to another app">Μοιρασθῆτε</string>
<!-- Context: Menu Action -->
<string name="action_web" comment="Menu action to open Keyman browser">Φυλλομετρητής</string>
<!-- Context: Menu Action -->
<string name="action_text_size" comment="Menu action to adjust text size">Μέγεθος κειμένου</string>
<!-- Context: Menu Action -->
<string name="action_overflow" comment="Show additional menu items">Περισσότερα</string>
<!-- Context: Menu Action -->
<string name="action_clear_text" comment="Menu action to erase text">Διαγραφὴ κειμένου</string>
<!-- Context: Menu Action -->
<string name="action_info" comment="Menu action to display Keyman help page">Πληροφορίες</string>
<!-- Context: Menu Action -->
<string name="action_settings" comment="Menu action to open Settings menu">Ρυθμίσεις</string>
<!-- Context: Menu Action -->
<string name="action_install_updates" comment="Menu notification that keyboard or dictionary updates available">Εγκατάσταση Ενημερώσεων</string>
<!-- Context: Title -->
<string name="title_version" comment="Title of Keyman for Android version">Ἔκδοση %1$s</string>
<!-- Context: Text label when old Chrome version installed -->
<string name="text_require_chrome_57" comment="Banner text when old version of Chrome is installed">Τὸ Keyman ἀπαιτεῖ ἔκδοση Chrome 57 ἢ νεώτερη.</string>
<!-- Context: Button label -->
<string name="button_update_chrome" comment="Prompt to upgrade Chrome in the Play Store">Ἐνημερῶστε τὸ Chrome</string>
<!-- Context: Textfield prompt (&#8230; is the ellipsis character "...") -->
<string name="textview_hint" comment="Prompt to start typing">Ἀρχίστε νὰ γράφετε ἐδῶ&#8230;</string>
<!-- Context: Splash screen (version/copyright info currently disabled -->
<!-- Context: Splash screen (version/copyright info currently disabled -->
<!-- Context: Text Size dialog -->
<string name="text_size" comment="Current text size (number)">Μέγεθος κειμένου: %1$d</string>
<!-- Context: Text Size dialog -->
<string name="ic_text_size_up" comment="Make text bigger">Μεγαλῶστε τὸ κείμενο</string>
<!-- Context: Text Size dialog -->
<string name="ic_text_size_down" comment="Make text smaller">Μεγαλῶστε τὸ κείμενο</string>
<!-- Context: Text Size dialog -->
<string name="ic_text_size_slider" comment="Adjust text size">Ρύθμιση μεγέθους κειμένου</string>
<!-- Context: Clear Text dialog -->
<string name="all_text_will_be_cleared" comment="Erase all the text">\nΤὸ κείμενο θὰ ἐκκαθαρισθεῖ πλήρως\n</string>
<!-- Context: Get Started menu -->
<string name="get_started" comment="Menu for getting started">Μικρύνετε τὸ κείμενο</string>
<!-- Context: Get Started menu -->
<string name="add_a_keyboard" comment="Menu item to add a keyboard">Προσθέστε πληκτρολόγιο γιὰ τὴν γλῶσσα σας</string>
<!-- Context: Get Started menu -->
<string name="enable_system_keyboard" comment="Menu item to enable Keyman as system keyboard">Ὁρίστε τὸ Κῆμαν ὡς παν-συστημικὸ πληκτρολόγιο</string>
<!-- Context: Get Started menu -->
<string name="set_keyman_as_default" comment="Menu item to set Keyman as default system keyboard">Ὁρίστε τὸ Κῆμαν ὡς προεπιλεγμένο πληκτρολόγιο</string>
<!-- Context: Get Started menu -->
<string name="more_info" comment="Open the Keyman for Android help page">Περισσότερες πληροφορίες</string>
<!-- Context: Get Started menu -->
<string name="show_get_started" comment="Show the &quot;Get Started&quot; menu on startup">Κατὰ τὴν ἔναρξη νὰ προβάλλεται τὸ \"%1$s</string>
<!-- Context: Android Storage Permission -->
<string name="request_storage_permission" comment="Request storage permission to access keyboard packages">Γιὰ νὰ ἐγκαταστήσετε πακέτα πληκτρολογίων, ἐπιτρέψτε στὸ Κῆμαν νὰ διαβάζει ἐξωτερικὸ χῶρο ἀποθήκευσης.</string>
<!-- Context: Android Storage Permission -->
<string name="storage_permission_denied" comment="Keyboard package installation may fail since Android storage permission not granted">Ἀπερρίφθη αἴτημα χώρου ἀποθήκευσης. Πιθανὴ ἀποτυχία ἐγκατάστασης πακέτου πληκτρολογίου</string>
<string name="storage_permission_denied2" comment="Keyboard package installation failed. Recommend install from local file">Ἀπερρίφθη αἴτημα χώρου ἀποθηκεύσεως. Δοκιμάστε τὶς ρυθμίσεις Κῆμαν - Ἐγκατάσταση ἀπὸ τοπικὸ ἀρχεῖο</string>
<!-- Context: Keyman Settings menu -->
<string name="keyman_settings" comment="Settings menu title">Ρυθμίσεις</string>
<!-- Context: Keyman Settings menu -->
<plurals name="installed_languages">
<item quantity="one">Ἐγκατεστημένες γλῶσσες (%1$d)</item>
<item quantity="other">Ἐγκατεστημένες γλῶσσες (%1$d)</item>
</plurals>
<!-- Context: Keyman Settings menu -->
<string name="install_keyboard_or_dictionary" comment="Menu item to install keyboard or dictionary">Ἐγκαταστῆστε πληκτρολόγιο ἢ λεξικό</string>
<!-- Context: Keyman Settings menu -->
<string name="change_display_language" comment="Menu action to change interface language">Γλῶσσα προβολῆς</string>
<!-- Context: Keyman Settings menu -->
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">Μεταβολὴ ὕψους πληκτρολογίου</string>
<!-- Context: Keyman Settings menu -->
<string name="spacebar_caption" comment="Menu action to set the spacebar caption">Spacebar caption</string>
<!-- Context: Keyman Settings menu / Spacebar caption -->
<string name="spacebar_caption_keyboard" comment="Spacebar caption option - keyboard">Πληκτρολόγιο</string>
<!-- Context: Keyman Settings menu / Spacebar caption -->
<string name="spacebar_caption_language" comment="Spacebar caption option - language">Γλῶσσα</string>
<!-- Context: Keyman Settings menu / Spacebar caption -->
<string name="spacebar_caption_language_keyboard" comment="Spacebar caption option - language + keyboard">Γλῶσσα + Πληκτρολόγιο</string>
<!-- Context: Keyman Settings menu / Spacebar caption -->
<string name="spacebar_caption_blank" comment="Spacebar caption option - blank">Κενό</string>
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
<string name="spacebar_caption_hint_keyboard" comment="Spacebar caption hint - keyboard">\'Ονομα πληκτρολογίου στὸ πλῆκτρο διαστήματος</string>
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
<string name="spacebar_caption_hint_language" comment="Spacebar caption hint - language">\'Ονομα γλώσσας στὸ πλῆκτρο διαστήματος</string>
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
<string name="spacebar_caption_hint_language_keyboard" comment="Spacebar caption hint - language + keyboard">\'Ονομα πληκτρολογίου καὶ γλώσσας στὸ πλῆκτρο διαστήματος</string>
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">Καμμία λεζάντα στὸ πλῆκτρο διαστήματος</string>
<!-- Context: Keyman Settings menu / Haptic feedback -->
<string name="haptic_feedback" comment="haptic feedback on key press">Δὸνηση κατὰ τὴν πληκτρολόγηση</string>
<!-- Context: Keyman Settings menu -->
<string name="show_banner" comment="text suggestions banner">Νὰ ἐμφανίζεται πάντα banner</string>
<!-- Context: Keyman Settings menu -->
<string name="show_banner_on" comment="Description when toggle is on">Πρὸς ὑλοποίησιν</string>
<!-- Context: Keyman Settings menu -->
<string name="show_banner_off" comment="Description when toggle is off">Ὅταν εἶναι off, ἐμφανίζεται μόνο ὅταν ἔχει ἐνεργοποιηθεῖ τὸ προγνωστικὸ κείμενο</string>
<!-- Context: Keyman Settings menu -->
<string name="show_send_crash_report" comment="permission for sending crash reports">Ἐπιτρέψτε τὴν ἀποστολὴ ἀναφορῶν κατάρρευσης μέσῳ δικτύου</string>
<!-- Context: Keyman Settings menu -->
<string name="show_send_crash_report_on" comment="Description when toggle is on">Ὅταν εἶναι ΟΝ, θὰ ἀποστέλλονται ἀναφορὲς κατάρρευσης</string>
<!-- Context: Keyman Settings menu -->
<string name="show_send_crash_report_off" comment="Description when toggle is off">Ὅταν εἶναι off, δὲν θὰ ἀποστέλλονται ἀναφορὲς κατάρρευσης</string>
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
<string name="install_from_keyman_dot_com" comment="Install package from Keyman server">Ἐγκατάσταση ἀπὸ τὸ keyman.com</string>
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
<string name="install_from_local_file" comment="Install package file from local device">Ἐγκατάσταση ἀπὸ τοπικὸ ἀρχεῖο</string>
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
<string name="install_from_other_device" comment="Scan QR Code">Ἐγκατάσταση ἀπὸ ἄλλη συσκευή</string>
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
<string name="add_languages_to_installed_keyboard" comment="Install additional languages from a keyboard package">Προσθέστε γλῶσσες σὲ ἐγκατεστημένο πληκτρολόγιο</string>
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
<string name="add_language_subtext" comment="Additional information for adding another language">(ἀπὸ πακέτο πληκτρολογίου)</string>
<!-- Context: Select Package and Select Languages menu -->
<string name="title_select_keyboard_package_list" comment="Select a keyboard package to add languages">Ἐπιλέξτε Πακέτο Πληκτρολογίου</string>
<!-- Context: Select Package and Select Languages menu -->
<string name="title_select_languages_for_package" comment="Select language names from the keyboard package">Ἐπιλέξτε γλῶσσες γιὰ τὸ %1$s</string>
<!-- Context: Select Package and Select Languages menu -->
<string name="added_language_to_keyboard" comment="Notification that a language name is added to a keyboard">Προσετέθη ἡ γλῶσσα %1$s στὸ %2$s</string>
<!-- Context: Select Package and Select Languages menu -->
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Ὅλες οἱ γλῶσσες ἔχουν ἤδη ἐγκατασταθεῖ</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Σύρετε τὸ πληκτρολόγιο γιὰ νὰ ἀλλάξετε τὸ ὕψος</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Περιστρέψτε τὴν συσκευὴ γιὰ λειτουργία πορτραίτου καὶ τοπίου</string>
<!-- Context: Adjust Keyboard Height menu -->
<string name="reset_to_defaults" comment="Button to reset to default heights">Ἐπαναφέρετε τὶς προεπιλεγμένες ρυθμίσεις</string>
<!-- Context: Keyman Web Browser -->
<string name="hint_text" comment="Prompt to type in the browser search bar">Ἀναζητῆστε ἢ πληκτρολογῆστε URL</string>
<!-- Context: Keyman Web Browser -->
<string name="title_bookmarks" comment="Title for bookmarks">Σελιδοδεῖκτες</string>
<!-- Context: Keyman Web Browser -->
<string name="no_bookmarks" comment="Text when bookmark list is empty">Δὲν ὑπάρχουν σελιδοδεῖκτες</string>
<!-- Context: Keyman Web Browser -->
<string name="add_bookmark" comment="Confirmation to add bookmark">Προσθέστε σελιδοδείκτη</string>
<!-- Context: Keyman Web Browser -->
<string name="hint_title" comment="Page title for saved bookmark">Τίτλος</string>
<!-- Context: Keyman Web Browser -->
<string name="hint_url" comment="Page URL for saved bookmark">URL</string>
<!-- Context: KMP Package strings -->
<string name="title_package_failed_to_install" comment="Error dialog title when package failed to install">Τὸ πακέτο %1$s ἀπέτυχε νὰ ἐγκατασταθεῖ</string>
<!-- Context: KMP Package strings -->
<string name="downloading_keyboard_package" comment="Confirmation to download keyboard package filename">Λήψη πακέτου πληκτρολογίου\n%1$s&#8230;</string>
<!-- Context: KMP Package strings -->
<string name="failed_to_extract" comment="Notification that keyboard package failed to unzip">Ἀποτυχία ἐξαγωγῆς</string>
<!-- Context: KMP Package strings -->
<string name="install_keyboard_package" comment="Title to install keyboard package">Ἐγκαταστῆστε πληκτρολόγιο</string>
<!-- Context: KMP Package strings -->
<string name="install_predictive_text_package" comment="Title to install dictionary package">Ἐγκαταστῆστε Λεξικό</string>
<!-- Context: KMP Package strings -->
<string name="not_valid_package_file" comment="Notification when invalid package file cannot be installed">Τὸ %1$s δὲν εἶναι ἔγκυρο ἀρχεῖο πακέτου Κῆμαν.\n%2$s\"</string>
<!-- Context: KMP Package strings -->
<string name="no_new_touch_keyboards_to_install" comment="Notification when no touch-optimized keyboards can be installed">Τὸ πακέτο πληκτρολογίου δὲν ἔχει βελτιστοποιημένα πληκτρολόγια ἀφῆς πρὸς ἐγκατάστασιν</string>
<!-- Context: KMP Package strings -->
<string name="no_new_predictive_text_to_install" comment="Notification when no dictionaries can be installed">Δὲν ὑπάρχει νέο προγνωστικό κείμενο πρὸς ἐγκατάστασιν</string>
<!-- Context: KMP Package strings -->
<string name="no_targets_to_install" comment="Notification when a package doesn't contain keyboards or dictionaries">Δὲν ὑπάρχουν πληκτρολόγια ἢ προγνωστικό κείμενο πρὸς ἐγκατάστασιν</string>
<!-- Context: KMP Package strings -->
<string name="no_associated_languages" comment="Notification when a keyboard package doesn't contain languages">Τὸ πακέτο πληκτρολογίου δὲν ἔχει σχετικὲς μὲ αὐτὸ γλῶσσες πρὸς ἐγκατάστασιν</string>
<!-- Context: KMP Package strings -->
<string name="invalid_metadata" comment="kmp.json metadata file is invalid or missing in package">Ἄκυρα/ἐλλιπῆ μεταδεδομένα στὸ πακέτο</string>
<!-- Context: KMP Package strings -->
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman"> Τὸ πληκτρολόγιο ἀπαιτεῖ νεώτερη ἔκδοση τοῦ Κῆμαν</string>
<!-- Context: anywhere -->
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Ἀδυναμία ἐκκινήσεως φυλλομετρητῆ</string>
</resources>

View file

@ -62,6 +62,7 @@ public class DisplayLanguages {
new DisplayLanguageType("nl-NL", "Nederlands (Dutch)"),
new DisplayLanguageType("ann", "Obolo"),
new DisplayLanguageType("pl-PL", "Polski (Polish)"),
new DisplayLanguageType("el", "Polytonic Greek"),
new DisplayLanguageType("pt-PT", "Português do Portugal"),
new DisplayLanguageType("ff-ZA", "Pulaar-Fulfulde"), // or Fulah
new DisplayLanguageType("ru-RU", "Pyccĸий (Russian)"),

View file

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Device type -->
<!-- Application name (Keyman Engine for Android) -->
<!-- Context: Title for list -->
<plurals name="title_keyboards">
<item quantity="one">Πληκτρολόγιο</item>
<item quantity="other">Πληκτρολόγια</item>
</plurals>
<!-- Context: Title for list -->
<plurals name="title_other_input_methods">
<item quantity="one">Ἄλλη μέθοδος εἰσαγωγῆς</item>
<item quantity="other">Ἄλλες Μέθοδοι Εἰσαγωγῆς</item>
</plurals>
<!-- Context: Title for list -->
<string name="title_add_keyboard" comment="Add a new keyboard">Προσθέστε νέο Πληκτρολόγιο</string>
<!-- Context: Title for list -->
<string name="title_languages_settings" comment="List of installed languages">Ἐγκατεστημένες γλῶσσες</string>
<!-- Context: Title for list -->
<string name="title_language_settings" comment="Keyman Settings for a language">Ρυθμίσεις %1$s</string>
<!-- Context: Button label -->
<string name="label_add" comment="Button to add an item">Προσθέστε</string>
<!-- Context: Button label -->
<string name="label_back" comment="Button to go back">Πίσω</string>
<!-- Context: Button label -->
<string name="label_cancel" comment="Button to cancel an action">Ἀκυρῶστε</string>
<!-- Context: Button label -->
<string name="label_close" comment="Close a dialog">Κλεῖστε</string>
<!-- Context: Button label. Removed in Keyman 15 -->
<string name="label_close_keyman" comment="Close the Keyman application">Κλεῖστε τὸ Κῆμαν</string>
<!-- Context: Button label -->
<string name="label_forward" comment="Button to go forward">Προχωρῆστε</string>
<!-- Context: Button label -->
<string name="label_next_input_method" comment="Switch to next input method (replaces label_close_keyman)">Ἑπόμενη Μέθοδος Εἰσαγωγῆς</string>
<!-- Context: Button label -->
<string name="label_download" comment="Button to confirm downloading an item">Λήψη</string>
<!-- Context: Button label -->
<string name="label_install" comment="Confirmation to install a package">Ἐγκαταστῆστε</string>
<!-- Context: Button label -->
<string name="label_later" comment="Do an action at a later time">Ἀργότερα</string>
<!-- Context: Button label -->
<string name="label_next" comment="Go to the next screen">Ἑπόμενο</string>
<!-- Context: Button label -->
<string name="label_ok" comment="Button to acknowledge a dialog">OK</string>
<!-- Context: Button label -->
<string name="label_update" comment="Dialog button to update a resource">Ἐνημερῶστε</string>
<!-- Context: No internet for updates -->
<string name="no_internet_connection" comment="Internet connection missing">Δὲν ὑπάρχει σύνδεση μὲ τὸ Διαδίκτυο</string>
<!-- Context: Keyboard Updates -->
<string name="cannot_connect" comment="Error message when network connection fails">Ἀδυναμία συνδέσεως μὲ τὸν διακομιστὴ τοῦ Κῆμαν!</string>
<!-- Context: Keyboard Updates -->
<string name="confirm_delete_keyboard" comment="Confirmation to delete a keyboard">Θέλετε νὰ διαγράψετε αὐτὸ τὸ πληκτρολόγιο;</string>
<!-- Context: Keyboard Updates -->
<string name="confirm_download_keyboard" comment="Confirmation to download a keyboard update">Θὰ θέλατε νὰ κατεβάσετε τὴν τελευταία ἔκδοση αὐτοῦ τοῦ πληκτρολογίου;</string>
<!-- Context: Keyboard Updates -->
<string name="confirm_update" comment="Confirmation to update several resources">Θά θέλατε νὰ ἐνημερώσετε τώρα πληκτρολόγια καὶ λεξικά;</string>
<!-- Context: Keyboard Updates -->
<string name="keyboard_updates_channel">Ἐνημερώσεις Πόρων</string>
<!-- Context: Keyboard Updates -->
<string name="keyboard_updates_available" comment="Notification when resource updates are available">Διαθέσιμες Ἐνημερώσεις Πόρων</string>
<!-- Context: Keyboard Updates -->
<string name="update_available" comment="Currently installed version of a resource with an available update">%1$s (Διαθέσιμη Ἐνημέρωση)</string>
<!-- Context: Keyboard Updates -->
<string name="keyboard_update_message" comment="language name: keyboard name"> Διαθέσιμες ἐνημερώσεις γιὰ τὸ πληκτρολόγιο %1$s: %2$s </string>
<!-- Context: Keyboard Updates -->
<string name="dictionary_update_message">Διαθέσιμες ἐνημερώσεις γιὰ τὸ λεξικὸ %1$s: %2$s </string>
<!-- Context: Keyboard Info and Keyboard Settings -->
<string name="keyboard_version" comment="Label for keyboard version">Ἔκδοση πληκτρολογίου</string>
<!-- Context: Keyboard Info and Keyboard Settings -->
<string name="help_link" comment="Label for help link">Σύνδεσμος βοηθείας</string>
<!-- Context: Keyboard Info and Keyboard Settings -->
<string name="uninstall_keyboard" comment="Label for uninstalling keyboard">Ἀπεγκαταστῆστε πληκτρολόγιο</string>
<!-- Context: Keyboard Info and Keyboard Settings -->
<string name="keyboard_picker_new_keyboard" comment="Mark a language name that's newly installed in keyboard list">[νέο] %1$s</string>
<!-- Context: Keyboard Info and Keyboard Settings -->
<string name="keyboard_qr_code" comment="QR Code description">Σαρῶστε αὐτὸν τὸν κωδικό γιὰ νὰ φορτώσετε\nαὐτὸ τὸ πληκτρολόγιο σὲ ἄλλη συσκευή</string>
<!-- Context: Keyboard Help welcome.htm title -->
<string name="welcome_package" comment="Title to welcome.htm page (name and version)">Καλωσορίσατε στὸ %1$s</string>
<!-- Context: Keyboard app doesn't include FileProvider library needed to view help file -->
<string name="fileprovider_undefined" comment="FileProvider library needed to view help file">Ἀπαιτεῖται βιβλιοθήκη FileProvider γιὰ νὰ δεῖτε ἀρχεῖο βοηθείας: %1$s</string>
<!-- Context: Fatal keyboard error. Will load default keyboard -->
<string name="fatal_keyboard_error" comment="Fatal keyboard error (keyboard ID::packageID for language). Will load default keyboard">Μοιραῖο σφάλμα πληκτρολογίου στὸ %1$s:%2$s γιὰ τὴν %3$s γλῶσσα. Φορτώνεται προεπιλεγμένο πληκτρολόγιο.</string>
<!-- Context: Fatal keyboard error. -->
<string name="fatal_keyboard_error_short" comment="Error in keyboard (keyboard ID::packageID for language)."> Error in keyboard %1$s:%2$s for %3$s language.</string>
<!-- Context: Query for associated dictionary -->
<string name="query_associated_model" comment="Check if there's an available dictionary to download">Ἔλεγχος συσχετισμένου λεξικοῦ πρὸς λῆψιν</string>
<string name="cannot_query_associated_model" comment="Cannot reach server to check if there's an available dictionary to download">Ἀδυναμία συνδέσεως μὲ τὸν διακομιστὴ Κῆμαν γιὰ τὸν ἔλεγχο συσχετισμένου λεξικοῦ πρὸς λῆψιν</string>
<!-- Context: Model Updates -->
<string name="confirm_download_model" comment="Confirmation to download a dictionary update">Θὰ θέλατε νὰ κατεβάσετε τὴν τελευταία ἔκδοση αὐτοῦ τοῦ λεξικοῦ;</string>
<!-- Context: No associated dictionary found -->
<string name="no_associated_model" comment="Confirmation there's no available dictionary to download">Δὲν ὑπάρχει λεξικὸ πρὸς λῆψιν</string>
<!-- Context: Model Updates -->
<string name="catalog_unavailable" comment="Notification that the cloud resource catalog can't be updated">Μὴ διαθέσιμος κατάλογος πόρων</string>
<!-- Context: Background download messages-->
<string name="catalog_download_start_in_background" comment="Notification that the resource catalog update will begin">Ἔχει ξεκινήσει ἐνημέρωση καταλόγου στὸ παρασκήνιο</string>
<!-- Context: Background download messages-->
<string name="catalog_download_is_running_in_background" comment="Notification that the resource catalog update is still downloading">Ἡ λήψη τοῦ καταλόγου συνεχίζεται· παρακαλοῦμε ξαναδοκιμάστε σὲ λίγο!</string>
<!-- Context: Background download messages-->
<string name="progress_message_checking_resource_is_running" comment="Progress notification that the check for a resource is still running ">Ἔλεγχος πόρου σὲ ἐξέλιξη</string>
<!-- Context: Background download messages-->
<string name="keyboard_download_start_in_background" comment="Notification that a keyboard download has started">Ἡ λήψη τοῦ πληκτρολογίου ἔχει ξεκινήσει στὸ παρασκήνιο</string>
<!-- Context: Background download messages-->
<string name="keyboard_download_is_running_in_background" comment="Notification that a keyboard download is still running">Ἡ λήψη τοῦ ἐπιλεγέντος πληκτρολογίου βρίσκεται σὲ ἐξέλιξη· παρακαλοῦμε ξαναδοκιμάστε σὲ λίγο!</string>
<!-- Context: Background download messages-->
<string name="keyboard_download_finished" comment="Notification that a keyboard download has finished">Ἡ λήψη τοῦ πληκτρολογίου ὁλοκληρώθηκε!</string>
<!-- Context: Background download messages-->
<string name="dictionary_download_start_in_background" comment="Notification that a dictionary download has started">Ἡ λήψη τοῦ λεξικοῦ ἔχει ξεκινήσει στὸ παρασκήνιο</string>
<!-- Context: Background download messages-->
<string name="dictionary_download_is_running_in_background" comment="Notification that a dictionary download is still running">Ἡ λήψη τοῦ ἐπιλεγέντος λεξικοῦ βρίσκεται σὲ ἐξέλιξη· παρακαλοῦμε ξαναδοκιμάστε σὲ λίγο!</string>
<!-- Context: Background download messages. Removed in Keyman 17-->
<string name="dictionary_download_finished" comment="Notification that a dictionary download has finished">Ἡ λήψη τοῦ λεξικοῦ ὁλοκληρώθηκε.</string>
<!-- Context: Background download messages -->
<string name="download_failed" comment="Notification that a download failed">Ἡ λήψη ἀπέτυχε</string>
<!-- Context: Background download messages -->
<string name="failed_to_retrieve_file" comment="Failed to retrieve downloaded file">Ἀποτυχία ἀνακτήσεως ληφθέντος ἀρχείου</string>
<!-- Context: General Updates -->
<string name="update_check_unavailable" comment="Error message when a Keyman server can't be reached">Ἀποτυχία προσβάσεως στὸν διακομιστή!</string>
<!-- Context: General Updates -->
<string name="update_check_current" comment="Notification that all resources are up to date">"Ὅλοι οἱ πόροι ἔχουν ἐνημερωθεῖ!"</string>
<!-- Context: General Updates -->
<string name="update_failed" comment="Notification that a resource update failed">Ἕνας ἢ περισσότεροι πόροι ἀπέτυχαν νὰ ἐνημερωθοῦν!</string>
<!-- Context: General Updates. Removed in Keyman 17 -->
<string name="update_success" comment="Notification that a resource update successfully updated">Οἱ πόροι ἐνημερώθηκαν ἐπιτυχῶς!</string>
<!-- Context: Model Info -->
<string name="model_version" comment="Title for a dictionary version">Ἔκδοση λεξικοῦ</string>
<!-- Context: Model Info -->
<string name="uninstall_model" comment="Label to uninstall a dictionary">Ἀπεγκαταστῆτε λεξικό</string>
<!-- Context: Model Info -->
<string name="confirm_delete_model" comment="Confirmation to delete a dictionary">Θὰ θέλατε νὰ διαγράψετε αὐτὸ τὸ λεξικό;</string>
<!-- Context: Model Deleted -->
<string name="model_deleted" comment="Notification when a dictionary is deleted">Τὸ λεξικὸ διεγράφη</string>
<!-- Context: Language Settings Keyboard install strings -->
<string name="keyboard_install_toast" comment="Notification when a keyboard is installed">Τὸ πληκτρολόγιο %1$s ἐγκατεστάθη</string>
<!-- Context: Language Settings Keyboard uninstall strings -->
<string name="keyboard_deleted_toast" comment="Notification when a keyboard is deleted">Τὸ πληκτρολόγιο διεγράφη</string>
<!-- Context: Language Settings menu strings -->
<string name="enable_corrections" comment="Enable corrections from the suggestion banner">Ἐνεργοποιῆστε τὶς διορθώσεις</string>
<!-- Context: Language Settings menu strings -->
<string name="enable_predictions" comment="Enable predictions from the suggestion banner">Ἐνεργοποιῆστε προβλέψεις</string>
<!-- Context: Language Settings menu strings -->
<string name="model_label">Λεξικά</string>
<plurals name="model_count">
<item quantity="one">Λεξικό</item>
<item quantity="other">Λεξικά</item>
</plurals>
<!-- Context: Language Settings menu substring - Check for available dictionary -->
<string name="check_available_model" comment="Check for available dictionary">Ἔλεγχος διαθεσίμου λεξικοῦ</string>
<string name="check_model_online" comment="Check for dictionaries online">Ἔλεγχος λεξικῶν ὀνλάϊν</string>
<!-- Context: Language Settings menu strings -->
<string name="model_info_header" comment="Dictionary name">Λεξικό: %1$s</string>
<!-- Context: Language Settings menu strings -->
<string name="model_picker_header" comment="Dictionaries for a specified language">%1$s λεξικά</string>
<!-- Context: Language Settings menu strings -->
<!-- Context: Language Settings menu strings -->
<string name="model_install_toast" comment="Notification when a dictionary is installed">Τὸ λεξικὸ ἐγκατεστάθη</string>
<!-- Context: Language Settings menu strings -->
<plurals name="keyboard_count">
<item quantity="one">(%1$d πληκτρολόγιο)</item>
<item quantity="other">(%1$d πληκτρολόγια)</item>
</plurals>
<!-- Context: "Change Display Language" menu -->
<string name="default_locale" comment="Use the device's current locale">Προεπιλεγμένη Γλῶσσα</string>
<!-- Context: Content descriptions -->
<!-- Context: Content descriptions -->
<!-- Context: Popup menu labels -->
<string name="label_delete" comment="Confirmation to delete an item">Διαγράψτε</string>
<!-- Context: Shared preferences name -->
<!-- Context: Other strings -->
<string name="help_bubble_text">Κτυπῆστε ἐδῶ γιὰ νὰ ἀλλάξετε πληκτρολόγιο</string>
<!-- Context: anywhere -->
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Ἀδυναμία ἐκκινήσεως φυλλομετρητῆ</string>
</resources>

View file

@ -2,7 +2,6 @@ export {
SENTINEL_CODE_UNIT, applyTransform, buildMergedTransform, isHighSurrogate, isLowSurrogate, isSentinel,
transformToSuggestion, defaultApplyCasing
} from "./common.js";
export { default as PriorityQueue, Comparator } from "./priority-queue.js";
export { default as QuoteBehavior } from "./quote-behavior.js";
export { Tokenization, tokenize, getLastPreCaretToken, wordbreak } from "./tokenization.js";
export { default as TrieModel, TrieModelOptions } from "./trie-model.js";

View file

@ -26,12 +26,11 @@
// Should probably make a 'lm-utils' submodule.
// Allows the kmwstring bindings to resolve.
import { extendString } from "@keymanapp/web-utils";
import { extendString, PriorityQueue } from "@keymanapp/web-utils";
import { default as defaultWordBreaker } from "@keymanapp/models-wordbreakers";
import { applyTransform, isHighSurrogate, isSentinel, SENTINEL_CODE_UNIT, transformToSuggestion } from "./common.js";
import { getLastPreCaretToken } from "./tokenization.js";
import PriorityQueue from "./priority-queue.js";
extendString();
@ -74,15 +73,6 @@ export interface TrieModelOptions {
punctuation?: LexicalModelPunctuation;
}
/**
* Used to determine the probability of an entry from the trie.
*/
type TextWithProbability = {
text: string;
// TODO: use negative-log scaling instead?
p: number; // real-number weight, from 0 to 1
}
class Traversal implements LexiconTraversal {
/**
* The lexical prefix corresponding to the current traversal state.
@ -95,14 +85,75 @@ class Traversal implements LexiconTraversal {
*/
root: Node;
constructor(root: Node, prefix: string) {
/**
* The max weight for the Trie being 'traversed'. Needed for probability
* calculations.
*/
totalWeight: number;
constructor(root: Node, prefix: string, totalWeight: number) {
this.root = root;
this.prefix = prefix;
this.totalWeight = totalWeight;
}
*children(): Generator<{char: string, traversal: () => LexiconTraversal}> {
child(char: USVString): LexiconTraversal | undefined {
/*
Note: would otherwise return the current instance if `char == ''`. If
such a call is happening, it's probably indicative of an implementation
issue elsewhere - let's signal now in order to catch such stuff early.
*/
if(char == '') {
return undefined;
}
// Split into individual code units.
let steps = char.split('');
let traversal: Traversal | undefined = this;
while(steps.length > 0 && traversal) {
const step: string = steps.shift()!;
traversal = traversal._child(step);
}
return traversal;
}
// Handles one code unit at a time.
private _child(char: USVString): Traversal | undefined {
const root = this.root;
const totalWeight = this.totalWeight;
const nextPrefix = this.prefix + char;
if(root.type == 'internal') {
let childNode = root.children[char];
if(!childNode) {
return undefined;
}
return new Traversal(childNode, nextPrefix, totalWeight);
} else {
// root.type == 'leaf';
const legalChildren = root.entries.filter(function(entry) {
return entry.key.indexOf(nextPrefix) == 0;
});
if(!legalChildren.length) {
return undefined;
}
return new Traversal(root, nextPrefix, totalWeight);
}
}
*children(): Generator<{char: USVString, traversal: () => LexiconTraversal}> {
let root = this.root;
// We refer to the field multiple times in this method, and it doesn't change.
// This also assists minification a bit, since we can't minify when re-accessing
// through `this.`.
const totalWeight = this.totalWeight;
if(root.type == 'internal') {
for(let entry of root.values) {
let entryNode = root.children[entry];
@ -120,7 +171,7 @@ class Traversal implements LexiconTraversal {
let prefix = this.prefix + entry + lowSurrogate;
yield {
char: entry + lowSurrogate,
traversal: function() { return new Traversal(internalNode.children[lowSurrogate], prefix) }
traversal: function() { return new Traversal(internalNode.children[lowSurrogate], prefix, totalWeight) }
}
}
} else {
@ -131,7 +182,7 @@ class Traversal implements LexiconTraversal {
yield {
char: entry,
traversal: function () {return new Traversal(entryNode, prefix)}
traversal: function () {return new Traversal(entryNode, prefix, totalWeight)}
}
}
} else if(isSentinel(entry)) {
@ -143,7 +194,7 @@ class Traversal implements LexiconTraversal {
let prefix = this.prefix + entry;
yield {
char: entry,
traversal: function() { return new Traversal(entryNode, prefix)}
traversal: function() { return new Traversal(entryNode, prefix, totalWeight)}
}
}
}
@ -165,30 +216,41 @@ class Traversal implements LexiconTraversal {
}
yield {
char: nodeKey,
traversal: function() { return new Traversal(root, prefix + nodeKey)}
traversal: function() { return new Traversal(root, prefix + nodeKey, totalWeight)}
}
};
return;
}
}
get entries(): string[] {
get entries() {
const entryMapper = (value: Entry) => {
return {
text: value.content,
p: value.weight / this.totalWeight
}
}
if(this.root.type == 'leaf') {
let prefix = this.prefix;
let matches = this.root.entries.filter(function(entry) {
return entry.key == prefix;
});
return matches.map(function(value) { return value.content });
return matches.map(entryMapper);
} else {
let matchingLeaf = this.root.children[SENTINEL_CODE_UNIT];
if(matchingLeaf && matchingLeaf.type == 'leaf') {
return matchingLeaf.entries.map(function(value) { return value.content });
return matchingLeaf.entries.map(entryMapper);
} else {
return [];
}
}
}
get p(): number {
return this.root.weight / this.totalWeight;
}
}
/**
@ -286,7 +348,7 @@ export default class TrieModel implements LexicalModel {
}
public traverseFromRoot(): LexiconTraversal {
return new Traversal(this._trie['root'], '');
return this._trie.traverseFromRoot();
}
};
@ -307,11 +369,10 @@ export default class TrieModel implements LexicalModel {
type SearchKey = string & { _: 'SearchKey'};
/**
* The priority queue will always pop the most weighted item. There can only
* be two kinds of items right now: nodes, and entries; both having a weight
* attribute.
* The priority queue will always pop the most probable item - be it a Traversal
* state or a lexical entry reached via Traversal.
*/
type Weighted = Node | Entry;
type TraversableWithProb = TextWithProbability | LexiconTraversal;
/**
* A function that converts a string (word form or query) into a search key
@ -367,9 +428,9 @@ interface Entry {
* Wrapper class for the trie and its nodes.
*/
class Trie {
private root: Node;
public readonly root: Node;
/** The total weight of the entire trie. */
private totalWeight: number;
readonly totalWeight: number;
/**
* Converts arbitrary strings to a search key. The trie is built up of
* search keys; not each entry's word form!
@ -382,6 +443,10 @@ class Trie {
this.totalWeight = totalWeight;
}
public traverseFromRoot(): LexiconTraversal {
return new Traversal(this.root, '', this.totalWeight);
}
/**
* Lookups an arbitrary prefix (a query) in the trie. Returns the top 3
* results in sorted order.
@ -390,12 +455,8 @@ class Trie {
*/
lookup(prefix: string): TextWithProbability[] {
let searchKey = this.toKey(prefix);
let lowestCommonNode = findPrefix(this.root, searchKey);
if (lowestCommonNode === null) {
return [];
}
return getSortedResults(lowestCommonNode, searchKey, this.totalWeight);
let rootTraversal = this.traverseFromRoot().child(searchKey);
return rootTraversal ? getSortedResults(rootTraversal) : [];
}
/**
@ -403,36 +464,10 @@ class Trie {
* @param n How many suggestions, maximum, to return.
*/
firstN(n: number): TextWithProbability[] {
return getSortedResults(this.root, '' as SearchKey, this.totalWeight, n);
return getSortedResults(this.traverseFromRoot(), n);
}
}
/**
* Finds the deepest descendent in the trie with the given prefix key.
*
* This means that a search in the trie for a given prefix has a best-case
* complexity of O(m) where m is the length of the prefix.
*
* @param key The prefix to search for.
* @param index The index in the prefix. Initially 0.
*/
function findPrefix(node: Node, key: SearchKey, index: number = 0): Node | null {
// An important note - the Trie itself is built on a per-JS-character basis,
// not on a UTF-8 character-code basis.
if (node.type === 'leaf' || index === key.length) {
return node;
}
// So, for SMP models, we need to match each char of the supplementary pair
// in sequence. Each has its own node in the Trie.
let char = key[index];
if (node.children[char]) {
return findPrefix(node.children[char], key, index + 1);
}
return null;
}
/**
* Returns all entries matching the given prefix, in descending order of
* weight.
@ -441,72 +476,36 @@ function findPrefix(node: Node, key: SearchKey, index: number = 0): Node | null
* @param results the current results
* @param queue
*/
function getSortedResults(node: Node, prefix: SearchKey, N: number, limit = MAX_SUGGESTIONS): TextWithProbability[] {
let queue = new PriorityQueue(function(a: Weighted, b: Weighted) {
function getSortedResults(traversal: LexiconTraversal, limit = MAX_SUGGESTIONS): TextWithProbability[] {
let queue = new PriorityQueue(function(a: TraversableWithProb, b: TraversableWithProb) {
// In case of Trie compilation issues that emit `null` or `undefined`
return (b ? b.weight : 0) - (a ? a.weight : 0);
return (b ? b.p : 0) - (a ? a.p : 0);
});
let results: TextWithProbability[] = [];
if (node.type === 'leaf') {
// Assuming the values are sorted, we can just add all of the values in the
// leaf, until we reach the limit.
for (let item of node.entries) {
// String.startsWith is not supported on certain Android (5.0) devices we wish to support.
// Requires a minimum of Chrome 36, as opposed to 5.0's default of 35.
if (item.key.indexOf(prefix) == 0) {
let { content, weight } = item;
results.push({
text: content,
p: weight / N
});
queue.enqueue(traversal);
if (results.length >= limit) {
return results;
}
}
}
} else {
queue.enqueue(node);
let next: Weighted | undefined;
while(queue.count > 0) {
const entry = queue.dequeue();
while (next = queue.dequeue()) {
if (isNode(next)) {
// When a node is next up in the queue, that means that next least
// likely suggestion is among its decsendants.
// So we search all of its descendants!
if (next.type === 'leaf') {
queue.enqueueAll(next.entries);
} else {
// XXX: alias `next` so that TypeScript can be SURE that internal is
// in fact an internal node. Because of the callback binding to the
// original definition of node (i.e., a Node | Entry), this will not
// type-check otherwise.
let internal = next;
queue.enqueueAll(next.values.map(char => {
return internal.children[char];
}));
}
} else {
// When an entry is up next in the queue, we just add its contents to
// the results!
results.push({
text: next.content,
p: next.weight / N
});
if (results.length >= limit) {
return results;
}
if((entry as TextWithProbability)!.text !== undefined) {
const lexicalEntry = entry as TextWithProbability;
results.push(lexicalEntry);
if(results.length >= limit) {
return results;
}
} else {
const traversal = entry as LexiconTraversal;
queue.enqueueAll(traversal.entries);
let children: LexiconTraversal[] = []
for(let child of traversal.children()) {
children.push(child.traversal());
}
queue.enqueueAll(children);
}
}
return results;
}
/** TypeScript type guard that returns whether the thing is a Node. */
function isNode(x: Entry | Node): x is Node {
return 'type' in x;
}
/**

View file

@ -13,6 +13,12 @@ var smpForUnicode = function(code){
return String.fromCharCode(H, L);
}
// Prob: entry weight / total weight
// "the" is the highest-weighted word in the fixture.
const PROB_OF_THE = 1000 / 500500;
const PROB_OF_TRUE = 607 / 500500;
const PROB_OF_TROUBLE = 267 / 500500;
describe('Trie traversal abstractions', function() {
it('root-level iteration over child nodes', function() {
var model = new TrieModel(jsonFixture('tries/english-1000'));
@ -21,7 +27,11 @@ describe('Trie traversal abstractions', function() {
assert.isDefined(rootTraversal);
let rootKeys = ['t', 'o', 'a', 'i', 'w', 'h', 'f', 'b', 'n', 'y', 's', 'm',
'u', 'c', 'd', 'l', 'e', 'j', 'p', 'g', 'v', 'k', 'r', 'q']
'u', 'c', 'd', 'l', 'e', 'j', 'p', 'g', 'v', 'k', 'r', 'q'];
rootKeys.forEach((entry) => assert.isOk(rootTraversal.child(entry)));
assert.isNotOk(rootTraversal.child('x'));
assert.isNotOk(rootTraversal.child('z'));
for(let child of rootTraversal.children()) {
let keyIndex = rootKeys.indexOf(child.char);
@ -50,6 +60,7 @@ describe('Trie traversal abstractions', function() {
assert.isDefined(traversalInner1);
assert.isArray(child.traversal().entries);
assert.isEmpty(child.traversal().entries);
assert.equal(traversalInner1.p, PROB_OF_THE);
for(let tChild of traversalInner1.children()) {
if(tChild.char == 'h') {
@ -58,19 +69,28 @@ describe('Trie traversal abstractions', function() {
assert.isDefined(traversalInner2);
assert.isEmpty(tChild.traversal().entries);
assert.isArray(tChild.traversal().entries);
assert.equal(traversalInner2.p, PROB_OF_THE);
for(let hChild of traversalInner2.children()) {
if(hChild.char == 'e') {
eSuccess = true;
let traversalInner3 = hChild.traversal();
assert.isDefined(traversalInner3);
assert.isDefined(traversalInner3.entries);
assert.equal(traversalInner3.entries[0], "the");
assert.deepEqual(traversalInner3.entries, [
{
text: "the",
p: PROB_OF_THE
}
]);
assert.equal(traversalInner3.p, PROB_OF_THE);
for(let eChild of traversalInner3.children()) {
let keyIndex = eKeys.indexOf(eChild.char);
assert.notEqual(keyIndex, -1, "Did not find char '" + eChild.char + "' in array!");
// THE is not accessible if any of the sub-tries of our 'e' node (traversalInner3).
assert.isBelow(eChild.traversal().p, PROB_OF_THE);
eKeys.splice(keyIndex, 1);
}
}
@ -87,6 +107,38 @@ describe('Trie traversal abstractions', function() {
assert.isEmpty(eKeys);
});
it('direct traversal with simple internal nodes', function() {
var model = new TrieModel(jsonFixture('tries/english-1000'));
let rootTraversal = model.traverseFromRoot();
assert.isDefined(rootTraversal);
let eKeys = ['y', 'r', 'i', 'm', 's', 'n', 'o'];
const tNode = rootTraversal.child('t');
assert.isOk(tNode);
assert.isDefined(tNode);
assert.isArray(tNode.entries);
assert.isEmpty(tNode.entries);
const hNode = tNode.child('h');
assert.isOk(hNode);
assert.isDefined(hNode);
assert.isArray(hNode.entries);
assert.isEmpty(hNode.entries);
const eNode = hNode.child('e');
assert.isOk(eNode);
assert.isDefined(eNode);
assert.isArray(eNode.entries);
assert.isNotEmpty(eNode.entries);
assert.equal(eNode.entries[0].text, "the");
for(let key of eKeys) {
assert.isOk(eNode.child(key));
}
});
it('traversal over compact leaf node', function() {
var model = new TrieModel(jsonFixture('tries/english-1000'));
@ -102,6 +154,7 @@ describe('Trie traversal abstractions', function() {
assert.isDefined(traversalInner1);
assert.isArray(child.traversal().entries);
assert.isEmpty(child.traversal().entries);
assert.equal(traversalInner1.p, PROB_OF_THE);
for(let tChild of traversalInner1.children()) {
if(tChild.char == 'r') {
@ -109,6 +162,7 @@ describe('Trie traversal abstractions', function() {
assert.isDefined(traversalInner2);
assert.isArray(tChild.traversal().entries);
assert.isEmpty(tChild.traversal().entries);
assert.equal(traversalInner2.p, PROB_OF_TRUE);
for(let rChild of traversalInner2.children()) {
if(rChild.char == 'o') {
@ -137,10 +191,17 @@ describe('Trie traversal abstractions', function() {
if(leafChildSequence.length > 0) {
assert.isArray(curChild.traversal().entries);
assert.isEmpty(curChild.traversal().entries);
assert.equal(curChild.traversal().p, PROB_OF_TROUBLE);
} else {
let finalTraversal = curChild.traversal();
assert.equal(finalTraversal.p, PROB_OF_TROUBLE);
assert.isDefined(finalTraversal.entries);
assert.equal(finalTraversal.entries[0], 'trouble');
assert.deepEqual(finalTraversal.entries, [
{
text: 'trouble',
p: PROB_OF_TROUBLE
}
]);
eSuccess = true;
}
} while (leafChildSequence.length > 0);
@ -154,7 +215,6 @@ describe('Trie traversal abstractions', function() {
assert.isTrue(eSuccess);
});
it('traversal with SMP entries', function() {
// Two entries, both of which read "apple" to native English speakers.
// One solely uses SMP characters, the other of which uses a mix of SMP and standard.
@ -179,18 +239,20 @@ describe('Trie traversal abstractions', function() {
for(let child of rootTraversal.children()) {
if(child.char == smpA) {
aSuccess = true;
let traversalInner1 = child.traversal();
const traversalInner1 = child.traversal();
assert.isDefined(traversalInner1);
assert.isArray(child.traversal().entries);
assert.isEmpty(child.traversal().entries);
assert.isArray(traversalInner1.entries);
assert.isEmpty(traversalInner1.entries);
assert.equal(traversalInner1.p, 0.5); // The two entries are equally weighted.
for(let aChild of traversalInner1.children()) {
if(aChild.char == smpP) {
pSuccess = true;
let traversalInner2 = aChild.traversal();
const traversalInner2 = aChild.traversal();
assert.isDefined(traversalInner2);
assert.isArray(aChild.traversal().entries);
assert.isEmpty(aChild.traversal().entries);
assert.isArray(traversalInner2.entries);
assert.isEmpty(traversalInner2.entries);
assert.equal(traversalInner2.p, 0.5);
for(let pChild of traversalInner2.children()) {
let keyIndex = pKeys.indexOf(pChild.char);
@ -198,10 +260,11 @@ describe('Trie traversal abstractions', function() {
pKeys.splice(keyIndex, 1);
if(pChild.char == 'p') { // We'll test traversal with the 'mixed' entry from here.
let traversalInner3 = pChild.traversal();
const traversalInner3 = pChild.traversal();
assert.isDefined(traversalInner3);
assert.isArray(pChild.traversal().entries);
assert.isEmpty(pChild.traversal().entries);
assert.isArray(traversalInner3.entries);
assert.isEmpty(traversalInner3.entries);
assert.equal(traversalInner3.p, 0.5);
// Now to handle the rest, knowing it's backed by a leaf node.
let curChild = pChild;
@ -227,12 +290,20 @@ describe('Trie traversal abstractions', function() {
// Conditional test - if that was not the final character, entries should be undefined.
if(leafChildSequence.length > 0) {
assert.isArray(curChild.traversal().entries);
assert.isEmpty(curChild.traversal().entries);
const nextTraversal = curChild.traversal()
assert.isArray(nextTraversal.entries);
assert.isEmpty(nextTraversal.entries);
assert.equal(nextTraversal.p, 0.5);
} else {
let finalTraversal = curChild.traversal();
assert.isDefined(finalTraversal.entries);
assert.equal(finalTraversal.entries[0], smpA + smpP + 'pl' + smpE);
assert.deepEqual(finalTraversal.entries, [
{
text: smpA + smpP + 'pl' + smpE,
p: 1/2
}
]);
assert.equal(finalTraversal.p, 0.5);
eSuccess = true;
}
} while (leafChildSequence.length > 0);
@ -249,4 +320,52 @@ describe('Trie traversal abstractions', function() {
assert.isEmpty(pKeys);
});
it('direct traversal with SMP entries', function() {
// Two entries, both of which read "apple" to native English speakers.
// One solely uses SMP characters, the other of which uses a mix of SMP and standard.
var model = new TrieModel(jsonFixture('tries/smp-apple'));
let rootTraversal = model.traverseFromRoot();
assert.isDefined(rootTraversal);
let smpA = smpForUnicode(0x1d5ba);
let smpP = smpForUnicode(0x1d5c9);
let smpL = smpForUnicode(0x1d5c5);
let smpE = smpForUnicode(0x1d5be);
// Just to be sure our utility function is working right.
assert.equal(smpA + smpP + 'pl' + smpE, "𝖺𝗉pl𝖾");
let pKeys = ['p', smpP];
let leafChildSequence = ['l', smpE];
const aNode = rootTraversal.child(smpA);
assert.isOk(aNode);
assert.isNotOk(rootTraversal.child('a'));
const pNode1 = aNode.child(smpP);
assert.isOk(pNode1);
assert.isNotOk(aNode.child('p'));
const pNode2 = pNode1.child('p');
assert.isOk(pNode2);
assert.isOk(pNode1.child(smpP)); // Both exist for this step.
const lNode = pNode2.child('l');
assert.isOk(lNode);
assert.isNotOk(pNode2.child(smpL));
const eNode = lNode.child(smpE);
assert.isOk(eNode);
assert.isNotOk(lNode.child('e'));
assert.deepEqual(eNode.entries, [
{
text: smpA + smpP + 'pl' + smpE,
p: 1/2
}
]);
assert.equal(eNode.p, 0.5);
});
});

View file

@ -19,13 +19,32 @@ declare type USVString = string;
declare type CasingForm = 'lower' | 'initial' | 'upper';
/**
* Represents one lexical entry and its probability..
*/
type TextWithProbability = {
/**
* A lexical entry (word) offered by the model.
*
* Note: not the search-term keyed part. This will match the actual, unkeyed form.
*/
text: string;
/**
* The probability of the lexical entry, directly based upon its frequency.
*
* A real-number weight, from 0 to 1.
*/
p: number;
}
/**
* Used to facilitate edit-distance calculations by allowing the LMLayer to
* efficiently search the model's lexicon in a Trie-like manner.
*/
declare interface LexiconTraversal {
/**
* Provides an iterable pattern used to search for words with a prefix matching
* Provides an iterable pattern used to search for words with a 'keyed' prefix matching
* the current traversal state's prefix when a new character is appended. Iterating
* across `children` provides 'breadth' to a lexical search.
*
@ -50,6 +69,20 @@ declare interface LexiconTraversal {
*/
children(): Generator<{char: USVString, traversal: () => LexiconTraversal}>;
/**
* Allows direct access to the traversal state that results when appending one
* or more codepoints encoded in UTF-16 to the current traversal state's prefix.
* This allows bypassing iteration among all legal child Traversals.
*
* If such a traversal state is not supported, returns `undefined`.
*
* Note: traversals navigate and represent the lexicon in its "keyed" state,
* as produced by use of the search-term keying function defined for the model.
* That is, if a model "keys" `è` to `e`, there will be no `è` child.
* @param char
*/
child(char: USVString): LexiconTraversal | undefined;
/**
* Any entries directly keyed by the currently-represented lookup prefix. Entries and
* children may exist simultaneously, but `entries` must always exist when no children are
@ -70,7 +103,14 @@ declare interface LexiconTraversal {
* - prefix of 'crepe': ['crêpe', 'crêpé']
* - other examples: https://www.thoughtco.com/french-accent-homographs-1371072
*/
entries: USVString[];
entries: TextWithProbability[];
// Note: `p`, not `maxP` - we want to see the same name for `this.entries.p` and `this.p`
/**
* Gives the probability of the highest-frequency lexical entry that is either a member or
* descendent of the represented trie `Node`.
*/
p: number;
}
/**
@ -294,6 +334,11 @@ declare interface Suggestion {
* to the input text. Ex: 'keep', 'emoji', 'correction', etc.
*/
tag?: SuggestionTag;
/**
* Set to true if this suggestion is a valid auto-accept target.
*/
autoAccept?: boolean
}
interface Reversion extends Suggestion {

View file

@ -36,6 +36,18 @@ describe('LMLayer using dummy model', function () {
// Since Firefox can't do JSON imports quite yet.
const hazelFixture = await fetch(new URL(`${domain}/resources/json/models/future_suggestions/i_got_distracted_by_hazel.json`));
hazelModel = await hazelFixture.json();
hazelModel = hazelModel.map((set) => set.map((entry) => {
return {
...entry,
// Dummy-model predictions all claim probability 1; there's no actual probability stuff
// used here.
'lexical-p': 1,
// We're predicting from a single transform, not a distribution, so probability 1.
'correction-p': 1,
// Multiply 'em together.
p: 1,
}
}));
});
describe('Prediction', function () {

View file

@ -113,7 +113,18 @@ export function randomToken() {
}
export function iGotDistractedByHazel() {
return jsonFixture('models/future_suggestions/i_got_distracted_by_hazel');
return jsonFixture('models/future_suggestions/i_got_distracted_by_hazel').map((set) => set.map((entry) => {
return {
...entry,
// Dummy-model predictions all claim probability 1; there's no actual probability stuff
// used here.
'lexical-p': 1,
// We're predicting from a single transform, not a distribution, so probability 1.
'correction-p': 1,
// Multiply 'em together.
p: 1,
}
}));
}
export function jsonFixture(name, root, import_root) {

View file

@ -19,7 +19,7 @@ export type StateChangeHandler = (state: StateChangeEnum) => any;
/**
* Covers 'tryaccept' events.
*/
export type TryUIHandler = (source: string) => boolean;
export type TryUIHandler = (source: string, returnObj: {shouldSwallow: boolean}) => boolean;
export type InvalidateSourceEnum = 'new'|'context';
@ -168,9 +168,9 @@ export default class LanguageProcessor extends EventEmitter<LanguageProcessorEve
let transcription = outputTarget.buildTranscriptionFrom(outputTarget, null, false);
return this.predict_internal(transcription, true, layerId);
} else {
// if there's no active context source, there's nothing to
// provide suggestions for. In that case, there's no reason
// to even request suggestions, so bypass the prediction
// if there's no active context source, there's nothing to
// provide suggestions for. In that case, there's no reason
// to even request suggestions, so bypass the prediction
// engine and say that there aren't any.
return Promise.resolve([]);
}
@ -453,12 +453,13 @@ export default class LanguageProcessor extends EventEmitter<LanguageProcessorEve
}
public tryAcceptSuggestion(source: string): boolean {
// If and when we do auto-correct, the suggestion is to pass this object to the event and
// denote any mutations to the contained value.
//let returnObj = {shouldSwallow: false};
this.emit('tryaccept', source);
// The object below is to facilitate a pass-by-reference on the boolean flag,
// allowing the event's handler to signal if whitespace has been added via
// auto-applied suggestion that should be blocked on the next keystroke.
let returnObj = {shouldSwallow: false};
this.emit('tryaccept', source, returnObj);
return false;
return returnObj.shouldSwallow ?? false;
}
public tryRevertSuggestion(): boolean {

View file

@ -15,7 +15,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
// SuggestionBanner class. This class serves as the main implementation of the banner's core logic.
// Designed for use with auto-correct behavior
private selected: Suggestion;
selected: Suggestion;
private initNewContext: boolean = true;
@ -23,7 +23,8 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
private keepSuggestion: Keep;
private revertSuggestion: Reversion;
private recentAccept: boolean = false;
// Set to null/undefined if there was no recent acceptance.
private recentAcceptCause: 'key' | 'banner';
private revertAcceptancePromise: Promise<Reversion>;
private swallowPrediction: boolean = false;
@ -191,7 +192,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
// We get here either if suggestion acceptance fails or if it was a reversion.
if(suggestion && suggestion.tag == 'revert') {
// Reversion state management
this.recentAccept = false;
this.recentAcceptCause = null;
this.recentRevert = true;
}
@ -205,7 +206,9 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
}
});
this.recentAccept = true;
// By default, we assume we were triggered by the banner.
// Acceptance by keystroke will overwrite this later (in `tryAccept`)
this.recentAcceptCause = 'banner';
this.recentRevert = false;
this.swallowPrediction = true;
@ -224,19 +227,34 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
* Should return 'false' if the current state allows accepting a suggestion and act accordingly.
* Otherwise, return true.
*/
private doTryAccept = (source: string /*, returnObj: {shouldSwallow: boolean}*/): void => {
//let keyman = com.keyman.singleton;
private doTryAccept = (source: string, returnObj: {shouldSwallow: boolean}): void => {
const recentAcceptCause = this.recentAcceptCause;
if(!this.recentAccept && this.selected) {
if(!recentAcceptCause && this.selected) {
this.accept(this.selected);
// returnObj.shouldSwallow = true;
} else if(this.recentAccept && source == 'space') {
this.recentAccept = false;
// // If the model doesn't insert wordbreaks, don't swallow the space. If it does,
// // we consider that insertion to be the results of the first post-accept space.
// returnObj.shouldSwallow = !!keyman.core.languageProcessor.wordbreaksAfterSuggestions; // can be handed outside
returnObj.shouldSwallow = true;
// doTryAccept is the path for keystroke-based auto-acceptance.
// Overwrite the cause to reflect this.
this.recentAcceptCause = 'key';
} else if(recentAcceptCause && source == 'space') {
this.recentAcceptCause = null;
if(recentAcceptCause == 'key') {
// No need to swallow the keystroke's whitespace; we triggered the prior acceptance
// FROM a space, so we've already aliased the suggestion's built-in space.
returnObj.shouldSwallow = false;
return;
}
// Standard whitespace applications from the banner, those we DO want to
// swallow the first time.
//
// If the model doesn't insert wordbreaks, there's no space to alias, so
// don't swallow the space. If it does, we consider that insertion to be
// the results of the first post-accept space.
returnObj.shouldSwallow = !!this.langProcessor.wordbreaksAfterSuggestions; // can be handed outside
} else {
// returnObj.shouldSwallow = false;
returnObj.shouldSwallow = false;
}
}
@ -250,9 +268,9 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
if(this.doRevert) {
// If so, clear the 'revert' option and start doing normal predictions again.
this.doRevert = false;
this.recentAccept = false;
this.recentAcceptCause = null;
// Otherwise, did we just accept something before the revert signal was received?
} else if(this.recentAccept) {
} else if(this.recentAcceptCause) {
this.showRevert();
this.swallowPrediction = true;
}
@ -270,9 +288,10 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
private invalidateSuggestions = (source: InvalidateSourceEnum): void => {
// By default, we assume that the context is the same until we notice otherwise.
this.initNewContext = false;
this.selected = null;
if(!this.swallowPrediction || source == 'context') {
this.recentAccept = false;
this.recentAcceptCause = null;
this.doRevert = false;
this.recentRevert = false;
@ -299,7 +318,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
}
private activateKeep(): boolean {
return !this.recentAccept && !this.recentRevert && !this.initNewContext;
return !this.recentAcceptCause && !this.recentRevert && !this.initNewContext;
}
/**
@ -312,6 +331,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
let suggestions = prediction.suggestions;
this._currentSuggestions = suggestions;
this.selected = null;
// Do we have a keep suggestion? If so, remove it from the list so that we can control its display position
// and prevent it from being hidden after reversion operations.
@ -320,6 +340,10 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
if(s.tag == 'keep') {
this.keepSuggestion = s as Keep;
}
if(s.autoAccept && !this.selected) {
this.selected = s;
}
}
if(this.keepSuggestion) {
@ -328,7 +352,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
// If we've gotten an update request like this, it's almost always user-triggered and means the context has shifted.
if(!this.swallowPrediction) {
this.recentAccept = false;
this.recentAcceptCause = null;
this.doRevert = false;
this.recentRevert = false;
} else { // This prediction was triggered by a recent 'accept.' Now that it's fulfilled, we clear the flag.

View file

@ -1,4 +1,5 @@
import { Comparator, isHighSurrogate, SENTINEL_CODE_UNIT, PriorityQueue } from '@keymanapp/models-templates';
import { isHighSurrogate, SENTINEL_CODE_UNIT } from '@keymanapp/models-templates';
import { QueueComparator as Comparator, PriorityQueue } from '@keymanapp/web-utils';
import { ClassicalDistanceCalculation, EditToken } from './classical-calculation.js';
import { ExecutionTimer, STANDARD_TIME_BETWEEN_DEFERS } from './execution-timer.js';

View file

@ -4,6 +4,12 @@ import * as correction from './correction/index.js'
import TransformUtils from './transformUtils.js';
type CorrectionPredictionTuple = {
prediction: ProbabilityMass<Suggestion>,
correction: ProbabilityMass<string>,
totalProb: number;
};
export default class ModelCompositor {
private lexicalModel: LexicalModel;
private contextTracker?: correction.ContextTracker;
@ -39,9 +45,13 @@ export default class ModelCompositor {
private SUGGESTION_ID_SEED = 0;
private testMode: boolean = false
private testMode: boolean = false;
private verbose: boolean = true;
constructor(lexicalModel: LexicalModel, testMode?: boolean) {
constructor(
lexicalModel: LexicalModel,
testMode?: boolean
) {
this.lexicalModel = lexicalModel;
if(lexicalModel.traverseFromRoot) {
this.contextTracker = new correction.ContextTracker();
@ -50,23 +60,31 @@ export default class ModelCompositor {
this.testMode = !!testMode;
}
private predictFromCorrections(corrections: ProbabilityMass<Transform>[], context: Context): Distribution<Suggestion> {
let returnedPredictions: Distribution<Suggestion> = [];
private predictFromCorrections(corrections: ProbabilityMass<Transform>[], context: Context): CorrectionPredictionTuple[] {
let returnedPredictions: CorrectionPredictionTuple[] = [];
for(let correction of corrections) {
let predictions = this.lexicalModel.predict(correction.sample, context);
let predictionSet = predictions.map(function(pair: ProbabilityMass<Suggestion>) {
let transform = correction.sample;
let inputProb = correction.p;
const { sample: correctionTransform, p: correctionProb } = correction;
const correctionRoot = this.wordbreak(models.applyTransform(correction.sample, context));
let predictionSet = predictions.map((pair: ProbabilityMass<Suggestion>) => {
// Let's not rely on the model to copy transform IDs.
// Only bother is there IS an ID to copy.
if(transform.id !== undefined) {
pair.sample.transformId = transform.id;
if(correctionTransform.id !== undefined) {
pair.sample.transformId = correctionTransform.id;
}
let prediction = {sample: pair.sample, p: pair.p * inputProb};
return prediction;
let tuple: CorrectionPredictionTuple = {
prediction: pair,
correction: {
sample: correctionRoot,
p: correctionProb
},
totalProb: pair.p * correctionProb
};
return tuple;
}, this);
returnedPredictions = returnedPredictions.concat(predictionSet);
@ -76,7 +94,7 @@ export default class ModelCompositor {
}
async predict(transformDistribution: Transform | Distribution<Transform>, context: Context): Promise<Suggestion[]> {
let suggestionDistribution: Distribution<Suggestion> = [];
let suggestionDistribution: CorrectionPredictionTuple[] = [];
let lexicalModel = this.lexicalModel;
let punctuation = this.punctuation;
@ -119,7 +137,7 @@ export default class ModelCompositor {
let keepOptionText = this.wordbreak(postContext);
let keepOption: Outcome<Keep> = null;
let rawPredictions: Distribution<Suggestion> = [];
let rawPredictions: CorrectionPredictionTuple[] = [];
// Used to restore whitespaces if operations would remove them.
let prefixTransform: Transform;
@ -318,10 +336,10 @@ export default class ModelCompositor {
// If we're getting the same prediction again, it's lower-cost. Update!
let oldPredictionSet = correctionPredictionMap[match.matchString];
if(oldPredictionSet) {
rawPredictions = rawPredictions.filter((entry) => !oldPredictionSet.find((match) => entry == match))
rawPredictions = rawPredictions.filter((entry) => !oldPredictionSet.find((match) => entry.prediction.sample == match.sample));
}
correctionPredictionMap[match.matchString] = predictions;
correctionPredictionMap[match.matchString] = predictions.map((entry) => entry.prediction);
rawPredictions = rawPredictions.concat(predictions);
@ -337,13 +355,13 @@ export default class ModelCompositor {
} else {
// Sort the prediction list; we need them in descending order for the next check.
rawPredictions.sort(function(a, b) {
return b.p - a.p;
return b.totalProb - a.totalProb;
});
// If the best suggestion from the search's current tier fails to beat the worst
// pending suggestion from previous tiers, assume all further corrections will
// similarly fail to win; terminate the search-loop.
if(rawPredictions[ModelCompositor.MAX_SUGGESTIONS-1].p > Math.exp(-correctionCost)) {
if(rawPredictions[ModelCompositor.MAX_SUGGESTIONS-1].totalProb > Math.exp(-correctionCost)) {
break;
}
}
@ -361,7 +379,7 @@ export default class ModelCompositor {
// Section 2 - post-analysis for our generated predictions, managing 'keep'.
// Assumption: Duplicated 'displayAs' properties indicate duplicated Suggestions.
// When true, we can use an 'associative array' to de-duplicate everything.
let suggestionDistribMap: {[key: string]: ProbabilityMass<Suggestion>} = {};
let suggestionDistribMap: {[key: string]: CorrectionPredictionTuple} = {};
let currentCasing: CasingForm = null;
if(lexicalModel.languageUsesCasing) {
currentCasing = this.detectCurrentCasing(postContext);
@ -370,9 +388,12 @@ export default class ModelCompositor {
let baseWord = this.wordbreak(context);
// Deduplicator + annotator of 'keep' suggestions.
for(let prediction of rawPredictions) {
for(let tuple of rawPredictions) {
const prediction = tuple.prediction.sample;
const prob = tuple.totalProb;
// Combine duplicate samples.
let displayText = prediction.sample.displayAs;
let displayText = prediction.displayAs;
let preserveAsKeep = displayText == keepOptionText;
// De-duplication should be case-insensitive, but NOT
@ -384,7 +405,7 @@ export default class ModelCompositor {
if(preserveAsKeep) {
// Preserve the original, pre-keyed version of the text.
if(!keepOption) {
let baseTransform = prediction.sample.transform;
let baseTransform = prediction.transform;
let keepTransform = {
insert: keepOptionText,
@ -393,15 +414,15 @@ export default class ModelCompositor {
id: baseTransform.id
}
let intermediateKeep = models.transformToSuggestion(keepTransform, prediction.p);
let intermediateKeep = models.transformToSuggestion(keepTransform, prob);
keepOption = this.toAnnotatedSuggestion(intermediateKeep, 'keep', models.QuoteBehavior.noQuotes);
keepOption.matchesModel = true;
// Since we replaced the original Suggestion with a keep-annotated one,
// we must manually preserve the transform ID.
keepOption.transformId = prediction.sample.transformId;
} else if(keepOption.p && prediction.p) {
keepOption.p += prediction.p;
keepOption.transformId = prediction.transformId;
} else if(keepOption.p && prob) {
keepOption.p += prob;
}
} else {
// Apply capitalization rules now; facilitates de-duplication of suggestions
@ -409,16 +430,16 @@ export default class ModelCompositor {
//
// Example: "apple" and "Apple" are separate when 'lower', but identical for 'initial' and 'upper'.
if(currentCasing && currentCasing != 'lower') {
this.applySuggestionCasing(prediction.sample, baseWord, currentCasing);
this.applySuggestionCasing(prediction, baseWord, currentCasing);
// update the mapping string, too.
displayText = prediction.sample.displayAs;
displayText = prediction.displayAs;
}
let existingSuggestion = suggestionDistribMap[displayText];
if(existingSuggestion) {
existingSuggestion.p += prediction.p;
existingSuggestion.totalProb += prob;
} else {
suggestionDistribMap[displayText] = prediction;
suggestionDistribMap[displayText] = tuple;
}
}
}
@ -448,28 +469,41 @@ export default class ModelCompositor {
}
suggestionDistribution = suggestionDistribution.sort(function(a, b) {
return b.p - a.p; // Use descending order - we want the largest probabilty suggestions first!
return b.totalProb - a.totalProb; // Use descending order - we want the largest probabilty suggestions first!
});
let suggestions = suggestionDistribution.splice(0, ModelCompositor.MAX_SUGGESTIONS).map(function(value) {
let sample: Suggestion & {
p?: number,
"lexical-p"?: number,
"correction-p"?: number
} = value.sample;
// Section 4: Auto-correction + finalization.
if(keepOption && keepOption.matchesModel) {
// Auto-select it for auto-acceptance; we don't correct away from perfectly-valid
// lexical entries, even if they are comparatively low-frequency.
keepOption.autoAccept = true;
} else {
this.predictionAutoSelect(suggestionDistribution);
}
if(sample['p']) {
// For analysis / debugging
sample['lexical-p'] = sample['p'];
sample['correction-p'] = value.p / sample['p'];
// Use of the Trie model always exposed the lexical model's probability for a word to KMW.
// It's useful for debugging right now, so may as well repurpose it as the posterior.
//
// We still condition on 'p' existing so that test cases aren't broken.
sample['p'] = value.p;
// Now that we've marked the suggestion to auto-select, we can finalize the suggestions.
let suggestions = suggestionDistribution.splice(0, ModelCompositor.MAX_SUGGESTIONS).map((tuple) => {
const prediction = tuple.prediction;
if(!this.verbose) {
return {
...prediction.sample,
p: tuple.totalProb
};
} else {
const sample: Suggestion & {
p?: number,
"lexical-p"?: number,
"correction-p"?: number
} = {
...prediction.sample,
p: tuple.totalProb,
"lexical-p": prediction.p,
"correction-p": tuple.correction.p
}
return sample;
}
//
return sample;
});
if(keepOption) {
@ -534,6 +568,53 @@ export default class ModelCompositor {
return suggestions;
}
private predictionAutoSelect(suggestionDistribution: CorrectionPredictionTuple[]) {
if(suggestionDistribution.length == 0) {
return;
}
if(suggestionDistribution.length == 1) {
// Mark for auto-acceptance; there are no alternatives.
suggestionDistribution[0].prediction.sample.autoAccept = true;
return;
}
// Is it reasonable to auto-accept any of our suggestions?
const bestSuggestion = suggestionDistribution[0];
const baseCorrection = bestSuggestion.correction.sample;
if(baseCorrection.length == 0) {
// If the correction is rooted on an empty root, there's no basis for
// auto-correcting to this suggestion.
return;
}
// Find the highest probability for any correction that led to a valid prediction.
// No need to full-on re-sort everything, though.
const bestCorrection = suggestionDistribution.reduce((prev, current) => prev?.correction.p > current.correction.p ? prev : current, null).correction;
if(bestCorrection.p > bestSuggestion.correction.p) {
// Here, the best suggestion didn't come from the best correction.
// Is it actually reasonable to auto-correct? We're probably just very
// biased toward its frequency. (Maybe a threshold should be considered?)
return;
}
// compare best vs other probabilities.
const probSum = suggestionDistribution.reduce((accum, current) => accum + current.totalProb, 0);
const proportionOfBest = bestSuggestion.totalProb / probSum;
if(proportionOfBest < .66) {
return;
}
// compare correction-cost aspects? We disable if the base correction is lower than best,
// but should we do other comparisons too?
// const nextSuggestion = suggestionDistribution[1];
// baseCorrection
bestSuggestion.prediction.sample.autoAccept = true;
}
// Responsible for applying casing rules to suggestions.
private applySuggestionCasing(suggestion: Suggestion, baseWord: USVString, casingForm: CasingForm) {
// Step 1: does the suggestion replace the whole word? If not, we should extend the suggestion to do so.

View file

@ -2,6 +2,7 @@ import { assert } from 'chai';
import * as models from '#./models/index.js';
import * as correction from '#./correction/index.js';
import { PriorityQueue } from '@keymanapp/web-utils';
import { jsonFixture } from '@keymanapp/common-test-resources/model-helpers.mjs';
function buildTestTimer() {
@ -142,7 +143,7 @@ describe('Correction Distance Modeler', function() {
assert.equal(edges.length, expectedChildCount);
// One final bit, which is a bit of integration - we know the top two nodes that should result.
let queue = new models.PriorityQueue(correction.QUEUE_NODE_COMPARATOR, edges);
let queue = new PriorityQueue(correction.QUEUE_NODE_COMPARATOR, edges);
let firstEdge = queue.dequeue();
assert.equal(firstEdge.priorInput[0].sample.insert, 't');
@ -185,13 +186,13 @@ describe('Correction Distance Modeler', function() {
];
let layer1Edges = rootNode.buildSubstitutionEdges(synthDistribution1);
let layer1Queue = new models.PriorityQueue(correction.QUEUE_NODE_COMPARATOR, layer1Edges);
let layer1Queue = new PriorityQueue(correction.QUEUE_NODE_COMPARATOR, layer1Edges);
let tEdge = layer1Queue.dequeue();
assertEdgeChars(tEdge, 't', 't');
let layer2Edges = tEdge.buildSubstitutionEdges(synthDistribution2);
let layer2Queue = new models.PriorityQueue(correction.QUEUE_NODE_COMPARATOR, layer2Edges);
let layer2Queue = new PriorityQueue(correction.QUEUE_NODE_COMPARATOR, layer2Edges);
let eEdge = layer2Queue.dequeue();
assertEdgeChars(eEdge, 'e', 'e');
@ -208,7 +209,7 @@ describe('Correction Distance Modeler', function() {
let layer3eEdges = eEdge.buildSubstitutionEdges(synthDistribution3);
let layer3hEdges = hEdge.buildSubstitutionEdges(synthDistribution3);
let layer3ehEdges = ehEdge.buildSubstitutionEdges(synthDistribution3);
let layer3Queue = new models.PriorityQueue(correction.QUEUE_NODE_COMPARATOR, layer3eEdges.concat(layer3hEdges).concat(layer3ehEdges));
let layer3Queue = new PriorityQueue(correction.QUEUE_NODE_COMPARATOR, layer3eEdges.concat(layer3hEdges).concat(layer3ehEdges));
// Find the first result with an actual word directly represented.
let bestEdge;

View file

@ -23,6 +23,8 @@ export { default as TimeoutPromise, timedPromise } from "./timeoutPromise.js";
export { Uni_IsSurrogate1, Uni_IsSurrogate2 } from "./surrogates.js";
export { default as PriorityQueue, QueueComparator } from "./priority-queue.js"
// // Uncomment the following line and run the bundled output to verify successful
// // esbuild bundling of this submodule:
// console.log(Version.CURRENT.toString());

View file

@ -11,11 +11,11 @@
* - value > 0 if `b` should come before `a`
* - 0 if they should be treated equally.
*/
export type Comparator<Type> = (a: Type, b: Type) => number;
export type QueueComparator<Type> = (a: Type, b: Type) => number;
export default class PriorityQueue<Type> {
private comparator: Comparator<Type>;
private comparator: QueueComparator<Type>;
private heap: Type[];
/**
@ -29,8 +29,8 @@ export default class PriorityQueue<Type> {
* the first parameter should precede the second parameter.
* @param initialEntries
*/
constructor(comparator: Comparator<Type>, initialEntries?: Type[]);
constructor(arg1: Comparator<Type> | PriorityQueue<Type>, initialEntries?: Type[]) {
constructor(comparator: QueueComparator<Type>, initialEntries?: Type[]);
constructor(arg1: QueueComparator<Type> | PriorityQueue<Type>, initialEntries?: Type[]) {
if(typeof arg1 != 'function') {
this.comparator = arg1.comparator;
// Shallow-copies are fine.

View file

@ -3,7 +3,7 @@
*/
import { assert } from 'chai';
import { PriorityQueue } from '@keymanapp/models-templates';
import { PriorityQueue } from '@keymanapp/web-utils';
describe('Priority queue', function() {
it('can act as a min-heap', function () {

View file

@ -18,7 +18,7 @@ builder_describe "Keyman common Windows modules" \
builder_parse "$@"
if [[ $BUILDER_OS != windows ]]; then
if [[ $BUILDER_OS != win ]]; then
builder_echo grey "Platform is not Windows; skipping common/windows"
exit 0
fi

View file

@ -1,3 +1,4 @@
#include <cstdint>
#include <test_assert.h>
#include "kmx/kmx_plus.h"
#include "kmx/kmx_xstring.h"

View file

@ -34,6 +34,7 @@ files:
languages_mapping:
# Prevent invalid region pap-rPAP. Leaving "in" for Indonesian
android_code:
el-polyton: b+el # TODO: figure out polyton variant
es-419: b+es+419
pap: pap
shu-latn-n: b+shu+latn
@ -44,6 +45,7 @@ files:
languages_mapping:
# Prevent invalid region pap-rPAP
android_code:
el-polyton: b+el # TODO: figure out polyton variant
es-419: b+es+419
pap: pap
shu-latn-n: b+shu+latn
@ -79,6 +81,7 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /ios/engine/KMEI/KeymanEngine/en.lproj/Localizable.strings
dest: /ios/engine/Localizable.strings
@ -86,6 +89,7 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /ios/engine/KMEI/KeymanEngine/en.lproj/Localizable.stringsdict
dest: /ios/engine/Localizable.stringsdict
@ -93,6 +97,7 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
- source: /ios/keyman/Keyman/Keyman/en.lproj/Localizable.strings
dest: /ios/app/Localizable.strings
@ -100,6 +105,7 @@ files:
languages_mapping:
osx_code:
pt-PT: pt-PT.lproj
el-polyton: el.lproj
# Linux files
@ -136,7 +142,7 @@ files:
osx_code:
pt-PT: pt-PT.lproj
- source: /mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/en.lproj/KMKeyboardHelpWindowController.strings
- source: /mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/en.lproj/KMKeyboardHelpWindowController.strings
dest: /mac/app/KMKeyboardHelpWindowController.strings
translation: /mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/%osx_code%/%original_file_name%
languages_mapping:

View file

@ -493,6 +493,9 @@
CEA9670A24BEC8030035AACF /* EngineStateBundler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EngineStateBundler.swift; sourceTree = "<group>"; };
CEA9670C24BEEFF80035AACF /* khmer_angkor update-base.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = "khmer_angkor update-base.bundle"; sourceTree = "<group>"; };
CEA9670E24BEF05A0035AACF /* Updates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updates.swift; sourceTree = "<group>"; };
CEAC2A222C2A503600C99ABD /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/ResourceInfoView.strings; sourceTree = "<group>"; };
CEAC2A232C2A505700C99ABD /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = el; path = el.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
CEAC2A242C2A508000C99ABD /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
CEACC90125F07C81006EAB45 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/ResourceInfoView.strings; sourceTree = "<group>"; };
CEACC90325F07CAF006EAB45 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
CEACC90425F07CB6006EAB45 /* km */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = km; path = km.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -1205,6 +1208,7 @@
uk,
ru,
es,
el,
);
mainGroup = F243887314BBD43000A3E055;
productRefGroup = F243887F14BBD43000A3E055 /* Products */;
@ -1602,6 +1606,7 @@
298566D32980D39F004ACA95 /* uk */,
298566DF2980E48C004ACA95 /* ru */,
CEFFECD72A417F2E00D58C36 /* es */,
CEAC2A232C2A505700C99ABD /* el */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
@ -1630,6 +1635,7 @@
298566D22980D39A004ACA95 /* uk */,
298566DE2980E486004ACA95 /* ru */,
CEFFECD62A417F2900D58C36 /* es */,
CEAC2A242C2A508000C99ABD /* el */,
);
name = Localizable.strings;
sourceTree = "<group>";
@ -1659,6 +1665,7 @@
298566D12980D390004ACA95 /* uk */,
298566DD2980E477004ACA95 /* ru */,
CEFFECD52A417F1300D58C36 /* es */,
CEAC2A222C2A503600C99ABD /* el */,
);
name = ResourceInfoView.xib;
sourceTree = "<group>";

View file

@ -0,0 +1,2 @@
/* Class = "UILabel"; text = "Scan this code to load this keyboard on another device"; ObjectID = "z2O-MT-IoV"; */
"z2O-MT-IoV.text" = "Σαρῶστε αὐτὸν τὸν κωδικό γιὰ νὰ φορτώσετε αὐτὸ τὸ πληκτρολόγιο σὲ ἄλλη συσκευή";

View file

@ -0,0 +1,257 @@
/* A descriptive message used for errors when the app is already busy downloading */
"alert-download-error-busy" = "Λήψη ἤδη σὲ ἐξέλιξη.";
/* A descriptive message used when a download fails */
"alert-download-error-detail" = "Παρουσιάσθηκε σφάλμα κατὰ τὴν λήψη ἢ ἐγκατάσταση.";
/* Title for a "download failed" alert */
"alert-download-error-title" = "Σφάλμα κατὰ τὴν λήψη";
/* Title for a general alert about errors */
"alert-error-title" = "Σφάλμα";
/* A descriptive message used when no internet connection is detected */
"alert-no-connection-detail" = "Ἀδυναμία προσβάσεως στὸν διακομιστὴ Κῆμαν. Παρακαλοῦμε ξαναδοκιμάστε ἀργότερα.";
/* Title for a "no connection" alert */
"alert-no-connection-title" = "Σφάλμα συνδέσεως";
/* Short text for a 'back' navigational command. Used to return to the previous screen */
"command-back" = "Πίσω";
/* Short text for a 'cancel' command. Used to back out of a menu or install process without making changes */
"command-cancel" = "Ἀκυρῶστε";
/* Short text for a 'done' command. Used to back out of settings menus after changes have been made */
"command-done" = "Ἕτοιμοι";
/* Short text for an 'install' command. Used to confirm installation of a package. */
"command-install" = "Ἐγκαταστῆστε";
/* Short text for a 'next' navigational command. Used to advance to the next screen */
"command-next" = "Ἑπόμενο";
/* Short text for an 'OK' command. Used for some error alerts */
"command-ok" = "OK";
/* Short text for confirmining 'uninstall' commands. */
"command-uninstall" = "Ἀπεγκαταστῆστε";
/* Text for the command to uninstall a keyboard */
"command-uninstall-keyboard" = "Ἀπεγκαταστῆστε πληκτρολόγιο";
/* Confirmation text to display before uninstalling a keyboard */
"command-uninstall-keyboard-confirm" = "Θὰ θέλατε νὰ ἀπεγκαταστήσετε αὐτὸ τὸ πληκτρολόγιο;";
/* Text for the command to uninstall a lexical model */
"command-uninstall-lexical-model" = "Ἀπεγκαταστῆτε λεξικό";
/* Confirmation text to display before uninstalling a lexical model */
"command-uninstall-lexical-model-confirm" = "Θὰ θέλατε νὰ ἀπεγκαταστήσετε αὐτὸ τὸ λεξικό;";
/* Text for error when a keyboard cannot load properly */
"error-loading-keyboard" = "Ἀδυνατοῦμε νὰ φορτώσομε τὸ πληκτρολόγιο ποὺ ζητήσατε";
/* Text for error when a lexical model cannot load properly */
"error-loading-lexical-model" = "Ἀδυνατοῦμε νὰ φορτώσομε τὸ λεξικὸ ποὺ ζητήσατε";
/* Text for error when an installed file is unexpectedly missing */
"error-missing-file" = "Δὲν βρέθηκε κάποιο ἀπαραίτητο ἀρχεῖο.";
/* Text for error when an installed file is unexpectedly missing */
"error-missing-file-critical" = "Κάποιο σημαντικὸ ἀρχεῖο δὲν εὑρέθη. Παρακαλοῦμε προσπαθῆστε νὰ ἐγκαταστήσετε ἐκ νέου τὴν ἐφαρμογή.";
/* Text for errors in data received from search queries */
"error-query-decoding" = "Αὐτὴν τὴν στιγμὴ ὑπάρχουν τεχνικὰ προβλήματα στὸν διακομιστή";
/* A descriptive message used when a download fails */
"error-query-general" = "Σημειώθηκε σφάλμα κατὰ τὴν ἐπικοινωνία μὲ τὸν διακομιστή";
/* Text for error when a search query is unexpectedly empty */
"error-query-no-data" = "Ὁ διακομιστὴς δὲν ἀποκρίθηκε";
/* Text for general errors where not much information is known */
"error-unknown" = "Σημειώθηκε ἀπροσδόκητο σφάλμα";
/* Text for error when updating a resource: cannot download because no source is available */
"error-update-no-link" = "Δὲν ὑπάρχει πηγαῖος κώδικας πρὸς ἐνημέρωσιν αὐτοῦ τοῦ πακέτου";
/* Text for error when updating a resource: Keyman does not know how to update the resource */
"error-update-not-managed" = "Ἀδυνατοῦμε νὰ ἐνημερώσομε πόρο μὴ διαχειριζόμενο ἀπὸ τὴν μηχανὴ Κῆμαν";
/* Text for the command to open the help page of a keyboard, as shown on resource information views */
"info-command-help-keyboard" = "Βοήθεια γιὰ τὸ πληκτρολόγιο";
/* Text for the command to open the help page of a lexical model, as shown on resource information views */
"info-command-help-lexical-model" = "Βοήθεια γιὰ τὸ λεξικό";
/* Text label for displaying a keyboard's version, as shown on resource information views */
"info-label-version-keyboard" = "Ἔκδοση πληκτρολογίου";
/* Text label for displaying a lexical model's version, as shown on resource information views */
"info-label-version-lexical-model" = "Ἔκδοση λεξικοῦ";
/* Label used for the "package info" / readme tab with the package installation prompt on phones. */
"installer-label-package-info" = "Πληροφορίες πακέτου";
/* Label used for the language-selection tab with the package installation prompt on phones. */
"installer-label-select-languages" = "Ἐπιλέξτε γλῶσσα(-ες)";
/* Label used with a package's version, as seen within the package installation prompt. Example: "Version: 14.0.0" */
"installer-label-version" = "Ἔκδοση: %@";
/* Section header for languages supported by a package, as seen within the package installation prompt */
"installer-section-available-languages" = "Διαθέσιμες γλῶσσες";
/* Text for the help popup for changing keyboards with the globe key */
"keyboard-help-change" = "Κτυπῆστε ἐδῶ γιὰ νὰ ἀλλάξετε πληκτρολόγιο";
/* Text for the command to exit the Keyman keyboard in favor of other keyboards installed on the system */
"keyboard-menu-exit" = "Κλεῖστε τὸ %@";
/* Error installing a Keyman package - could not allocate a location to install it */
"kmp-error-file-system" = "Σφάλμα κατά τὴν ἐγκατάσταση πακέτου - σφάλμα συστήματος ἀρχείων";
/* Error installing a Keyman package - could not copy package files */
"kmp-error-file-copying" = "Σφάλμα κατά τὴν ἐγκατάσταση πακέτου - ἀδυναμία ἀντιγραφῆς ἀπαραιτήτων ἀρχείων";
/* Error opening a Keyman package - package is not valid */
"kmp-error-invalid" = "Κατεστραμμένο ἀρχεῖο πακέτου.";
/* Error opening a Keyman package - it does not exist / the specified location is wrong */
"kmp-error-missing" = "Τὸ πακέτο ποὺ ὁρίσατε δὲν ὑπάρχει.";
/* Error installing a Keyman package - expected resource (keyboard or dictionary) is missing */
"kmp-error-missing-resource" = "Αὐτὸ τὸ πακέτο δὲν περιέχει τὸ πληκτρολόγιο ἢ λεξικὸ ποὺ ζητήσατε.";
/* Error installing a Keyman package with a version of Keyman that does not support it */
"kmp-error-unsupported-keyman-version" = "Αὐτὸ τὸ πακέτο ἀπαιτεῖ νεώτερη ἔκδοση τοῦ Κῆμαν.";
/* Error opening a Keyman package - cannot parse contents */
"kmp-error-no-metadata" = "Αὐτὸ τὸ πακέτο δὲν ἔχει κατασκευασθεῖ σωστά - ὑπάρχουν ἄγνωστα περιεχόμενα.";
/* Error opening a Keyman package - package's contents are for desktop platforms only */
"kmp-error-unsupported" = "Αὐτὸ τὸ πακέτο δὲν συμπεριλαμβάνει ὑποστήριξη γιὰ τὴν συσκευή σας.";
/* Error opening a Keyman package - package contains unexpected resource (keyboard or dictionary) type */
"kmp-error-wrong-type" = "Αὐτὸ τὸ πακέτο δὲν περιέχει τὸν ἀναμενόμενο τύπο πόρου.";
/* Title for the Installed Languages menu */
"menu-installed-languages-title" = "Ἐγκατεστημένες γλῶσσες";
/* Section header for lexical models within a language-specific settings menu */
"menu-langsettings-label-lexical-models" = "Λεξικά";
/* Section header for keyboards within a language-specific settings menu */
"menu-langsettings-section-keyboards" = "Πληκτρολόγια";
/* Section header for the settings toggles within a language-specific settings menu */
"menu-langsettings-section-settings" = "Ρυθμίσεις γλώσσας";
/* Title for the language-specific settings menus */
"menu-langsettings-title" = "Ρυθμίσεις %@";
/* Label for the toggle that enables corrections that is displayed within a language-specific settings menu */
"menu-langsettings-toggle-correct" = "Ἐνεργοποιῆστε τὶς διορθώσεις";
/* Label for the toggle that enables predictions that is displayed within a language-specific settings menu */
"menu-langsettings-toggle-predict" = "Ἐνεργοποιῆστε προβλέψεις";
/* Help message for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
"menu-lexical-model-install-message" = "Θὰ θέλατε νὰ ἐγκαταστήσετε αὐτὸ τὸ λεξικό;";
/* Title for a prompt that appears for confirming a lexical model download: language (1): lexical model (dictionary) name (2) */
"menu-lexical-model-install-title" = "%1$@: %2$@";
/* Text for an info alert indicating that no lexical models are available */
"menu-lexical-model-none-message" = "Δὲν ὑπάρχουν διαθέσιμα λεξικά";
/* Title for the lexical model menu, a submenu of the language-specific settings menus */
"menu-lexical-model-title" = "%@ Λεξικά";
/* Title for the keyboard picker */
"menu-picker-title" = "Πληκτρολόγια";
/* Primary text for the Settings menu option to report keyboard crashes */
"menu-settings-error-report" = "Ἐπιτρέψτε ἀναφορὲς σφαλμάτων";
/* Secondary text for the Settings menu option to report keyboard crashes */
"menu-settings-error-report-description" = "Μπορεῖ νὰ ἀπαιτηθεῖ \"πλήρης πρόσβαση\"";
/* Primary text for the Settings menu local-file package installation option */
"menu-settings-install-from-file" = "Ἐγκαταστῆστε ἀπὸ ἀρχεῖο";
/* Secondary text for the Settings menu local-file package installation option */
"menu-settings-install-from-file-description" = "Ψάξτε ἀρχεῖα .kmp";
/* Primary text for the Settings menu option that displays the iOS system menu options for the app's keyboard */
"menu-settings-system-keyboard-menu" = "Ρυθμίσεις πληκτρολογίου συστήματος";
/* Label for the "Show Banner" toggle on the main settings screen */
"menu-settings-show-banner" = "Νὰ ἐμφανίζεται Banner";
/* Label for the "Get Started" automatic display toggle seen in the Settings menu */
"menu-settings-startup-get-started" = "Νὰ ἐμφανίζεται ἡ ἐναρκτήρια ὀθόνη κατὰ τὴν ἐκκίνηση";
/* Title for the main Settings menu */
"menu-settings-title" = "Ρυθμίσεις Κῆμαν";
/* Secondary text showing current setting for spacebar caption - blank */
"menu-settings-spacebar-hint-blank" = "Καμμία λεζάντα στὸ πλῆκτρο διαστήματος";
/* Secondary text showing current setting for spacebar caption - keyboard */
"menu-settings-spacebar-hint-keyboard" = "Νὰ ἐμφανίζεται στὸ στὸ πλῆκτρο διαστήματος τὸ ὄνομα τοῦ πληκτρολογίου";
/* Secondary text showing current setting for spacebar caption - language */
"menu-settings-spacebar-hint-language" = "Νὰ ἐμφανίζεται στὸ στὸ πλῆκτρο διαστήματος τὸ ὄνομα τῆς γλώσσας";
/* Secondary text showing current setting for spacebar caption - language + keyboard */
"menu-settings-spacebar-hint-languageKeyboard" = "Νὰ ἐμφανίζεται στὸ στὸ πλῆκτρο διαστήματος τὸ ὄνομα τοῦ πληκτρολογίου καὶ τῆς γλώσσας";
/* Label for the "Spacebar Caption" item on the main settings screen */
"menu-settings-spacebar-text" = "Λεζάντα Πλήκτρου Διαστήματος";
/* Title for the "Spacebar Caption" settings screen */
"menu-settings-spacebar-title" = "Λεζάντα Πλήκτρου Διαστήματος";
/* Text showing name of spacebar caption - blank */
"menu-settings-spacebar-item-blank" = "Κενό";
/* Text showing name of spacebar caption - keyboard */
"menu-settings-spacebar-item-keyboard" = "Πληκτρολόγιο";
/* Text showing name of spacebar caption - language */
"menu-settings-spacebar-item-language" = "Γλῶσσα";
/* Text showing name of spacebar caption - language + keyboard */
"menu-settings-spacebar-item-languageKeyboard" = "Γλῶσσα καὶ πληκτρολόγιο";
/* Short text for notification: download failure for keyboard */
"notification-download-failure-keyboard" = "Ἡ μεταφόρτωση τοῦ πληκτρολογίου ἀπέτυχε";
/* Short text for notification: download failure for lexical model */
"notification-download-failure-lexical-model" = "Ἡ μεταφόρτωση τοῦ λεξικοῦ ἀπέτυχε";
/* Short text for notification: download success for keyboard */
"notification-download-success-keyboard" = "Τὸ πληκτρολόγιο μεταφορτώθηκε ἐπιτυχῶς";
/* Short text for notification: download success for lexical model */
"notification-download-success-lexical-model" = "Τὸ λεξιλογικὸ μοντέλλο μεταφορτώθηκε ἐπιτυχῶς";
/* Short text for notification: downloading a keyboard */
"notification-downloading-keyboard" = "Μεταφορτώνεται πληκτρολόγιο\U2026";
/* Short text for notification: downloading a lexical model */
"notification-downloading-lexical-model" = "Μεταφορτώνεται λεξικό\U2026";
/* Short text for notification: an update is available */
"notification-update-available" = "Διαθέσιμη Ἐνημέρωση";
/* Short text for notification: currently updating */
"notification-update-processing" = "Ἐνημέρωση σὲ ἐξέλιξη\U2026";
/* Text indicating success at installing new keyboards or dictionaries */
"success-install" = "Ἐπιτυχὴς ἐγκατάσταση.";
/* A title to use in alerts indicating 'success' at whatever task the user requested */
"success-title" = "Ἐπιτυχία";

View file

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>menu-langsettings-lexical-model-count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>u</string>
<key>one</key>
<string>Τὸ λεξικὸ %u ἐγκατεστάθη</string>
<key>other</key>
<string>%u λεξικὰ ἐγκατεστάθησαν</string>
</dict>
</dict>
<key>notification-update-failed</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>u</string>
<key>one</key>
<string>%u ἐνημέρωση ἀπέτυχε</string>
<key>other</key>
<string>%u ἐνημερώσεις ἀπέτυχαν</string>
</dict>
</dict>
<key>notification-update-success</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>u</string>
<key>one</key>
<string>%u ἐπιτυχὴς ἐνημέρωση</string>
<key>other</key>
<string>%u ἐπιτυχεῖς ἐνημερώσεις</string>
</dict>
</dict>
<key>settings-keyboards-installed-count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>u</string>
<key>one</key>
<string>%u ἐγκατεστημένο πληκτρολόγιο</string>
<key>other</key>
<string>%u ἐγκατεστημένα πληκτρολόγια</string>
</dict>
</dict>
<key>settings-languages-installed-count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>u</string>
<key>one</key>
<string>%u ἐγκατεστημένη γλῶσσα</string>
<key>other</key>
<string>%u ἐγκατεστημένες γλῶσσες</string>
</dict>
</dict>
<key>package-default-found-keyboards</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>u</string>
<key>one</key>
<string>Εὑρέθη %u πληκτρολόγιο στὸ πακέτο:</string>
<key>other</key>
<string>Εὑρέθησαν %u πληκτρολόγια στὸ πακέτο:</string>
</dict>
</dict>
<key>package-default-found-lexical-models</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>u</string>
<key>one</key>
<string>Εὑρέθη %u λεξικὸ στὸ πακέτο:</string>
<key>other</key>
<string>Εὑρέθησαν %u λεξικὰ στὸ πακέτο:</string>
</dict>
</dict>
</dict>
</plist>

View file

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@ -332,6 +332,7 @@
CE7FF1EF239A0293007859D9 /* PackageBrowserViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageBrowserViewController.swift; sourceTree = "<group>"; };
CE80AD32257F2B4A008D2150 /* KeymanEngine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KeymanEngine.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CE98E6BD2615593300F3F2C0 /* ff */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ff; path = ff.lproj/Localizable.strings; sourceTree = "<group>"; };
CEAC2A272C2A50E100C99ABD /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
CEACC90E25F07D58006EAB45 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
CEACC90F25F07D5A006EAB45 /* km */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = km; path = km.lproj/Localizable.strings; sourceTree = "<group>"; };
CEACC91225F07D77006EAB45 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -793,6 +794,7 @@
sv,
uk,
ru,
el,
);
mainGroup = 98ABADA7176935E400B62590;
productRefGroup = 98ABADB1176935E400B62590 /* Products */;
@ -1106,6 +1108,7 @@
298566C42980C493004ACA95 /* sv */,
298566D02980D354004ACA95 /* uk */,
298566DC2980E416004ACA95 /* ru */,
CEAC2A272C2A50E100C99ABD /* el */,
);
name = Localizable.strings;
sourceTree = "<group>";

View file

@ -0,0 +1,81 @@
/* Title for the bookmarks menu within the embedded browser */
"browser-bookmarks-add-title" = "Προσθέστε σελιδοδείκτη";
/* Title for the bookmarks menu within the embedded browser */
"browser-bookmarks-none" = "Δὲν ὑπάρχουν σελιδοδεῖκτες";
/* Title for the bookmarks menu within the embedded browser */
"browser-bookmarks-title" = "Σελιδοδεῖκτες";
/* Used to confirm a user's desire to install a package */
"confirm-install" = "Ἐγκαταστῆστε";
/* The label for the toggle to stop automatically showing the "Get Started" tutorial popup. */
"disable-get-started" = "Νὰ μὴν ξαναεμφανισθεῖ";
/* Indicates an error opening a web page requested by a user */
"error-opening-page" = "Ἀδυναμία ἀνοίγματος σελίδας";
/* Long-form used when installing a font in order to display a language properly. */
"font-install-description" = "Πατῆστε τὸ πλῆκτρο ἐγκατάστασης γιὰ νὰ ἐμφανίζεται ἡ %@ σωστὰ σὲ ὅλες τὶς ἐφαρμογές σας";
/* The name of the iOS Settings menu option for keyboards */
"ios-settings-keyboards" = "Πληκτρολόγια";
/* The name of the iOS Settings menu option for giving the keyboard full access. (The menu entry
underneath the app's name within the app-specific keyboard menu.) */
"ios-settings-allow-full-access" = "Ἐπιστρέψτε πλήρη πρόσβαση";
/* Short-form used when installing a font in order to display a language properly. */
"language-for-font" = "Γραμματοσειρά %@";
/* Used for 'add' options within menus */
"menu-add" = "Προσθήκη";
/* Used to indicate a sequence of menu options that a user needs to copy. May be chained. Example: "Keyboards (1) > Enable Keyman (2)" */
"menu-breadcrumbing" = "%1$@ > %2$@";
/* Used to exit a menu without choosing an option */
"menu-cancel" = "Ἀκύρωση";
/* Menu option that erases all previously-typed text. */
"menu-clear-text" = "Διαγραφὴ κειμένου";
/* Menu option that displays a list designed to help users start using the app */
"menu-get-started" = "Ξεκινῆστε";
/* Menu option that displays help for the app */
"menu-help" = "Πληροφορίες";
/* Menu option that displays the main screen's drop-down menu */
"menu-more" = "Περισσότερα";
/* Menu option used to edit keyboard and dictionary settings */
"menu-settings" = "Ρυθμίσεις";
/* Menu option that displays the iOS Share menu */
"menu-share" = "Μοιρασθῆτε";
/* Menu option that displays an embedded web browser. */
"menu-show-browser" = "Φυλλομετρητής";
/* Menu option used to control in-app font size. */
"menu-text-size" = "Μέγεθος κειμένου";
/* Used to describe the current font size */
"text-size-label" = "Μέγεθος κειμένου: %i";
/* Text to indicate that a user should set a toggle within iOS Settings to 'active'. */
"toggle-to-enable" = "Ἐνεργοποιῆστε %@";
/* First option on the Get Started tutorial - Add a keyboard for your language */
"tutorial-add-keyboard" = "Προσθέστε πληκτρολόγιο γιὰ τὴν γλῶσσα σας";
/* Third option on the Get Started tutorial - Displays app help. */
"tutorial-show-help" = "Περισσότερες πληροφορίες";
/* Second option on the Get Started tutorial - Set up Keyman as system-wide keyboard */
"tutorial-system-keyboard" = "Ὁρίστε τὸ Κῆμαν ὡς παν-συστημικὸ πληκτρολόγιο";
/* Used to display app version (as in \"Version: 1.0.2\" */
"version-label" = "Ἔκδοση: %@";

View file

@ -13,7 +13,7 @@ import {
import { BANNER_GESTURE_SET } from './bannerGestureSet.js';
import { DeviceSpec, Keyboard, KeyboardProperties } from '@keymanapp/keyboard-processor';
import { DeviceSpec, Keyboard, KeyboardProperties, timedPromise } from '@keymanapp/keyboard-processor';
import { Banner } from './banner.js';
import { ParsedLengthStyle } from '../lengthStyle.js';
import { getFontSizeStyle } from '../fontSizeUtils.js';
@ -175,6 +175,7 @@ export class BannerSuggestion {
}
this.currentWidth = this.collapsedWidth;
this.highlight(suggestion?.autoAccept);
this.updateLayout();
}
@ -553,6 +554,16 @@ export class SuggestionBanner extends Banner {
return;
}
const autoselection = this._predictionContext.selected;
this._predictionContext.selected = null;
if(autoselection) {
this.options.forEach((entry) => {
if(entry.suggestion == autoselection) {
entry.highlight(false);
};
});
}
this.scrollState = new BannerScrollState(source.currentSample, this.container.scrollLeft);
const suggestion = source.baseItem;
@ -585,6 +596,31 @@ export class SuggestionBanner extends Banner {
}
const terminationHandler = () => {
const currentSuggestions = this.currentSuggestions;
// First, schedule reselection of the autoselected suggestion.
// We shouldn't do it synchronously, as suggestion acceptance triggers
// _after_ this handler is called.
// Delaying via the task queue is enough to get the desired order of events.
timedPromise(0).then(async () => {
// If the suggestion list instance has changed, our state has changed; do
// not reselect.
if(currentSuggestions != this.currentSuggestions) {
return;
}
// The suggestions are still current? Then restore the original
// auto-correct suggestion and its highlighting.
this._predictionContext.selected = autoselection;
if(autoselection) {
for(let entry of this.options) {
if(entry.suggestion == autoselection) {
entry.highlight(true);
break;
};
}
}
});
if(sourceTracker.suggestion) {
clearSelection(sourceTracker.suggestion);
sourceTracker.suggestion = null;
@ -603,7 +639,15 @@ export class SuggestionBanner extends Banner {
// The actual result comes in via the sequence's `stage` event.
sequence.once('stage', (result) => {
const suggestion = result.item; // Should also == sourceTracker.suggestion.
if(suggestion && !this.scrollState.hasScrolled) {
// 1. A valid suggestion has been selected
// 2. The user wasn't scrolling the banner. (If they were, they likely
// need to lift their finger to select a newly-visible suggestion!)
// 3. The suggestions themselves are still valid; avoid suggestion
// double-application or similar.
if(suggestion && !this.scrollState.hasScrolled && this.currentSuggestions.length > 0) {
// Invalidate the suggestions internally, but don't visually update;
// this will avoid banner-flicker.
this.currentSuggestions = [];
this.predictionContext.accept(suggestion.suggestion).then(() => {
// Reset the scroll state
this.container.scrollLeft = this.isRTL ? this.container.scrollWidth : 0;

View file

@ -16,7 +16,7 @@
# These files are generated during build
engine/keyman32/KEYMAN32.res
engine/keyman64/Keyman64.res
engine/keyman32/Keyman64.res
engine/keymanx64/keymanx64.res
engine/mcompile/Release/
tds_file.txt

View file

@ -3,11 +3,6 @@ keyman32/keyman-debug-etw.h
keyman32/keyman-debug-etw.rc
keyman32/keyman-debug-etw.res
keyman32/keyman-debug-etwTEMP.BIN
keyman64/MSG00001.bin
keyman64/keyman-debug-etw.h
keyman64/keyman-debug-etw.rc
keyman64/keyman-debug-etw.res
keyman64/keyman-debug-etwTEMP.BIN
mcompile/Debug
# Visual Studio packages for test

View file

@ -11,13 +11,9 @@ The installation merge module database for the Keyman Engine.
Host application for the Keyman Engine. Shows the Keyman icon, Keyman menu, OSK, and handles language switching etc, as well as running the windows hooks to capture and translate keystrokes.
## keyman32 - keyman32.dll
## keyman32 - keyman32.dll, keyman64.dll
Main keyboard processing library and hook library (32 bit).
## keyman64 - keyman64.dll
Main keyboard processing library and hook library (64 bit).
Main keyboard processing library and hook library (x86, x64).
## keymanmc - keymanmc.dll

View file

@ -17,8 +17,7 @@ builder_describe \
\
":insthelper Installation helper module" \
":keyman Main host process (32 bit)" \
":keyman32 Keystroke processing engine (32 bit)" \
":keyman64 Keystroke processing engine (64 bit)" \
":keyman32 Keystroke processing engine (all archs)" \
":keymanmc Message library" \
":keymanx64 Host process (64 bit)" \
":kmcomapi COM API library" \

View file

@ -3,9 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31313.79
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Keyman32", "keyman32\Keyman32.vcxproj", "{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keyman64", "keyman64\keyman64.vcxproj", "{D1115FB2-230D-4FD8-90B9-982E49953D18}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keyman32", "keyman32\Keyman32.vcxproj", "{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keymanx64", "keymanx64\keymanx64.vcxproj", "{A34650EA-D6E8-4229-8091-6BF1443565B5}"
EndProject
@ -29,18 +27,12 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Debug|Win32.ActiveCfg = Debug|Win32
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Debug|Win32.Build.0 = Debug|Win32
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Debug|Win32.ActiveCfg = Release|x64
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Debug|Win32.Build.0 = Release|x64
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Debug|x64.ActiveCfg = Debug|Win32
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Release|Win32.ActiveCfg = Release|Win32
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Release|Win32.Build.0 = Release|Win32
{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}.Release|x64.ActiveCfg = Release|Win32
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Debug|Win32.ActiveCfg = Debug|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Debug|x64.ActiveCfg = Debug|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Debug|x64.Build.0 = Debug|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Release|Win32.ActiveCfg = Release|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Release|x64.ActiveCfg = Release|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Release|x64.Build.0 = Release|x64
{A34650EA-D6E8-4229-8091-6BF1443565B5}.Debug|Win32.ActiveCfg = Debug|x64
{A34650EA-D6E8-4229-8091-6BF1443565B5}.Debug|x64.ActiveCfg = Debug|x64
{A34650EA-D6E8-4229-8091-6BF1443565B5}.Debug|x64.Build.0 = Debug|x64

View file

@ -191,9 +191,6 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM
_td->TIPFUpdateable = Updateable;
_td->TIPFPreserved = Preserved; // I4290
_td->state.msg.hwnd = GetFocus();
_td->state.msg.lParam = 0;
_td->state.msg.message = wm_keymankeydown;
_td->state.vkey = (WORD) wParam;
_td->state.isDown = !isUp;

View file

@ -5,10 +5,11 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "${THIS_SCRIPT%/*}/../../../../resources/build/builder.inc.sh"
## END STANDARD BUILD SCRIPT INCLUDE
builder_describe "Keystroke processing engine (32 bit)" \
builder_describe "Keystroke processing engine" \
@/common/include \
@/core:x86 \
clean configure build test publish install
@/core \
clean configure build test publish install \
:x86 :x64
builder_parse "$@"
@ -16,19 +17,26 @@ builder_parse "$@"
source "$KEYMAN_ROOT/resources/build/win/environment.inc.sh"
WIN32_TARGET="$WIN32_TARGET_PATH/keyman32.dll"
X64_TARGET="$X64_TARGET_PATH/keyman64.dll"
builder_describe_outputs \
configure:project /resources/build/win/delphi_environment_generated.inc.sh \
build:project /windows/src/engine/keyman32/$WIN32_TARGET
configure /resources/build/win/delphi_environment_generated.inc.sh \
build:x86 /windows/src/engine/keyman32/$WIN32_TARGET \
build:x64 /windows/src/engine/keyman32/$X64_TARGET \
#-------------------------------------------------------------------------------------------------------------------
function do_clean() {
vs_msbuild keyman32.vcxproj //t:Clean
function do_clean_x86() {
vs_msbuild keyman32.vcxproj //t:Clean //p:Platform=Win32
clean_windows_project_files
}
function do_build() {
function do_clean_x64() {
vs_msbuild keyman32.vcxproj //t:Clean //p:Platform=x64
clean_windows_project_files
}
function do_build_x86() {
create-windows-output-folders
build_version.res
vs_msbuild keyman32.vcxproj //t:Build "//p:Platform=Win32"
@ -36,21 +44,43 @@ function do_build() {
cp "$WIN32_TARGET_PATH/keyman32.pdb" "$WINDOWS_DEBUGPATH_ENGINE"
}
function do_publish() {
function do_build_x64() {
create-windows-output-folders
run_in_vs_env rc version64.rc
vs_msbuild keyman32.vcxproj //t:Build "//p:Platform=x64"
cp "$X64_TARGET" "$WINDOWS_PROGRAM_ENGINE"
cp "$X64_TARGET_PATH/keyman64.pdb" "$WINDOWS_DEBUGPATH_ENGINE"
}
function do_publish_x86() {
wrap-signcode //d "Keyman Engine for Windows" "$WINDOWS_PROGRAM_ENGINE/keyman32.dll"
wrap-symstore "$WINDOWS_PROGRAM_ENGINE/keyman32.dll" //t keyman-engine-windows
wrap-symstore "$WINDOWS_DEBUGPATH_ENGINE/keyman32.pdb" //t keyman-engine-windows
}
function do_install() {
function do_publish_x64() {
wrap-signcode //d "Keyman Engine for Windows" "$WINDOWS_PROGRAM_ENGINE/keyman64.dll"
wrap-symstore "$WINDOWS_PROGRAM_ENGINE/keyman64.dll" //t keyman-engine-windows
wrap-symstore "$WINDOWS_DEBUGPATH_ENGINE/keyman64.pdb" //t keyman-engine-windows
}
function do_install_x86() {
cp "$WINDOWS_PROGRAM_ENGINE/keyman32.dll" "$INSTALLPATH_KEYMANENGINE/keyman32.dll"
echo "You may want to manually tweak keyman-debug-etw.man and fill in $INSTALLPATH_KEYMANENGINE/keyman32.dll"
echo "and then run wevtutil im keyman-debug-etw.man to get the latest event tracing"
}
builder_run_action clean:project do_clean
builder_run_action configure:project configure_windows_build_environment
builder_run_action build:project do_build
function do_install_x64() {
cp "$WINDOWS_PROGRAM_ENGINE/keyman64.dll" "$INSTALLPATH_KEYMANENGINE/keyman64.dll"
}
builder_run_action clean:x86 do_clean_x86
builder_run_action clean:x64 do_clean_x64
builder_run_action configure configure_windows_build_environment
builder_run_action build:x86 do_build_x86
builder_run_action build:x64 do_build_x64
# builder_run_action test:project do_test
builder_run_action publish:project do_publish
builder_run_action install:project do_install
builder_run_action publish:x86 do_publish_x86
builder_run_action publish:x64 do_publish_x64
builder_run_action install:x86 do_install_x86
builder_run_action install:x64 do_install_x64

View file

@ -270,7 +270,7 @@ extern "C" uint8_t IM_CallBackCore(km_core_state *km_state, uint32_t UniqueStore
SendDebugMessageFormat(0, sdmKeyboard, 0, "IM_CallBackCore: td TIPFUpdatable about to call function [%s]", imdh->name);
LogContext(_td->lpActiveKeyboard->lpCoreKeyboardState, CONTEXT_CORE);
LogContext(_td->lpActiveKeyboard->lpCoreKeyboardState, CONTEXT_INT);
(*imdh->function)(_td->state.msg.hwnd, _td->state.vkey, _td->state.charCode, Globals::get_ShiftState());
(*imdh->function)(GetFocus(), _td->state.vkey, _td->state.charCode, Globals::get_ShiftState());
//SendDebugMessageFormat(0, sdmKeyboard, 0, "IM_CallBackCore: Exit");
return TRUE;

View file

@ -252,8 +252,6 @@ extern UINT
wm_keyman, // user message - ignore msg
wm_keyman_control, // messages to main Keyman window - replaces WM_USER+*
wm_keyman_control_internal, // messages to all windows to notify of changes to Keyman // I4412
wm_keymankeydown,
wm_keymankeyup,
wm_keyman_grabwindowproc,
wm_keyman_refresh,
wm_kmgetactivekeymanid,

View file

@ -26,9 +26,7 @@
// I5136
#include "pch.h"
#ifdef _WIN64
#error hotkeys.cpp is not required for win64.
#endif
#ifndef _WIN64
Hotkeys *g_Hotkeys = NULL; // I4326
@ -141,3 +139,5 @@ Hotkey *Hotkeys::GetHotkey(DWORD hotkey)
return &m_hotkeys[i];
return NULL;
}
#endif

View file

@ -225,13 +225,7 @@ void DebugMessage(LPMSG msg, WPARAM wParam) // I2908
{
char ds[256];
if(msg->message == wm_keymankeydown)
wsprintf(ds, "DebugMessage(%x, wm_keymankeydown: %s lParam: %X) [message flags: %x time: %d]", PtrToInt(msg->hwnd),
Debug_VirtualKey((WORD) msg->wParam), (unsigned int) msg->lParam, wParam, (int) msg->time);
else if(msg->message == wm_keymankeyup)
wsprintf(ds, "DebugMessage(%x, wm_keymankeyup: %s lParam: %X) [message flags: %x time: %d]", PtrToInt(msg->hwnd),
Debug_VirtualKey((WORD) msg->wParam), (unsigned int) msg->lParam, wParam, (int) msg->time);
else if (msg->message == WM_KEYMAN_KEY_EVENT)
if (msg->message == WM_KEYMAN_KEY_EVENT)
wsprintf(ds, "DebugMessage(%x, WM_KEYMAN_KEY_EVENT: %s lParam: %X) [message flags: %x time: %d]", PtrToInt(msg->hwnd),
Debug_VirtualKey((WORD)msg->wParam), (unsigned int) msg->lParam, wParam, (int) msg->time);
else if(msg->message == WM_KEYDOWN || msg->message == WM_KEYUP || msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSKEYUP)

View file

@ -73,8 +73,6 @@ UINT
//TODO: consolidate these messages -- they are probably not all required now
wm_keyman = 0, // user message - ignore msg // I3594
wm_keymankeydown = 0,
wm_keymankeyup = 0,
wm_keyman_grabwindowproc = 0,
wm_keyman_refresh = 0,
wm_kmgetactivekeymanid = 0,

View file

@ -26,9 +26,7 @@
#include "serialkeyeventserver.h"
#include "kbd.h" /* DDK kbdlayout */
#ifdef _WIN64
#error k32_lowlevelkeyboardhook.cpp is not required for win64.
#endif
#ifndef _WIN64
BOOL ProcessHotkey(UINT vkCode, BOOL isUp, DWORD ShiftState);
@ -329,3 +327,5 @@ BOOL ProcessHotkey(UINT vkCode, BOOL isUp, DWORD ShiftState) {
return TRUE;
}
#endif

View file

@ -190,8 +190,6 @@ void DoChangeWindowMessageFilter()
}
DoCWMF(wm_keyman); // I3594
DoCWMF(wm_keymankeydown);
DoCWMF(wm_keymankeyup);
DoCWMF(wm_keyman_grabwindowproc);
DoCWMF(wm_keyman_refresh);
DoCWMF(wm_kmgetactivekeymanid);
@ -255,8 +253,6 @@ BOOL InitialiseProcess(HWND hwnd)
Initialise_Flag_ShouldSerializeInput();
wm_keyman = RegisterWindowMessage(RWM_KEYMAN);
wm_keymankeydown = RegisterWindowMessage("WM_KEYMANKEYDOWN");
wm_keymankeyup = RegisterWindowMessage("WM_KEYMANKEYUP");
wm_keyman_grabwindowproc = RegisterWindowMessage("WM_KEYMAN_GRABWINDOWPROC");
wm_keyman_refresh = RegisterWindowMessage("WM_KEYMANREFRESH");
wm_kmgetactivekeymanid = RegisterWindowMessage("WM_KEYMAN_GETACTIVEKEYMANID");

View file

@ -1,4 +1,3 @@
#include "version.rc"
/////////////////////////////////////////////////////////////////////////////

View file

@ -5,10 +5,18 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BD5564FB-35A5-4A3C-B96A-4A6578E2B593}</ProjectGuid>
@ -22,11 +30,21 @@
<UseOfMfc>false</UseOfMfc>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@ -34,33 +52,65 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)obj\$(Platform)\$(Configuration)\</IntDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)obj\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)obj\$(Platform)\$(Configuration)\</IntDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)obj\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LibraryPath>$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\subprojects\icu\source\common;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\subprojects\icu\source\i18n;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath)</LibraryPath>
<IncludePath>$(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath)</IncludePath>
<TargetName>keyman32</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\common;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\i18n;$(ProjectDir)..\..\..\..\core\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(IncludePath)</IncludePath>
<TargetName>keyman64</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\subprojects\icu\source\common;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\subprojects\icu\source\i18n;$(ProjectDir)..\..\..\..\core\build\rust\x86\$(Configuration);$(LibraryPath)</LibraryPath>
<IncludePath>$(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x86\$(Configuration)\include;$(IncludePath)</IncludePath>
<TargetName>keyman32</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\common;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\i18n;$(ProjectDir)..\..\..\..\core\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(IncludePath)</IncludePath>
<TargetName>keyman64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
@ -120,6 +170,62 @@
</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TypeLibraryName>./Keyman32.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>.\;..\..\global\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AssemblerOutput>All</AssemblerOutput>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/verbose:lib /section:.SHARDATA,rws %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>libicuuc.a;libicuin.a;libkeymancore.a;psapi.lib;rpcrt4.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>keyman64.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<MapExports>false</MapExports>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<BaseAddress>0x1c100000</BaseAddress>
<UACUIAccess>true</UACUIAccess>
<TreatWarningAsError>true</TreatWarningAsError>
<ImportLibrary>..\..\..\lib\keyman64.lib</ImportLibrary>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>./Keyman64.bsc</OutputFile>
</Bscmake>
<Manifest>
<AdditionalManifestFiles>
</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -173,124 +279,92 @@
</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TypeLibraryName>./Keyman32.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.\;..\..\global\inc;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AssemblerOutput>All</AssemblerOutput>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/verbose:lib /section:.SHARDATA,rws %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>libicuuc.a;libicuin.a;libkeymancore.a;psapi.lib;rpcrt4.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>keyman64.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<SubSystem>Windows</SubSystem>
<BaseAddress>0x1C100000</BaseAddress>
<UACUIAccess>true</UACUIAccess>
<TreatWarningAsError>true</TreatWarningAsError>
<ImportLibrary>..\..\..\lib\keyman64.lib</ImportLibrary>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>./Keyman32.bsc</OutputFile>
</Bscmake>
<Manifest>
<AdditionalManifestFiles>
</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\global\cpp\kmtip_guids.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\xstring.cpp" />
<ClCompile Include="appcontext.cpp" />
<ClCompile Include="appint\aiTIP.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="appint\aiWin2000Unicode.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="appint\appint.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="calldll.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="capsstate.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="appint\aiTIP.cpp" />
<ClCompile Include="appint\aiWin2000Unicode.cpp" />
<ClCompile Include="appint\appint.cpp" />
<ClCompile Include="calldll.cpp" />
<ClCompile Include="capsstate.cpp" />
<ClCompile Include="CoreEnvironment.cpp" />
<ClCompile Include="DebugEventTrace.cpp" />
<ClCompile Include="glossary.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="glossary.cpp" />
<ClCompile Include="hookutils.cpp" />
<ClCompile Include="hotkeys.cpp" />
<ClCompile Include="K32_DBG.CPP">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="k32_globals.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="K32_LOAD.CPP">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="K32_DBG.CPP" />
<ClCompile Include="k32_globals.cpp" />
<ClCompile Include="K32_load.cpp" />
<ClCompile Include="k32_lowlevelkeyboardhook.cpp" />
<ClCompile Include="k32_tsf.cpp" />
<ClCompile Include="keybd_shift.cpp" />
<ClCompile Include="keyboardoptions.cpp" />
<ClCompile Include="KEYMAN32.CPP">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\keynames.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="keystate.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="kmhook_callwndproc.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="kmhook_getmessage.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="kmhook_keyboard.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="kmprocess.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\registry.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="keyman32.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\keynames.cpp" />
<ClCompile Include="keystate.cpp" />
<ClCompile Include="kmhook_callwndproc.cpp" />
<ClCompile Include="kmhook_getmessage.cpp" />
<ClCompile Include="kmhook_keyboard.cpp" />
<ClCompile Include="kmprocess.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\registry.cpp" />
<ClCompile Include="kmprocessactions.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="preservedkeymap.cpp" />
<ClCompile Include="security.cpp" />
@ -298,60 +372,58 @@
<ClCompile Include="serialkeyeventclient.cpp" />
<ClCompile Include="serialkeyeventserver.cpp" />
<ClCompile Include="SharedBuffers.cpp" />
<ClCompile Include="syskbd.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="syskbdnt.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="syskbd.cpp" />
<ClCompile Include="syskbdnt.cpp" />
<ClCompile Include="syskbdnt64.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\unicode.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="versioninfo.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="VKScanCodes.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\unicode.cpp" />
<ClCompile Include="versioninfo.cpp" />
<ClCompile Include="VKScanCodes.cpp" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="keyman-debug-etw.man">
<FileType>Document</FileType>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc %(FullPath)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc %(FullPath)</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling keyman-debug-etw</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling keyman-debug-etw</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Filename).rc;%(Filename.h);MSG00001.bin</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).rc;%(Filename.h);MSG00001.bin</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc %(FullPath)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc %(FullPath)</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling keyman-debug-etw</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling keyman-debug-etw</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Filename).rc;%(Filename.h);MSG00001.bin</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).rc;%(Filename.h);MSG00001.bin</Outputs>
<SubType>Designer</SubType>
</CustomBuild>
<None Include="KEYMAN32.DEF" />
<None Include="KEYMAN32.DEF">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</None>
<None Include="..\..\..\..\common\resources\bitmaps\arrow.bmp" />
<None Include="..\..\..\..\common\resources\bitmaps\mask.bmp" />
<None Include="keyman64.def">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="keyman-debug-etw.rc" />
<ResourceCompile Include="KEYMAN32.RC">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ResourceCompile>
<ResourceCompile Include="keyman64.rc">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ResourceCompile>
</ItemGroup>
<ItemGroup>

View file

@ -152,6 +152,9 @@
<None Include="..\..\..\..\common\resources\bitmaps\mask.bmp">
<Filter>Resource Files</Filter>
</None>
<None Include="keyman64.def">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="KEYMAN32.RC">
@ -160,6 +163,9 @@
<ResourceCompile Include="keyman-debug-etw.rc">
<Filter>Source Files</Filter>
</ResourceCompile>
<ResourceCompile Include="keyman64.rc">
<Filter>Source Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="appint\aiTIP.h">

View file

@ -0,0 +1,45 @@
LIBRARY KEYMAN64
EXPORTS
Keyman_GetInitialised
Keyman_Initialise
Keyman_Exit
Keyman_GetLastActiveWindow
Keyman_GetLastFocusWindow
KMSetOutput
KMGetContext
KMQueueAction
KMDisplayIM
KMHideIM
KMGetActiveKeyboard
KMGetKeyboardPath
TIPActivateEx
TIPActivateKeyboard
TIPProcessKey
TIPIsKeymanRunning
GetKeyboardPreservedKeys
GetActiveKeymanID
Keyman_RegisterControllerWindow
Keyman_UnregisterControllerWindow
Keyman_RestartEngine
Keyman_SendMasterController
Keyman_PostControllers
Keyman_PostMasterController
Keyman_StartExit
Keyman_ResetInitialisation
Keyman_WriteDebugEvent
Keyman_WriteDebugEventW
Keyman_Diagnostic
Keyman_RegisterMasterController
Keyman_UnregisterMasterController
Keyman_RegisterControllerThread
Keyman_UnregisterControllerThread
SetCustomPostKeyCallback

View file

@ -0,0 +1 @@
#include "version64.rc"

View file

@ -97,7 +97,6 @@ typedef struct tagINTKEYBOARDINFO
typedef struct tagKMSTATE
{
BOOL NoMatches;
MSG msg;
WORD vkey; // I934
WCHAR charCode; // I4582
BOOL windowunicode; // I4287

View file

@ -73,21 +73,21 @@ void GetCapsAndNumlockState();
/*
BOOL SysTabCtrl(HWND hwnd)
{
char buf[64];
GetClassName(hwnd, buf, 64);
return !strcmpi(buf, "SysTabControl32");
char buf[64];
GetClassName(hwnd, buf, 64);
return !strcmpi(buf, "SysTabControl32");
}
*/
BOOL IsMessageEquivalent(LPMSG m1, LPMSG m2)
{
return m1->hwnd == m2->hwnd &&
m1->lParam == m2->lParam &&
m1->message == m2->message &&
m1->time == m2->time &&
m1->pt.x == m2->pt.x &&
m1->pt.y == m2->pt.y &&
m1->wParam == m2->wParam;
return m1->hwnd == m2->hwnd &&
m1->lParam == m2->lParam &&
m1->message == m2->message &&
m1->time == m2->time &&
m1->pt.x == m2->pt.x &&
m1->pt.y == m2->pt.y &&
m1->wParam == m2->wParam;
}
LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam);
@ -108,16 +108,16 @@ LRESULT CALLBACK kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
}
#endif
return res;
return res;
}
LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LPMSG mp;
LPMSG mp;
mp = (LPMSG)lParam;
mp = (LPMSG)lParam;
// If the message sent should be ignored, just return
// If the message sent should be ignored, just return
if(nCode < 0)
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
@ -131,19 +131,18 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
_td = ThreadGlobals();
if(!_td)
if(!_td)
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(!_td->FInitialised) // Keyman keyboard is being selected for first time in active process
{
if(!Globals::CheckControllers()) return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); // I2435 - Prevent Keyman from re-initialising when it is shutting down // I3253 // I3532
if(!InitialiseProcess(mp->hwnd)) return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
if(!InitialiseProcess(mp->hwnd)) return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if (((mp->message >= WM_KEYFIRST && mp->message <= WM_KEYLAST) || mp->message == wm_keymankeydown || mp->message == wm_keymankeyup ||
mp->message == WM_KEYMAN_KEY_EVENT)
&& ShouldDebug(sdmMessage)) {
if (((mp->message >= WM_KEYFIRST && mp->message <= WM_KEYLAST) ||
mp->message == WM_KEYMAN_KEY_EVENT) && ShouldDebug(sdmMessage)) {
DebugMessage(mp, wParam);
}
@ -173,67 +172,52 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
// I1337 - move mousewheel message checking before the PM_REMOVE handling - otherwise we can't pre-modify the message
// TODO: Move to WH_MOUSE_LL proc in main process
if(mp->message == WM_MOUSEWHEEL)
{
HWND hwndMouseWheel = FindWindow("TfrmVisualKeyboard", NULL);
if(hwndMouseWheel && GetWindowThreadProcessId(mp->hwnd, NULL) != GetWindowThreadProcessId(hwndMouseWheel, NULL))
{
RECT rcMouseWheel;
POINT pt;
GetWindowRect(hwndMouseWheel, &rcMouseWheel);
pt.x = LOWORD(mp->lParam);
pt.y = HIWORD(mp->lParam);
if(PtInRect(&rcMouseWheel, pt))
{
if(mp->message == WM_MOUSEWHEEL)
{
HWND hwndMouseWheel = FindWindow("TfrmVisualKeyboard", NULL);
if(hwndMouseWheel && GetWindowThreadProcessId(mp->hwnd, NULL) != GetWindowThreadProcessId(hwndMouseWheel, NULL))
{
RECT rcMouseWheel;
POINT pt;
GetWindowRect(hwndMouseWheel, &rcMouseWheel);
pt.x = LOWORD(mp->lParam);
pt.y = HIWORD(mp->lParam);
if(PtInRect(&rcMouseWheel, pt))
{
// if(!_td->state.PreviousNoRemove) // I2908
PostMessage(WindowFromPoint(pt), WM_MOUSEWHEEL, mp->wParam, mp->lParam);
mp->message = WM_NULL;
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
}
}
PostMessage(WindowFromPoint(pt), WM_MOUSEWHEEL, mp->wParam, mp->lParam);
mp->message = WM_NULL;
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
}
}
if((wParam & PM_REMOVE) == 0) // I2908
{
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
#if 0 // I2908
if(_td->state.PreviousNoRemove && IsMessageEquivalent(&_td->state.msg, mp))
{
/*
Was the previous message the same as this one. If so, don't process it again.
*/
_td->state.PreviousNoRemove = (wParam & PM_REMOVE) == 0;
_td->state.msg = *mp;
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
#endif
_td->state.msg = *mp;
/*_td->state.PreviousNoRemove = (wParam & PM_REMOVE) == 0; I2908 */
// 16 April 2005, 7 May 2007 - mcdurdin - Check if Keyman is receiving messages (reimplement from v6.2) */
if(mp->message == wm_test_keyman_functioning && mp->wParam == TKF_PING)
{
PostMessage(mp->hwnd, wm_test_keyman_functioning, TKF_RESPONSE, mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(mp->message == wm_test_keyman_functioning && mp->wParam == TKF_PING)
{
PostMessage(mp->hwnd, wm_test_keyman_functioning, TKF_RESPONSE, mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
// I3594
if(mp->message == wm_keyman_refresh)
{
SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keyman_refresh %d tag=%d", mp->wParam, mp->lParam);
HandleRefresh((int) mp->wParam, (LONG) mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(mp->message == wm_keyman_refresh)
{
SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keyman_refresh %d tag=%d", mp->wParam, mp->lParam);
HandleRefresh((int) mp->wParam, (LONG) mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(mp->message == wm_keyman_control_internal) // I3933
{
if(mp->message == wm_keyman_control_internal) // I3933
{
SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keyman_control_internal hwnd=%x %x %x", mp->hwnd, mp->wParam, mp->lParam); // I4674
ProcessWMKeymanControlInternal(mp->hwnd, mp->wParam, mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
ProcessWMKeymanControlInternal(mp->hwnd, mp->wParam, mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if (mp->message == wm_keyman_control) {
SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keyman_control hwnd=%x %x %x", mp->hwnd, mp->wParam, mp->lParam);
@ -241,43 +225,43 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(mp->message == wm_keyman) // I3933
{
if(mp->message == wm_keyman) // I3933
{
SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keyman hwnd=%x %x %x", mp->hwnd, mp->wParam, mp->lParam); // I4674
ProcessWMKeyman(mp->hwnd, mp->wParam, mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
ProcessWMKeyman(mp->hwnd, mp->wParam, mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
/*
Handle wm_keyman_control_internal messages
*/
/*
Handle wm_keyman_control_internal messages
*/
/*
If the keyboard needs to be activated, select it: messaging from the main application
*/
/*
If the keyboard needs to be activated, select it: messaging from the main application
*/
if(_td->lpActiveKeyboard)
{
if(_td->lpActiveKeyboard)
{
_td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard;
}
}
// I4412
if(mp->message == wm_keymanshift)
{
SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keymanshift %x %x", mp->wParam, mp->lParam);
if(mp->message == wm_keymanshift)
{
SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keymanshift %x %x", mp->wParam, mp->lParam);
SelectApplicationIntegration();
if(!_td->app->IsWindowHandled(mp->hwnd)) _td->app->HandleWindow(mp->hwnd);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(!_td->app->IsWindowHandled(mp->hwnd)) _td->app->HandleWindow(mp->hwnd);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(*Globals::hwndIM() != 0)
{
if(mp->message == wm_keymanim_close)
{
if(mp->lParam) KMHideIM();
if(mp->wParam)
{
if(_td->app)
{
if(*Globals::hwndIM() != 0)
{
if(mp->message == wm_keymanim_close)
{
if(mp->lParam) KMHideIM();
if(mp->wParam)
{
if(_td->app)
{
// Call the core keyboard processor to process the queued actions
if (!_td->lpActiveKeyboard) {
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
@ -291,43 +275,45 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
_td->app->SetCurrentShiftState(Globals::get_ShiftState());
_td->app->SendActions();
}
}
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
}
}
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(!*Globals::hwndIMAlways())
{
if(mp->message == wm_keymankeydown)
PostMessage(*Globals::hwndIM(), WM_KEYDOWN, mp->wParam, mp->lParam);
else if(mp->message == wm_keymankeyup)
PostMessage(*Globals::hwndIM(), WM_KEYUP, mp->wParam, mp->lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
}
if(!*Globals::hwndIMAlways())
{
/* TODO: IM windows no longer receive these messages, what is going on? #11919?
if(mp->message == wxm_keymankeydown)
PostMessage(*Globals::hwndIM(), WM_KEYDOWN, mp->wParam, mp->lParam);
else if(mp->message == wxm_keymankeyup)
PostMessage(*Globals::hwndIM(), WM_KEYUP, mp->wParam, mp->lParam);
*/
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
}
/*
If no keyboard is active, return
*/
/*
If no keyboard is active, return
*/
if(!_td->lpActiveKeyboard || _td->FInRefreshKeyboards)
{
if(_td->app) _td->app->ResetContext();
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(!_td->lpActiveKeyboard || _td->FInRefreshKeyboards)
{
if(_td->app) _td->app->ResetContext();
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(mp->message > WM_MOUSEFIRST && mp->message <= WM_MOUSELAST && !IsIMWindow(mp->hwnd))
{
// > MOUSEFIRST ignores mouse movement
if(_td->app) _td->app->ResetContext();
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
if(mp->message > WM_MOUSEFIRST && mp->message <= WM_MOUSELAST && !IsIMWindow(mp->hwnd))
{
// > MOUSEFIRST ignores mouse movement
if(_td->app) _td->app->ResetContext();
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
/* // I3617
Text Services Framework tells us we don't need to continue here
*/
/* // I3617
Text Services Framework tells us we don't need to continue here
*/
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam);
}
void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam)
@ -335,38 +321,38 @@ void ProcessWMKeyman(HWND hwnd, WPARAM wParam, LPARAM lParam)
PKEYMAN64THREADDATA _td = ThreadGlobals();
if(!_td) return;
SendDebugMessageFormat(hwnd, sdmGlobal, 0, "ProcessWMKeyman wm_keyman: %d %d", wParam, lParam);
switch(wParam)
{
case KM_DISABLEUI:
_td->KeymanUIDisabled = TRUE;
break;
case KM_ENABLEUI:
_td->KeymanUIDisabled = FALSE;
break;
case KM_FOCUSCHANGED:
SendDebugMessageFormat(hwnd, sdmGlobal, 0, "ProcessWMKeyman wm_keyman: %d %d", wParam, lParam);
switch(wParam)
{
case KM_DISABLEUI:
_td->KeymanUIDisabled = TRUE;
break;
case KM_ENABLEUI:
_td->KeymanUIDisabled = FALSE;
break;
case KM_FOCUSCHANGED:
if(lParam & KMF_WINDOWCHANGED)
{
hwnd = GetFocus();
if(_td->lpActiveKeyboard) {
if(_td->lpActiveKeyboard) {
_td->state.lpCoreKb = _td->lpActiveKeyboard->lpCoreKeyboard;
}
}
SelectApplicationIntegration();
if(_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd);
_td->state.windowunicode = !_td->app || _td->app->IsUnicode();
if(IsFocusedThread())
{
{
if(_td->app) _td->app->ResetQueue();
GetCapsAndNumlockState();
UpdateActiveWindows();
GetCapsAndNumlockState();
UpdateActiveWindows();
}
}
break;
}
break;
}
}
@ -374,8 +360,8 @@ void ProcessWMKeymanControlInternal(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(hwnd);
switch(wParam)
{
switch(wParam)
{
case KMCI_GETACTIVEKEYBOARD: // I3933
ReportActiveKeyboard(LOWORD(lParam)); // I3949
break;
@ -393,7 +379,7 @@ void ProcessWMKeymanControlInternal(HWND hwnd, WPARAM wParam, LPARAM lParam)
case KMCI_SETFOREGROUND: // I3933
SetForegroundWindow(hwnd);
break;
}
}
}
void
@ -422,30 +408,30 @@ ProcessWMKeymanControl(WPARAM wParam, LPARAM lParam) {
may have been reset while Keyman was not aware of it
*/
void GetCapsAndNumlockState() { // I4793
DWORD n = Globals::get_ShiftState();
DWORD n = Globals::get_ShiftState();
if(GetKeyState(VK_NUMLOCK) & 1) *Globals::ShiftState() |= NUMLOCKFLAG;
else *Globals::ShiftState() &= ~NUMLOCKFLAG;
if(GetKeyState(VK_NUMLOCK) & 1) *Globals::ShiftState() |= NUMLOCKFLAG;
else *Globals::ShiftState() &= ~NUMLOCKFLAG;
if(GetKeyState(VK_CAPITAL) & 1) *Globals::ShiftState() |= CAPITALFLAG;
else *Globals::ShiftState() &= ~CAPITALFLAG;
if(GetKeyState(VK_CAPITAL) & 1) *Globals::ShiftState() |= CAPITALFLAG;
else *Globals::ShiftState() &= ~CAPITALFLAG;
if(GetKeyState(VK_SHIFT) < 0) *Globals::ShiftState() |= K_SHIFTFLAG;
else *Globals::ShiftState() &= ~K_SHIFTFLAG;
if(GetKeyState(VK_SHIFT) < 0) *Globals::ShiftState() |= K_SHIFTFLAG;
else *Globals::ShiftState() &= ~K_SHIFTFLAG;
if(GetKeyState(VK_RCONTROL) < 0) *Globals::ShiftState() |= RCTRLFLAG;
else *Globals::ShiftState() &= ~RCTRLFLAG;
if(GetKeyState(VK_RCONTROL) < 0) *Globals::ShiftState() |= RCTRLFLAG;
else *Globals::ShiftState() &= ~RCTRLFLAG;
if(GetKeyState(VK_LCONTROL) < 0) *Globals::ShiftState() |= LCTRLFLAG;
else *Globals::ShiftState() &= ~LCTRLFLAG;
if(GetKeyState(VK_LCONTROL) < 0) *Globals::ShiftState() |= LCTRLFLAG;
else *Globals::ShiftState() &= ~LCTRLFLAG;
if(GetKeyState(VK_LMENU) < 0) *Globals::ShiftState() |= LALTFLAG;
else *Globals::ShiftState() &= ~LALTFLAG;
if(GetKeyState(VK_LMENU) < 0) *Globals::ShiftState() |= LALTFLAG;
else *Globals::ShiftState() &= ~LALTFLAG;
if(GetKeyState(VK_RMENU) < 0) *Globals::ShiftState() |= RALTFLAG;
else *Globals::ShiftState() &= ~RALTFLAG;
if(GetKeyState(VK_RMENU) < 0) *Globals::ShiftState() |= RALTFLAG;
else *Globals::ShiftState() &= ~RALTFLAG;
SendDebugMessageFormat(0, sdmInternat, 0, "GetCapsAndNumlockState (Enter:%x Exit:%x)", n, Globals::get_ShiftState());
SendDebugMessageFormat(0, sdmInternat, 0, "GetCapsAndNumlockState (Enter:%x Exit:%x)", n, Globals::get_ShiftState());
}
/*
@ -489,5 +475,5 @@ BOOL IsFocusedThread()
return FALSE;
}
return gti.hwndFocus == GetFocus();
//return GetCurrentThreadId() == GetWindowThreadProcessId(GetForegroundWindow(), NULL);
//return GetCurrentThreadId() == GetWindowThreadProcessId(GetForegroundWindow(), NULL);
}

View file

@ -62,9 +62,8 @@
#include "pch.h"
#include <Psapi.h>
#ifdef _WIN64
#error kmhook_keyboard.cpp is not required for win64.
#endif
#ifndef _WIN64
// I3617
BOOL IsLanguageSwitchWindowVisible();
void SendToLanguageSwitchWindow(WPARAM wParam, LPARAM lParam);
@ -192,3 +191,5 @@ int ProcessLanguageSwitchShiftKey(WPARAM wParam, BOOL isUp)
PostDummyKeyEvent(); // I3301 - this is imperfect because we don't deal with HC_NOREMOVE. But good enough? // I3534 // I4844
return 0;
}
#endif

View file

@ -121,23 +121,22 @@ BOOL ProcessHook()
fOutputKeystroke = FALSE; // TODO: 5442 no longer needs to be global once we use core processor
if(_td->state.msg.message == wm_keymankeydown) { // I4827
if (ShouldDebug(sdmKeyboard)) {
if(!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Key pressed: %s Context <unavailable>",
Debug_VirtualKey(_td->state.vkey));
} else {
km_core_cu* debug_context = km_core_state_context_debug(
_td->lpActiveKeyboard->lpCoreKeyboardState,
KM_CORE_DEBUG_CONTEXT_CACHED
);
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Key pressed: %s Context '%ls'",
Debug_VirtualKey(_td->state.vkey), debug_context);
km_core_cu_dispose(debug_context);
}
if (ShouldDebug(sdmKeyboard)) {
if(!_td->lpActiveKeyboard || !_td->lpActiveKeyboard->lpCoreKeyboardState) {
SendDebugMessageFormat(0, sdmKeyboard, 0, "Key %s: %s Context <unavailable>",
_td->state.isDown ? "pressed" : "released",
Debug_VirtualKey(_td->state.vkey));
} else {
km_core_cu* debug_context = km_core_state_context_debug(
_td->lpActiveKeyboard->lpCoreKeyboardState,
KM_CORE_DEBUG_CONTEXT_CACHED
);
SendDebugMessageFormat(0, sdmKeyboard, 0, "Key %s: %s Context '%ls'",
_td->state.isDown ? "pressed" : "released",
Debug_VirtualKey(_td->state.vkey), debug_context);
km_core_cu_dispose(debug_context);
}
}
}
// For applications not using the TSF kmtip calls this function twice for each keystroke,
// first to determine if we are doing processing work (TIPFUpdateable == FALSE),

View file

@ -31,6 +31,9 @@
////////////////////////////////////////////////////////////////////////////
#include "pch.h"
#ifndef _WIN64
#include "kbd.h" /* DDK kbdlayout */
//#pragma warning ( disable : 4200 )
@ -221,3 +224,5 @@ BOOL IsWow64()
fStored = TRUE;
return bIsWow64;
}
#endif

View file

@ -1,50 +0,0 @@
#!/usr/bin/env bash
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "${THIS_SCRIPT%/*}/../../../../resources/build/builder.inc.sh"
## END STANDARD BUILD SCRIPT INCLUDE
builder_describe "Keystroke processing engine (64 bit)" \
@/common/include \
@/core:x64 \
clean configure build test publish install
builder_parse "$@"
#-------------------------------------------------------------------------------------------------------------------
source "$KEYMAN_ROOT/resources/build/win/environment.inc.sh"
X64_TARGET="$X64_TARGET_PATH/keyman64.dll"
builder_describe_outputs \
configure:project /resources/build/win/delphi_environment_generated.inc.sh \
build:project /windows/src/engine/keyman64/$X64_TARGET
#-------------------------------------------------------------------------------------------------------------------
function do_clean() {
vs_msbuild keyman64.vcxproj //t:Clean
clean_windows_project_files
}
function do_build() {
create-windows-output-folders
build_version.res
vs_msbuild keyman64.vcxproj //t:Build "//p:Platform=x64"
cp "$X64_TARGET" "$WINDOWS_PROGRAM_ENGINE"
cp "$X64_TARGET_PATH/keyman64.pdb" "$WINDOWS_DEBUGPATH_ENGINE"
}
function do_publish() {
wrap-signcode //d "Keyman Engine for Windows" "$WINDOWS_PROGRAM_ENGINE/keyman64.dll"
wrap-symstore "$WINDOWS_PROGRAM_ENGINE/keyman64.dll" //t keyman-engine-windows
wrap-symstore "$WINDOWS_DEBUGPATH_ENGINE/keyman64.pdb" //t keyman-engine-windows
}
builder_run_action clean:project do_clean
builder_run_action configure:project configure_windows_build_environment
builder_run_action build:project do_build
# builder_run_action test:project do_test
builder_run_action publish:project do_publish
builder_run_action install:project cp "$WINDOWS_PROGRAM_ENGINE/keyman64.dll" "$INSTALLPATH_KEYMANENGINE/keyman64.dll"

View file

@ -1,3 +0,0 @@
#include "version.rc"

View file

@ -1,24 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "keyman64", "keyman64.vcxproj", "{D1115FB2-230D-4FD8-90B9-982E49953D18}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Debug|Win32.ActiveCfg = Debug|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Debug|x64.ActiveCfg = Debug|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Debug|x64.Build.0 = Debug|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Release|Win32.ActiveCfg = Release|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Release|x64.ActiveCfg = Release|x64
{D1115FB2-230D-4FD8-90B9-982E49953D18}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -1,332 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D1115FB2-230D-4FD8-90B9-982E49953D18}</ProjectGuid>
<RootNamespace>Keyman32</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)obj\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)obj\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\common;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\i18n;$(ProjectDir)..\..\..\..\core\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\src;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\common;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\subprojects\icu\source\i18n;$(ProjectDir)..\..\..\..\core\build\rust\x64\$(Configuration);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(ProjectDir)..\..\..\..\common\include;$(ProjectDir)..\..\..\..\core\include;$(ProjectDir)..\..\..\..\core\build\x64\$(Configuration)\include;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>./Keyman32.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\keyman32;..\..\global\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
<StringPooling>true</StringPooling>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AssemblerOutput>All</AssemblerOutput>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/verbose:lib /section:.SHARDATA,rws %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>libicuuc.a;libicuin.a;libkeymancore.a;psapi.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;libcmt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>C:\Program Files\Microsoft SDKs\Windows\v7.0\Lib\x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>
</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<MapExports>true</MapExports>
<SubSystem>Windows</SubSystem>
<BaseAddress>0x1C800000</BaseAddress>
<ImportLibrary>..\..\..\lib\Keyman64.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
<UACUIAccess>true</UACUIAccess>
<TreatWarningAsError>true</TreatWarningAsError>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>./Keyman32.bsc</OutputFile>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>./Keyman32.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\keyman32;..\..\global\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
<MinimalRebuild>true</MinimalRebuild>
<ExceptionHandling>
</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AssemblerOutput>All</AssemblerOutput>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/verbose:lib /section:.SHARDATA,rws %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>libicuuc.a;libicuin.a;libkeymancore.a;psapi.lib;version.lib;setupapi.lib;iphlpapi.lib;imm32.lib;crypt32.lib;wintrust.lib;imagehlp.lib;ws2_32.lib;libcmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>C:\Program Files\Microsoft SDKs\Windows\v7.0\Lib\x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
<ModuleDefinitionFile>
</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<SubSystem>Windows</SubSystem>
<BaseAddress>0x1C800000</BaseAddress>
<ImportLibrary>..\..\..\lib\Keyman64.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
<UACUIAccess>true</UACUIAccess>
<TreatWarningAsError>true</TreatWarningAsError>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>./Keyman32.bsc</OutputFile>
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\global\cpp\kmtip_guids.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\xstring.cpp" />
<ClCompile Include="..\keyman32\appcontext.cpp" />
<ClCompile Include="..\keyman32\appint\aiTIP.cpp" />
<ClCompile Include="..\keyman32\appint\aiWin2000Unicode.cpp" />
<ClCompile Include="..\keyman32\appint\appint.cpp" />
<ClCompile Include="..\keyman32\calldll.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\capsstate.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\CoreEnvironment.cpp" />
<ClCompile Include="..\keyman32\DebugEventTrace.cpp" />
<ClCompile Include="..\keyman32\glossary.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\hookutils.cpp" />
<ClCompile Include="..\keyman32\K32_DBG.CPP" />
<ClCompile Include="..\keyman32\k32_globals.cpp" />
<ClCompile Include="..\keyman32\K32_load.cpp" />
<ClCompile Include="..\keyman32\k32_tsf.cpp" />
<ClCompile Include="..\keyman32\keybd_shift.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\keyboardoptions.cpp" />
<ClCompile Include="..\keyman32\Keyman32.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\keynames.cpp" />
<ClCompile Include="..\keyman32\keystate.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\kmhook_callwndproc.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\kmhook_getmessage.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\kmprocess.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\registry.cpp" />
<ClCompile Include="..\keyman32\kmprocessactions.cpp" />
<ClCompile Include="..\keyman32\pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\keyman32\preservedkeymap.cpp" />
<ClCompile Include="..\keyman32\security.cpp" />
<ClCompile Include="..\keyman32\selectkeyboard.cpp" />
<ClCompile Include="..\keyman32\serialkeyeventclient.cpp" />
<ClCompile Include="..\keyman32\serialkeyeventserver.cpp" />
<ClCompile Include="..\keyman32\SharedBuffers.cpp" />
<ClCompile Include="..\keyman32\syskbd.cpp" />
<ClCompile Include="..\keyman32\syskbdnt.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\unicode.cpp" />
<ClCompile Include="..\keyman32\versioninfo.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
<ClCompile Include="..\keyman32\VKScanCodes.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\keyman32\keyman-debug-etw.rc" />
<ResourceCompile Include="Keyman64.RC" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\keyman32\appcontext.h" />
<ClInclude Include="..\keyman32\keymanengine.h" />
<ClInclude Include="..\..\..\include\kmtip_guids.h" />
<ClInclude Include="..\keyman32\appint\aiTIP.h" />
<ClInclude Include="..\keyman32\appint\aiWin2000Unicode.h" />
<ClInclude Include="..\keyman32\appint\appint.h" />
<ClInclude Include="..\keyman32\calldll.h" />
<ClInclude Include="..\keyman32\capsstate.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\legacy_kmx_file.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\crc32.h" />
<ClInclude Include="..\keyman32\globals.h" />
<ClInclude Include="..\keyman32\hotkeys.h" />
<ClInclude Include="..\keyman32\k32_res.h" />
<ClInclude Include="..\keyman32\KBD.H" />
<ClInclude Include="..\keyman32\keyman64.h" />
<ClInclude Include="..\keyman32\keymancontrol.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\keynames.h" />
<ClInclude Include="..\keyman32\keyman-debug-etw.h" />
<ClInclude Include="..\keyman32\keyeventsenderthread.h" />
<ClInclude Include="..\keyman32\keystate.h" />
<ClInclude Include="..\keyman32\kmprocessactions.h" />
<ClInclude Include="..\keyman32\kmprot.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\registry.h" />
<ClInclude Include="..\keyman32\pch.h" />
<ClInclude Include="..\keyman32\security.h" />
<ClInclude Include="..\keyman32\serialkeyeventclient.h" />
<ClInclude Include="..\keyman32\serialkeyeventcommon.h" />
<ClInclude Include="..\keyman32\serialkeyeventserver.h" />
<ClInclude Include="..\keyman32\SharedBuffers.h" />
<ClInclude Include="..\keyman32\syskbd.h" />
<ClInclude Include="..\keyman32\testkeymanfunctioning.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\unicode.h" />
<ClInclude Include="..\keyman32\vkscancodes.h" />
</ItemGroup>
<ItemGroup>
<None Include="$(KEYMAN_ROOT)\common\resources\bitmaps\arrow.bmp" />
<None Include="$(KEYMAN_ROOT)\common\resources\bitmaps\mask.bmp" />
<CustomBuild Include="..\keyman32\keyman-debug-etw.man">
<FileType>Document</FileType>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc %(FullPath)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).rc;%(Filename).h;MSG00001.bin</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc %(FullPath)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).rc;%(Filename).h;MSG00001.bin</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling %(Filename).man</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling %(Filename).man</Message>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,89 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\xstring.cpp" />
<ClCompile Include="..\keyman32\appint\aiTIP.cpp" />
<ClCompile Include="..\keyman32\appint\aiWin2000Unicode.cpp" />
<ClCompile Include="..\keyman32\appint\appint.cpp" />
<ClCompile Include="..\keyman32\calldll.cpp" />
<ClCompile Include="..\keyman32\capsstate.cpp" />
<ClCompile Include="..\keyman32\glossary.cpp" />
<ClCompile Include="..\keyman32\hookutils.cpp" />
<ClCompile Include="..\keyman32\K32_DBG.CPP" />
<ClCompile Include="..\keyman32\k32_globals.cpp" />
<ClCompile Include="..\keyman32\K32_load.cpp" />
<ClCompile Include="..\keyman32\k32_tsf.cpp" />
<ClCompile Include="..\keyman32\keybd_shift.cpp" />
<ClCompile Include="..\keyman32\keyboardoptions.cpp" />
<ClCompile Include="..\keyman32\Keyman32.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\keynames.cpp" />
<ClCompile Include="..\keyman32\keystate.cpp" />
<ClCompile Include="..\keyman32\kmhook_callwndproc.cpp" />
<ClCompile Include="..\keyman32\kmhook_getmessage.cpp" />
<ClCompile Include="..\keyman32\kmprocess.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\registry.cpp" />
<ClCompile Include="..\keyman32\pch.cpp" />
<ClCompile Include="..\keyman32\preservedkeymap.cpp" />
<ClCompile Include="..\keyman32\security.cpp" />
<ClCompile Include="..\keyman32\selectkeyboard.cpp" />
<ClCompile Include="..\keyman32\serialkeyeventclient.cpp" />
<ClCompile Include="..\keyman32\serialkeyeventserver.cpp" />
<ClCompile Include="..\keyman32\SharedBuffers.cpp" />
<ClCompile Include="..\keyman32\syskbd.cpp" />
<ClCompile Include="..\keyman32\syskbdnt.cpp" />
<ClCompile Include="$(KEYMAN_ROOT)\common\windows\cpp\src\unicode.cpp" />
<ClCompile Include="..\keyman32\versioninfo.cpp" />
<ClCompile Include="..\keyman32\VKScanCodes.cpp" />
<ClCompile Include="..\keyman32\DebugEventTrace.cpp" />
<ClCompile Include="..\keyman32\kmprocessactions.cpp" />
<ClCompile Include="..\..\global\cpp\kmtip_guids.cpp" />
<ClCompile Include="..\keyman32\CoreEnvironment.cpp" />
<ClCompile Include="..\keyman32\appcontext.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\keyman32\appint\aiTIP.h" />
<ClInclude Include="..\keyman32\appint\aiWin2000Unicode.h" />
<ClInclude Include="..\keyman32\appint\appint.h" />
<ClInclude Include="..\keyman32\calldll.h" />
<ClInclude Include="..\keyman32\capsstate.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\legacy_kmx_file.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\crc32.h" />
<ClInclude Include="..\keyman32\globals.h" />
<ClInclude Include="..\keyman32\hotkeys.h" />
<ClInclude Include="..\keyman32\k32_res.h" />
<ClInclude Include="..\keyman32\KBD.H" />
<ClInclude Include="..\keyman32\keyman64.h" />
<ClInclude Include="..\keyman32\keymancontrol.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\keynames.h" />
<ClInclude Include="..\keyman32\keyman-debug-etw.h" />
<ClInclude Include="..\keyman32\keyeventsenderthread.h" />
<ClInclude Include="..\keyman32\keystate.h" />
<ClInclude Include="..\keyman32\kmprot.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\registry.h" />
<ClInclude Include="..\keyman32\pch.h" />
<ClInclude Include="..\keyman32\security.h" />
<ClInclude Include="..\keyman32\serialkeyeventclient.h" />
<ClInclude Include="..\keyman32\serialkeyeventcommon.h" />
<ClInclude Include="..\keyman32\serialkeyeventserver.h" />
<ClInclude Include="..\keyman32\SharedBuffers.h" />
<ClInclude Include="..\keyman32\syskbd.h" />
<ClInclude Include="..\keyman32\testkeymanfunctioning.h" />
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\unicode.h" />
<ClInclude Include="..\keyman32\vkscancodes.h" />
<ClInclude Include="..\keyman32\keymanengine.h" />
<ClInclude Include="..\keyman32\kmprocessactions.h" />
<ClInclude Include="..\..\..\include\kmtip_guids.h" />
<ClInclude Include="..\keyman32\appcontext.h" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\keyman32\keyman-debug-etw.man" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\keyman32\keyman-debug-etw.rc" />
<ResourceCompile Include="Keyman64.RC" />
</ItemGroup>
<ItemGroup>
<None Include="$(KEYMAN_ROOT)\common\resources\bitmaps\arrow.bmp" />
<None Include="$(KEYMAN_ROOT)\common\resources\bitmaps\mask.bmp" />
</ItemGroup>
</Project>

View file

@ -312,8 +312,8 @@ Fail(PCWSTR message) {
#ifdef _WIN64
#define KEYMAN32 "keyman64.dll"
#define KEYMAN32_DEBUG "keyman64" / "bin" / "x64" / "Debug" / "keyman64.dll"
#define KEYMAN32_RELEASE "keyman64" / "bin" / "x64" / "Release" / "keyman64.dll"
#define KEYMAN32_DEBUG "keyman32" / "bin" / "x64" / "Debug" / "keyman64.dll"
#define KEYMAN32_RELEASE "keyman32" / "bin" / "x64" / "Release" / "keyman64.dll"
#else
#define KEYMAN32 "keyman32.dll"
#define KEYMAN32_DEBUG "keyman32" / "bin" / "Win32" / "Debug" / "keyman32.dll"