Skip to content

feat(common/core/desktop): Allow preserved key support#5850

Merged
rc-swag merged 17 commits intomasterfrom
feat/windows/preserved-key-support
Nov 29, 2021
Merged

feat(common/core/desktop): Allow preserved key support#5850
rc-swag merged 17 commits intomasterfrom
feat/windows/preserved-key-support

Conversation

@rc-swag
Copy link
Copy Markdown
Contributor

@rc-swag rc-swag commented Oct 22, 2021

Fixes: #5777

Add km_kbp_keyboard_get_key_rules to get a list of virtual keys and the shift modifiers that are used in the keyboard rules.
The data structure for each item in the list is

typedef struct {
  km_kbp_virtual_key key;   // The key the belongs
  uint32_t modifier_flag;   // modifier flag for the rule
} km_kbp_keyboard_key_rules;

There is more information in the kmx processor implmentation for a key. Line; dpOutput; dpContext;. These seemed to be processor specific, and they are coupled to Group again which is a kmx specific rule layout. I wasn't sure what would be useful to have in a list of "keys". So if I am after guidance if this data structure should contain more information in this public api call to make it a more useful API call. The other option would be to make this an encode/decode pair with the structured data type which would then allow more info to be added to km_kbp_keyboard_key_rules without breaking previous implementations. That is it would be backward compatible.

User Testing

All tests are for keyman for windows.

TEST_PRESERVEDKEYS
This is to test the key rules which contain AltGr or Shift + AltGr work correctly.

  • Load a keyboard khmer_angkor

  • Open LibreOffice or Notepad

  • Type a AltGr + o

  • Observere output of ឱ​

  • Type a Shift + AltGr + o

  • Observere output of ᧨

@keymanapp-test-bot keymanapp-test-bot bot added the user-test-required User tests have not been completed label Oct 22, 2021
@keymanapp-test-bot
Copy link
Copy Markdown

keymanapp-test-bot bot commented Oct 22, 2021

User Test Results

Test specification and instructions

  • TEST_PRESERVEDKEYS (PASSED): The characters are output per instructions given, see the screenshot below. (notes)

Test Artifacts

@rc-swag rc-swag marked this pull request as ready for review October 29, 2021 07:31
@darcywong00 darcywong00 added this to the A15S17 milestone Oct 30, 2021
@darcywong00 darcywong00 changed the title Feat/windows/preserved key support feat(common/core/desktop) Allow preserved key support Nov 1, 2021
@darcywong00 darcywong00 changed the title feat(common/core/desktop) Allow preserved key support feat(common/core/desktop): Allow preserved key support Nov 2, 2021
Comment on lines +757 to +768


void km_kbp_keyboard_key_list_dispose(km_kbp_keyboard_key *key_list);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to document this function too 😉

Comment on lines +45 to +76
km_kbp_keyboard_key *key_rule_it = kb_key_list;
auto n = 0;
for (; key_rule_it->key; ++key_rule_it) {
++n;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we assert the values returned as well? I would also like to see a test for a more complex keyboard with multiple groups and with the same keys referred in multiple groups (to validate that we don't list keys more than once). We cannot assume the list order so will need to be careful on testing results!

Comment on lines +476 to +477
} else {
if (!_td->lpActiveKeyboard->Keyboard) {
return FALSE;
}
return pkm.MapKeyboard(_td->lpActiveKeyboard->Keyboard, pPreservedKeys, cPreservedKeys);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add the issue number for future removal of this code and related functions?

@github-actions github-actions bot added the feat label Nov 7, 2021
@mcdurdin
Copy link
Copy Markdown
Member

Jenkins failure:

[2021-11-09T09:18:44.341Z] 55/57 key_list                                FAIL     0.01 s
[2021-11-09T09:18:44.341Z] 
[2021-11-09T09:18:44.341Z] --- command ---
[2021-11-09T09:18:44.341Z] /<<PKGBUILDDIR>>/common/core/desktop/build/arch/release/tests/unit/kmx/key_list /<<PKGBUILDDIR>>/common/core/desktop/build/arch/release/tests/unit/kmx
[2021-11-09T09:18:44.341Z] --- stderr ---
[2021-11-09T09:18:44.341Z] Test failed with 7 at ../../../tests/unit/kmx/kmx_key_list.cpp:46:
[2021-11-09T09:18:44.341Z]   km_kbp_keyboard_load(full_path.native().c_str(), &test_kb)

@rc-swag rc-swag marked this pull request as draft November 11, 2021 05:26
@@ -0,0 +1,28 @@
c Description: Tests multiple groups. Purpose here is to interleave output and backspaces from kmx processor to consumer
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this test doesn't run (because it's not listed in meson.build). I see that it's used in kmx_key_list.cpp. If it's intended to be used only from that test than IMO it would be better and less confusing to rename it to kmx_key_list.kmn or something like that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, when I was first setting it up I as going to create a new expected key list comment to go in the header of the kmn so that it would test with kmx.cpp. I ended up with having it all testested from kmx_key_list.cpp I will rename this to the suggested name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ermshiperete I fixed the what I thought where the issues with kmx_key_list and the meson.build, but the jenkins build is still failing. Can you also add my user to the build so I can view it in Jenkins?

@mcdurdin mcdurdin modified the milestones: A15S17, A15S18 Nov 14, 2021
@rc-swag rc-swag marked this pull request as ready for review November 15, 2021 03:39
Copy link
Copy Markdown
Contributor

@ermshiperete ermshiperete left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like 049 - groups ctrlalt.kmx is still present!?

return 1;
}

km_kbp_keyboard_key kb_key_expected_list[] = {{49,16384},{50,16384},{66,16416},{67,16384},{67,16448},{97,0},{98,0}};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test might be easier to understand if we'd use the KM_KBP_VKEY_* and KM_KBP_MODIFIER_* consts here, especially when looking at the .kmn file and trying to understand the expected list here.

return TRUE;
}

if (*cPreservedKeys < cKeys) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we set *cPreservedKeys = cKeys here as well?

Copy link
Copy Markdown
Contributor Author

@rc-swag rc-swag Nov 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get to this if statement it means the size of the array of PreservedKeys pPreservedKeys is going to be big enough to store all the keys. So it returns False.

When ::MapKeyboardCore is called if pPreservedKeys is NULL, we set *cPreservedKeys to the size pPreservedKeys needs to be.

So in the other cases we don't set cPreservedKeys

++cRules;
}
cKeys = cRules;
if (cKeys == 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we set *cPreservedKeys = cKeys here as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could check if pPreservedKeys == NULL and set *cPreservedKeys = cKeys basically setting it to zero. but in this case we are returning FALSE anyway. So if the function is returning FALSE for failure, I don't think the *cPreservedKeys should be trusted.
This also mimics the behaviour of the current ::MapCore

Copy link
Copy Markdown
Member

@mcdurdin mcdurdin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM

@MakaraSok
Copy link
Copy Markdown

  • TEST_PRESERVEDKEYS: PASSED The characters are output per instructions given, see the screenshot below.

image

@keymanapp-test-bot keymanapp-test-bot bot removed the user-test-required User tests have not been completed label Nov 16, 2021
@rc-swag
Copy link
Copy Markdown
Contributor Author

rc-swag commented Nov 16, 2021

@mcdurdin The comment @ermshiperete made about using constants instead of magic numbers in the kmx_list.cpp raised an issue. I now realise what I am putting in the km_kbp_keyboard_key is not a "virtual key" but kmx KEY that can either be a "Virtual Key" or a "Character Code" determined by the modifier flag KM_KBP_MODIFIER_VIRTUALKEY. So we have a kmx engine detail in the keyboard_processor API. This is not good. I then spent some time thinking how I could change this but I wasn't sure what we should do?

@mcdurdin
Copy link
Copy Markdown
Member

I now realise what I am putting in the km_kbp_keyboard_key is not a "virtual key" but kmx KEY that can either be a "Virtual Key" or a "Character Code" determined by the modifier flag KM_KBP_MODIFIER_VIRTUALKEY. So we have a kmx engine processor detail in the keyboard_processor Keyman Core API.

Two possible solutions. I lean towards the first.

Translate the characters to US vkeys before returning from kmx processor

This is probably the cleanest way to solve the issue. MapUSCharToVK is defined in preservedkeymap.cpp and CharToKeyConversion.cpp (which we should consolidate...), so that'll need to be ported over to kmx processor.

        v_key = p_group->dpKeyArray[j].Key;
        modifier_flag = p_group->dpKeyArray[j].ShiftFlags;
        if(modifier_flag == 0) {
          if(!MapUSCharToVK(&v_key, &modifier_flag)) continue;
        }
  
        map_rules[std::make_pair(v_key,modifier_flag)] = modifier_flag;

Live with it

This alternative is also okay, although not great.

We have many kmx processor details that inform the design of the Keyman Core API. The fact that the kmx processor can report chars as well as vkeys should be documented, not ignored :-).

However, let's split out the char pattern as a separate bit property rather than encoding it into the modifier_flag:

typedef struct {
  
  km_kbp_virtual_key key;   /// a virtual key, or an ASCII character if `is_character` is non-zero.
  uint16_t modifier_state;  /// bitmask from `km_kbp_modifier_state` enum 
  uint8_t is_character;     /// if non-zero, `key` is an ascii character corresponding to
                            /// the US English key cap (shifted or unshifted), and
                            /// `modifier_state` is ignored.
} km_kbp_keyboard_key;

(Noted also, use modifier_state not modifier_flag, and it should be uint16_t not uint32_t!)

That hides the worst of the implementation details (a modifier_state that included the KM_KBP_MODIFIER_VIRTUALKEY flag would differs from all other uses of modifiers in the API -- ignoring debug api which is a bit special anyway). If other engines don't need to list chars in this API, then that's fine; the is_character field will be 0 in those cases.

@mcdurdin mcdurdin marked this pull request as draft November 18, 2021 02:32
@mcdurdin
Copy link
Copy Markdown
Member

Per discussion, moving back to draft to eliminate use of characters in place of virtual keys outside the boundaries of kmx processor.

@rc-swag rc-swag marked this pull request as ready for review November 23, 2021 04:30
@rc-swag
Copy link
Copy Markdown
Contributor Author

rc-swag commented Nov 23, 2021

Per discussion, moving back to draft to eliminate use of characters in place of virtual keys outside the boundaries of kmx processor.

This work has now been done and ready for re-review.

@mcdurdin
Copy link
Copy Markdown
Member

mcdurdin commented Nov 29, 2021

Jenkins error:

[2021-11-23T04:36:16.697Z] ../../../common/core/desktop/src/kmx/ibus_keyman_tests-kmx_processor.o: In function `km::kbp::kmx_processor::get_key_list() const':

[2021-11-23T04:36:16.697Z] ./linux/ibus-keyman/tests/../../../common/core/desktop/src/kmx/kmx_processor.cpp:221: undefined reference to `km::kbp::kmx::MapUSCharToVK(unsigned short, unsigned short*, unsigned int*)'

[2021-11-23T04:36:16.697Z] collect2: error: ld returned 1 exit status

This suggests kmx_conversion.cpp needs to be added to linux\ibus-keyman\tests\Makefile.am. (It's a shame we are not using meson here!)

@rc-swag rc-swag force-pushed the feat/windows/preserved-key-support branch from c154681 to cfed6f1 Compare November 29, 2021 00:55
@rc-swag rc-swag merged commit 13fc2bf into master Nov 29, 2021
@rc-swag rc-swag deleted the feat/windows/preserved-key-support branch November 29, 2021 04:48
@ermshiperete
Copy link
Copy Markdown
Contributor

It's a shame we are not using meson here!

Indeed. I have it on my to-do list though 😄 - probably should create an issue for it: #5981

@keyman-server
Copy link
Copy Markdown
Collaborator

Changes in this pull request will be available for download in Keyman version 15.0.157-alpha

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(windows): Implement an API call in common core so that a platform engine can register preserved keys.🥑

6 participants