Skip to content

Commit

Permalink
Move to HID usage-page-based detection (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
donn authored Apr 20, 2023
1 parent 9963d24 commit 3b31ee8
Show file tree
Hide file tree
Showing 13 changed files with 137 additions and 45 deletions.
35 changes: 35 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Bug Report
description: If Nudelta is not behaving as expected, please report here.
body:
- type: input
id: nudelta-version
attributes:
label: Version
description: What version of Nudelta are you using?
placeholder: "0.7.0"
validations:
required: true
- type: textarea
id: environment-report
attributes:
label: Operating System
description: |
Which operating system are you using and what is its version?
* Windows - Pressing Windows+R and then type "winver" then press "Ok"
in the window that pops up. You should see something like
`Version XXXX (OS Build XXXXX.XXXX)`. Please copy that here.
* macOS - From the Apple menu, press About this Mac, and screenshot the
Window that pops up. Please remember to hide your serial number using
the screenshot editor or Preview.
* Linux - in your terminal of choice, paste `uname -a` then paste the output
here. Please also mention the distribution and version.
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: What went wrong? Be clear and concise.
validations:
required: true
10 changes: 10 additions & 0 deletions .github/ISSUE_TEMPLATE/requests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: Feature Requests and Enhancements
description: Have any ideas? Find any shortcomings? Feel free to share them.
body:
- type: textarea
id: prompt
attributes:
label: Description
description: Is there anything currently not in Nudelta that you'd like to see added?
validations:
required: true
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ jobs:
* Please note that you will need Rosetta as there is no Apple Silicon build at the moment.
On Linux, download the `.AppImage`, enable "allow executing file as program" in its properties (shown below), then double-click it.
* You may need to install `libudev` separately- on Ubuntu, you can run `sudo apt-get install -y libudev`.
![Setting Linux execute permission with the GNOME File Browser](https://raw.githubusercontent.com/donn/nudelta/main/res/linux_exec_permission.png)
files: |
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ dist/
*.AppImage
yarn-error.log

!OSAcknowledgements.txt
!OSAcknowledgements.txt

# Python
venv
11 changes: 6 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ set(PROJECT_VERSION ${NUDELTA_VERSION})

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_OSX_ARCHITECTURES x86_64)

set(HIDAPI_WITH_LIBUSB TRUE)
set(HIDAPI_WITH_HIDRAW FALSE)
set(HIDAPI_WITH_LIBUSB FALSE)
set(HIDAPI_WITH_HIDRAW TRUE)
set(BUILD_SHARED_LIBS FALSE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

Expand Down Expand Up @@ -44,7 +45,7 @@ file(GLOB nudelta_lib_src "lib/*.cpp")
add_library(nd ${nudelta_lib_src} ${CMAKE_CURRENT_BINARY_DIR}/res.cpp)
add_dependencies(nd res_file)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(nd PRIVATE hidapi::libusb)
target_link_libraries(nd PRIVATE hidapi::hidraw)
else ()
target_link_libraries(nd PRIVATE hidapi)
endif ()
Expand All @@ -65,7 +66,7 @@ if (NODE_RUNTIME)
include_directories(${CMAKE_SOURCE_DIR}/node_modules/node-api-headers/include)
add_library(node-libnd SHARED src/node.cpp ${CMAKE_JS_SRC})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(node-libnd PRIVATE hidapi::libusb)
target_link_libraries(node-libnd PRIVATE hidapi::hidraw)
else ()
target_link_libraries(node-libnd PRIVATE hidapi)
endif ()
Expand All @@ -83,7 +84,7 @@ add_executable(nudelta src/main.cpp)
add_compile_definitions(NUDELTA_VERSION="${CMAKE_PROJECT_VERSION}")
target_link_libraries(nudelta PRIVATE nd)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(nudelta PRIVATE hidapi::libusb)
target_link_libraries(nudelta PRIVATE hidapi::hidraw)
else ()
target_link_libraries(nudelta PRIVATE hidapi)
endif ()
Expand Down
6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 0.7.0
- Updated to fix a bug for macOS 13.3 or higher
- Linux builds now use `hidraw` instead of `libusb` so the detection mechanism
remains identical for macOS and Linux
- libhidapi gives access to `usage` and `usage_page` only when using `hidraw`
on Linux
# 0.6.7
- Add a no-verify CLI flag so unsupported keyboards can still dump data.
- Reorder the keycodes for consistency
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ RUN n 14
RUN npm i -g yarn

## LibUSB
RUN yum install -y libusbx-devel
RUN yum install -y libudev-devel

##
WORKDIR /nudelta
Expand Down
8 changes: 3 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
</p>


> Note: This software is in beta. Nudelta is an unofficial product and is not affiliated with NuPhy Studio.
> Note: This software is in beta. NuPhy® is a registered trademark of NuPhy Studio.
> Nudelta is an unofficial product and is not affiliated with NuPhy Studio.


Expand All @@ -21,8 +22,7 @@
An open-source alternative to the [NuPhy Console](https://nuphy.com/pages/nuphy-console) created by reverse-engineering the keyboards' USB protocol.

What this has:
* Support for NuPhy Air75 on Windows 10+, macOS 11+, and Linux
* ALPHA support for the NuPhy Halo75
* Support for NuPhy Air75 and Halo75 on Windows 10+, macOS 11+, and Linux
* Loading and saving keymap modifications from a `.yml` configuration file
* The ability to back up and dump keymaps to binary formats (CLI)
* The ability to dump keymaps to a human-readable hex format (CLI)
Expand Down Expand Up @@ -103,5 +103,3 @@ nudelta -r

## License
The GNU General Public License v3 or, at your option, any later version. Check '[License](/License)'.

> NuPhy® is a registered trademark of NuPhy Studio.
36 changes: 33 additions & 3 deletions lib/nuphy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <algorithm>
#include <scope_guard.hpp>
#include <sstream>
#include <yaml-cpp/yaml.h>

NuPhy::Handles NuPhy::getHandles() {
Expand Down Expand Up @@ -148,8 +149,36 @@ static std::shared_ptr< NuPhy > createKeyboard(
return nullptr;
}

std::string represent_hid_struct(hid_device_info *info) {
std::stringstream str;

str << std::hex;

str << "At path: " << info->path << std::endl;
str << "VID/PID: " << info->vendor_id << ":" << info->product_id
<< std::endl;
if (info->serial_number != nullptr) {
str << "SN: " << info->serial_number << std::endl;
}
str << "Release: " << info->release_number << std::endl;
if (info->manufacturer_string != nullptr) {
str << "Manufacturer String: " << to_utf8(info->manufacturer_string)
<< std::endl;
}
if (info->product_string != nullptr) {
str << "Product String: " << to_utf8(info->product_string) << std::endl;
}
str << "Usage/Page: " << info->usage << "/" << info->usage_page
<< std::endl;
str << "Interface Number: " << std::dec << info->interface_number
<< std::endl;
str << "---" << std::endl;
return str.str();
}

#ifdef _WIN32
// Win is different: there are multiple "channels" each with a different path
// Win is different: there are multiple "channels" each with a different
// path
// - So far, I've identified col06 as the one for keymap data, col05 for
// requests
std::string writeCol = "col05";
Expand All @@ -168,7 +197,7 @@ std::shared_ptr< NuPhy > NuPhy::find(bool verify) {
std::optional< std::string > requestPath;

while (seeker != nullptr) {
if (seeker->interface_number == 1 && seeker->usage == 1
if (seeker->interface_number != -1 && seeker->usage == 1
&& seeker->usage_page == 0xFF00
&& (!productName.has_value()
|| productName.value() == to_utf8(seeker->product_string))) {
Expand Down Expand Up @@ -233,7 +262,8 @@ std::shared_ptr< NuPhy > NuPhy::find(bool verify) {
bool multipleWarned = false;
std::string productString = "";
while (seeker != nullptr) {
if (seeker->interface_number == 1) {
if (seeker->interface_number != -1 && seeker->usage == 1
&& seeker->usage_page == 0xFF00) {
if (keyboard != nullptr) {
// We only care if the path is different, because that means a
// different device on Mac and Linux
Expand Down
12 changes: 3 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "nudelta",
"author": "Mohamed Gaber <me@donn.website>",
"version": "0.6.7",
"version": "0.7.0",
"license": "GPL-3.0-or-later",
"homepage": "https://github.com/donn/nudelta#readme",
"description": "An open-source alternative to the NuPhy Console",
Expand All @@ -23,7 +23,7 @@
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-url": "^8.0.1",
"@rollup/plugin-yaml": "^4.0.1",
"cmake-js": "^7.1.1",
"cmake-js": "^7.2.1",
"electron": "^21.2.1",
"electron-builder": "^23.6.0",
"fast-glob": "^3.2.12",
Expand Down Expand Up @@ -52,12 +52,6 @@
"linux": {
"target": [
"appimage"
],
"extraFiles": [
{
"from": "/lib64/libusb-1.0.so.0",
"to": "usr/lib/libusb-1.0.so.0"
}
]
},
"mac": {
Expand All @@ -76,4 +70,4 @@
"tabWidth": 4,
"quoteProps": "consistent"
}
}
}
5 changes: 2 additions & 3 deletions shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
pkgs ? import <nixpkgs> {}
}:

with pkgs; (mkShell.override { stdenv = clangStdenv; }) {
with pkgs; (mkShell.override { stdenv = if stdenv.isDarwin then darwin.apple_sdk_11_0.stdenv else clangStdenv; }) {
packages = [
nodejs
yarn
cmake
gnumake
libusb
pkg-config
electron
];
] ++ (if stdenv.isDarwin then [darwin.apple_sdk_11_0.frameworks.IOKit darwin.apple_sdk_11_0.frameworks.AppKit] else [udev]);
}
13 changes: 11 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
#include <iostream>
#include <scope_guard.hpp>
#include <ssco.hpp>
#ifdef _MSC_VER
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#else
#include <unistd.h>
#endif

#define MAX_STR 255
#ifndef NUDELTA_VERSION
Expand Down Expand Up @@ -78,7 +84,7 @@ SSCO_Fn(resetKeymap) {
SSCO_Fn(dumpKeymap) {
auto mac = opts.options.find("mac") != opts.options.end();
auto verify = opts.options.find("no-verify") == opts.options.end();

auto keyboard = getKeyboard(verify);
auto keys = keyboard->getKeymap(mac);
auto file = opts.options.find("dump-keys")->second;
Expand Down Expand Up @@ -143,7 +149,10 @@ SSCO_Fn(loadKeymap) {
};

uint8_t readBuffer[1024];
fread(readBuffer, 1, sizeof readBuffer, filePtr);
ssize_t readResult = fread(readBuffer, 1, sizeof readBuffer, filePtr);
if (readResult < 0) {
throw std::runtime_error("Failed to read the keymap file.");
}

// ALERT: Endianness-defined Behavior
auto keymap = std::vector< uint32_t >(
Expand Down
38 changes: 22 additions & 16 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -460,13 +460,14 @@ at-least-node@^1.0.0:
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==

axios@^0.27.2:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
axios@^1.3.2:
version "1.3.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024"
integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==
dependencies:
follow-redirects "^1.14.9"
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"

balanced-match@^1.0.0:
version "1.0.2"
Expand Down Expand Up @@ -720,17 +721,17 @@ clone-response@^1.0.2:
dependencies:
mimic-response "^1.0.0"

cmake-js@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-7.1.1.tgz#7935210efe0d562bbb02a7fde445d147e9eb4523"
integrity sha512-2NK9diAsNC0eIeKUUi+eN8uxCJukZ0TlMNZ8f1Z2PEW3Oeh0Tmn0VizPayFVnhrvZQcBK8tPqzrL4oHeaQBymw==
cmake-js@^7.2.1:
version "7.2.1"
resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-7.2.1.tgz#757c0d39994121b084bab96290baf115ee7712cd"
integrity sha512-AdPSz9cSIJWdKvm0aJgVu3X8i0U3mNTswJkSHzZISqmYVjZk7Td4oDFg0mCBA383wO+9pG5Ix7pEP1CZH9x2BA==
dependencies:
axios "^0.27.2"
axios "^1.3.2"
debug "^4"
fs-extra "^10.1.0"
lodash.isplainobject "^4.0.6"
memory-stream "^1.0.0"
node-api-headers "^0.0.1"
node-api-headers "^0.0.2"
npmlog "^6.0.2"
rc "^1.2.7"
semver "^7.3.8"
Expand Down Expand Up @@ -1199,7 +1200,7 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"

follow-redirects@^1.14.9:
follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
Expand Down Expand Up @@ -1938,10 +1939,10 @@ node-addon-api@^5.0.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501"
integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==

node-api-headers@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-0.0.1.tgz#e49821048943e50d5b93bc12ada0dd072d2b0769"
integrity sha512-eRxckUSXMRQRV69h+ksfleQzR3BdRwkJuc/Y65KFFwhibC5G1y6wgytYW2WWTB/oG1bt+pf2RwjZDYC0xKqgqQ==
node-api-headers@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-0.0.2.tgz#31f4c6c2750b63e598128e76a60aefca6d76ac5d"
integrity sha512-YsjmaKGPDkmhoNKIpkChtCsPVaRE0a274IdERKnuc/E8K1UJdBZ4/mvI006OijlQZHCfpRNOH3dfHQs92se8gg==

nodemon@^2.0.9:
version "2.0.9"
Expand Down Expand Up @@ -2135,6 +2136,11 @@ proto-list@~1.2.1:
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=

proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==

pstree.remy@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
Expand Down

0 comments on commit 3b31ee8

Please sign in to comment.