Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update USB HID Usage Tables with new System & Consumer keys #901

Conversation

gedankenexperimenter
Copy link
Collaborator

@gedankenexperimenter gedankenexperimenter commented Sep 12, 2020

There has been an update to the USB HID Usage Tables (v1.2), and it includes several new System Control and Consumer Control keys, some of which are being used already by major operating systems. This PR updates Kaleidoscope's copy of the keycodes table, and adds the new Key definitions. I also did some reformatting and added comments to hopefully make the table more readable and make it easier to spot errors.

In addition, I have included changes to make the definition of System Control and Consumer Control keys simpler, and more robust.

This PR includes (and replaces) #899 & #897.

Comment on lines -235 to -240
#define HID_TYPE_LC B00000100
#define HID_TYPE_NARY B00001000
#define HID_TYPE_OOC B00001100
#define HID_TYPE_OSC B00010000
#define HID_TYPE_RTC B00010100
#define HID_TYPE_SEL B00011000
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These HID_TYPE_* constants were being combined with others in the flags byte of both Consumer and System Control Key definitions, but this was incorrect. These bits overlap with the IS_CONSUMER and SWITCH_TO_KEYMAP bits, which are used to detect ConsumerControl and Layer keys, respectively.

For example HID_TYPE_RTC would be detected in Layer.eventHandler() as SWITCH_TO_KEYMAP, and since all of these Key types have the SYNTHETIC bit set, this would result in any System or Consumer keys with usage type RTC triggering a call to Layer.handleKeymapKeyswitchEvent() (which probably wouldn't do anything, because the keycode byte would be out of range, but it's still incorrect). Likewise, any System key with HID_TYPE_OOC would be misidentified as a Consumer key in handleSyntheticKeyswitchEvent(), and the System key's HID report would never get sent.

Copy link
Member

Choose a reason for hiding this comment

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

That indeed sounds like a bug, but one to be fixed, rather than just throwing away the key type data.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think there are enough bits to spare.


/* Most Consumer keys are more then 8bit, the highest Consumer hid code
uses 10bit. By using the 11bit as flag to indicate a consumer keys was activate we can
use the 10 lsb as the HID Consumer code. If you need to get the keycode of a Consumer key
use the CONSUMER(key) macro this will return the 10bit keycode.
*/
#define CONSUMER(key) (key.getRaw() & 0x03FF)
#define CONSUMER_KEY(code, flags) Key((code) | ((flags | SYNTHETIC|IS_CONSUMER) << 8))
#define CONSUMER_KEY(code) Key((code & 0x03FF) | ((SYNTHETIC | IS_CONSUMER) << 8))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a simpler and more correct version of CONSUMER_KEY(). The high six bits should always be the same on any Consumer key, regardless of HID usage type.

Really, I think this should be a static constexpr function inside the Key class: Key::consumer(uint16_t code), rather than a macro, but that requires more extensive code reorganization.

Copy link
Member

Choose a reason for hiding this comment

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

Now that we're using that magic 0x03FF constant more than once, It should get defined as a named constant. Really it should have been one from the beginning.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Excellent point. I'll get on that.

@@ -255,14 +241,15 @@ typedef kaleidoscope::Key Key_;
#define KEY_LEFT_FN2 0xff
#define Key_LFN2 Key(KEY_LEFT_FN2, KEY_FLAGS)

#define SYSTEM_KEY(code) Key(code, SYNTHETIC | IS_SYSCTL)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

To simplify the definition of System Control keys, I added this macro as the counterpart to the existing CONSUMER_KEY() macro below.

@obra
Copy link
Member

obra commented Sep 14, 2020

I'm going to start to break this apart. The data update to the HID table is a no-brainer, but mixing in functionality changes into the same PR makes me a little uneasy. (I'd probably have done the changes to the Consumer and System key macros each as its own PR)

@obra
Copy link
Member

obra commented Sep 14, 2020

All the changes to HIDTables.h are now on master as 9404dcc.

@gedankenexperimenter
Copy link
Collaborator Author

I'm going to start to break this apart. The data update to the HID table is a no-brainer, but mixing in functionality changes into the same PR makes me a little uneasy. (I'd probably have done the changes to the Consumer and System key macros each as its own PR)

I did try to keep the commits separate to make it easy to reconfigure things, since I figured you might want adjustments made.

#define System_MenuHelp Key(HID_SYSTEM_MENU_HELP, KEY_FLAGS | SYNTHETIC|IS_SYSCTL | HID_TYPE_OSC)
#define System_MenuExit Key(HID_SYSTEM_MENU_EXIT, KEY_FLAGS | SYNTHETIC|IS_SYSCTL | HID_TYPE_OSC)
#define System_MenuSelect Key(HID_SYSTEM_MENU_SELECT, KEY_FLAGS | SYNTHETIC|IS_SYSCTL | HID_TYPE_OSC)
#define System_MenuRight Key(HID_SYSTEM_MENU_RIGHT, KEY_FLAGS | SYNTHETIC|IS_SYSCTL | HID_TYPE_RTC)
Copy link
Member

Choose a reason for hiding this comment

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

Not all of the System control keys -are- OSC keys. Even if we're not yet using this data, I really don't want to just discard it from the tables.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The problem is that the HID_TYPE_* bits overlap with other bits that are in use in the flags byte of a Key object. If you include HID_TYPE_OOC, you're also including IS_CONSUMER along with it. handleSyntheticKeyswitchEvent() could be changed to check for System keys before Consumer keys to solve that problem, but Consumer keys can't use those HID_TYPE_* constants.

Copy link
Member

Choose a reason for hiding this comment

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

I want @algernon's input before I sign off on it, but I think I'd be ok with a solution where, for now, we define all the HID_TYPE_XX constants to 0, rather than just removing them from the key definitions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Correction: we can't solve it by changing handleSyntheticKeyswitchEvent(), because Consumer keys might have the IS_SYSCTL bit set, depending on the value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think we could call out four HID types (using the two bits above IS_CONSUMER and below SYNTHETIC). Or a default, and three that get special handling.

Copy link
Member

Choose a reason for hiding this comment

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

I'd rather defer the exact bit math until we understand our needs.

@gedankenexperimenter
Copy link
Collaborator Author

@obra – At this point, would you like me to rebase this PR onto the master branch?

@obra
Copy link
Member

obra commented Sep 14, 2020 via email

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
These shouldn't have been added in the first place.

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
`KEY_FLAGS` is just 0, so was just extra clutter, and `HID_TYPE_*`
shouldn't be there in the first place, as it can cause a System
Control key to be marked as a Consumer Control key.

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
These constants may have served a purpose at some point, but now all
they can accomplish is causing a System key of usage type OOC to get
misidentified as a Consumer key (since `HID_TYPE_OOC` has the
`IS_CONSUMER` bit set).

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
There were a few minor problems in the way Consumer `Key` objects were
constructed (using `CONSUMER_KEY()`). First, no masking of the high
bits was being done, so it was possible to create a "Consumer" key
with the `RESERVED` bit set (e.g. `Key_Transparent`), or the
`SWITCH_TO_KEYMAP` bit (in fact, any `Key` value with both the
`SYNTHETIC` and `IS_CONSUMER` bits set was possible).

Second, the high six bits of the raw `Key` value should always be
`010010` (`SYNTHETIC | IS_CONSUMER`), as Consumer keys don't have any
flags. The macro should really only take one argument: a 16-bit
integer keycode value. The `HID_TYPE_*` constants really shouldn't be
used at all in defining the keys in key_defs_consumer.h, because
setting those bits could potentially cause a key to be misidentified
by some plugin.

This change fixes these potential problems by ignoring the `flags`
parameter, masking the high six bits of the `code` supplied, and
setting those high six bits to the correct value.

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
They are now all set to 0 to avoid conflicts with other flags bits,
and I've added a `HID_TYPE_MASK` constant to use when constructing
System and Consumer keys.

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
@gedankenexperimenter
Copy link
Collaborator Author

I've done a rebase in my working repository. I'm checking it now to make sure I didn't screw anything up in the process, then I'll force-push the new version.


/* Most Consumer keys are more then 8bit, the highest Consumer hid code
uses 10bit. By using the 11bit as flag to indicate a consumer keys was activate we can
use the 10 lsb as the HID Consumer code. If you need to get the keycode of a Consumer key
use the CONSUMER(key) macro this will return the 10bit keycode.
*/
#define CONSUMER(key) (key.getRaw() & 0x03FF)
#define CONSUMER_KEY(code, flags) Key((code) | ((flags | SYNTHETIC|IS_CONSUMER) << 8))
constexpr uint16_t CONSUMER_KEYCODE_MASK = 0x03FF;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Magic number replaced with defined constant. The official code style guide says it should be named kConsumerKeycodeMask, but that style isn't used anyplace else in Kaleidoscope that I can find, so I'm leaving it in all caps for the moment.

#define HID_TYPE_SEL B00000000
#define HID_TYPE_SV B00000000
// Mask defining the allowed usage type flag bits:
#define HID_TYPE_MASK B00110000
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These are the only two non-conflicting bits available. Enough for a base 00 default, and three "special" usage types (01, 10, 11), to be defined later.

Comment on lines +263 to +264
#define SYSTEM_KEY(code, hid_type) \
Key(code, SYNTHETIC | IS_SYSCTL | (hid_type & HID_TYPE_MASK))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've added back in the HID Usage Type parameter. I'm using the HID_TYPE_MASK to ensure that only the allowed bits can be set in the flags byte.

Comment on lines +273 to +275
#define CONSUMER_KEY(code, hid_type) \
Key((code & CONSUMER_KEYCODE_MASK) | \
((SYNTHETIC | IS_CONSUMER | (hid_type & HID_TYPE_MASK)) << 8))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

HID Usage Type parameter also added here.

@obra obra mentioned this pull request Oct 4, 2020
@obra
Copy link
Member

obra commented Oct 4, 2020

I've just spent a couple hours working through this PR, rewriting the history to contain separable logical changes, since the flow got a little hard to follow with the rework.

Closing in favor of #915

@obra obra closed this Oct 4, 2020
@gedankenexperimenter gedankenexperimenter deleted the usb-hid-tables-update branch October 27, 2020 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants