2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【サ終】Canon LS-120TK III (電卓10キー)をmacOSで使えるようにする (環境の変化と戦う⑥)

Last updated at Posted at 2025-12-22

はじめに

はじめに

不定期で開催されるクラフェスの電子工作(分解教室)用の材料集めメモです。

2025.11.24

HARDOFF

八王子大和田店でCanon LS-120TK IIIを入手しましたが、既に【サ終】(サポート終了)となっているデバイスです。

Canon LS-120TK III

WindowsとLinux (Raspberry Pi)では標準ドライバーで正常に認識され、テンキー(キーボード)として使用できました。

しかし、macOSではUSBデバイスとして認識はされましたが、テンキーとして使用できませんでした。

$ system_profiler SPUSBDataType
USB:
    USB 3.1 Bus:

      Host Controller Driver: AppleT8103USBXHCI

        Composite Device:

          Product ID: 0x6523
          Vendor ID: 0x1267
          Version: 1.10
          Speed: Up to 1.5 Mb/s
          Location ID: 0x01100000 / 1
          Current Available (mA): 500
          Current Required (mA): 100
          Extra Operating Current (mA): 0

正確に言うと、電卓に「PC/計算」(電卓とPC入力モードを切り替える)ボタンが付いているのですが、押しても反応しない(PC入力モードに切り替えられない)状態でした。

調査

Canon LS-120TK IIIをmacOSで使用している事例を調査したところ、古いブログページが見つかりました。

DentakuTenkeyというソフトウェアをインストールすれば動作するようですが、古いホームページで既にリンク先(GeoCities)が【サ終】(2019年3月末にサービス終了)になっていました。

インターネットアーカイブサイトで入手

インターネットアーカイブサイトの「Wayback Machine - Internet Archive」でソフトウェアの入手に成功しました。

MacOS X 10.6までしか対応していないため、当然、Macbook Air M1 (macOS Sequoia 15.7.3)にはインストールすらできませんでしたが、ソースコードが付属していたため、Xcodeでビルドすることにしました。

Xcodeでのビルドに失敗

IOKit/hid/IOHIDEvent.h file not foundというエラーが発生しました。

ChatGPTに聞いたところ、Appleが仕様変更で非公開(Private API)扱いにし、Xcode 15 / macOS 14(Sonoma) で遮断したとのことでした。

Xcodeでのビルドに成功するもkextloadに失敗

MacKernelSDKをダウンロードして、不足しているヘッダーファイルを取り込んだところビルドは成功しました。

しかし、実際に/sbin/kextloadコマンドを実行したところ、エラー「failed to load (libkern/kext) not found」が発生しました。

Karabiner-Elementsを試す

古いブログページの記載がヒントになりました。

「KeyRemap4MacBookをベースにタイトルのソフトを作ってみました。」

「KeyRemap4MacBook」は現在「Karabiner」になっています。

ということで、Karabiner-Elementsをインストールして試してみましたが、デバイスをPC入力モードに変更できないと、そもそもmacOS側でキー入力を検知できませんでした。

解析

ソフトウェアを動かすことを諦めて、正常に動作しているデバイスの通信を解析して、直接デバイスを制御する方針に変更しました。

デバイスが正常に動作しているLinux (Raspberry Pi)でUSB (HID)の通信をキャプチャーします。
USBトラフィックをモニタリングするために、usbmonモジュールをロードします。

$ sudo modprobe usbmon

WiresharkでUSBトラフィックをキャプチャーします。

$ sudo apt install wireshark
$ sudo wireshark

スクリーンショット 2025-12-21 22.54.29.png

無事にデバイスの初期化ログを取得できました。

08:45:35.223123 USB CONTROL SUBMIT to 1:5:0			
08:45:35.224380 USB CONTROL COMPLETE from 1:5:0			
	0x0000:  1201 1001 0000 0008 6712 2365 1001 0000  ........g.#e....		
	0x0010:  0001                                     ..		
08:45:35.224432 USB CONTROL SUBMIT to 1:5:0			
08:45:35.225502 USB CONTROL COMPLETE from 1:5:0			
	0x0000:  0902 2200 0101 0080 32                   ..".....2		
08:45:35.225534 USB CONTROL SUBMIT to 1:5:0			
08:45:35.227323 USB CONTROL COMPLETE from 1:5:0			
	0x0000:  0902 2200 0101 0080 3209 0400 0001 0301  ..".....2.......		
	0x0010:  0100 0921 1001 0001 2241 0007 0581 0308  ...!...."A......		
	0x0020:  000a                                     ..		
08:45:35.229038 USB CONTROL SUBMIT to 1:5:0			
08:45:35.229762 USB CONTROL COMPLETE from 1:5:0			
08:45:35.230455 USB CONTROL SUBMIT to 1:5:0			
08:45:35.232276 USB CONTROL COMPLETE from 1:5:0			
08:45:35.232329 USB CONTROL SUBMIT to 1:5:0			
08:45:35.235151 USB CONTROL COMPLETE from 1:5:0			
	0x0000:  0501 0906 a101 0507 19e0 29e7 1500 2501  ..........)...%.		
	0x0010:  9508 7501 8102 9508 7501 8101 0508 1901  ..u.....u.......		
	0x0020:  2905 9505 7501 9102 9501 7503 9101 0507  )...u.....u.....		
	0x0030:  1900 2aff 0015 0026 ff00 9506 7508 8100  ..*....&....u...		
	0x0040:  c0                                       .		
08:45:35.238150 USB CONTROL SUBMIT to 1:5:0			
	0x0000:  00		

PC入力モードに切り替える代替え手段

結果的に古いブログページの記載がヒントになりました。

「デバイス情報からは一般的なキーパッドの様な感じでしたので、LED辺りを操作してやれば動くのでは?と試してみた所、接続時にNumLock LEDをONするコードを送ってやれば良い様です。」

setledsmac

HIDデバイスへNumLock LEDをONする方法をChatGPTへ聞いたところ、setledsmacツールをインストールする方法です。

$ git clone https://github.com/damieng/setledsmac.git
$ cd setledsmac/Source/SetLEDs
$ make
$ ./setleds +num

実行したところ、残念ながらキーボードとして認識していない(HID(キーボード)としてデバイス名が見えていない)ため失敗しました。

% ./setleds +num
SetLEDs version 0.4 - https://github.com/damieng/setledsmac

 "Apple Internal Keyboard / Trackpad" +num 

コードを作成

次にHIDデバイスへNumLock LEDをONするソースコードをChatGPTに作成してもらいました。

ソースコード
hid_set_numlock.c
// hid_set_numlock.c
// Build: clang hid_set_numlock.c -o hid_set_numlock -framework IOKit -framework CoreFoundation
// Usage: sudo ./hid_set_numlock 0x1267 0x6523 0x01100000

#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDManager.h>
#include <stdio.h>
#include <stdlib.h>

static int hex_or_dec(const char* s) {
    // accepts "0x...." or decimal
    return (int)strtol(s, NULL, 0);
}

static void print_cfstring(CFStringRef s) {
    if (!s) { printf("(null)"); return; }
    char buf[512];
    if (CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8)) printf("%s", buf);
    else printf("(cfstring)");
}

int main(int argc, char** argv) {
    if (argc < 4) {
        fprintf(stderr, "Usage: %s <vid> <pid> <location_id>\n", argv[0]);
        fprintf(stderr, "Example: %s 0x1267 0x6523 0x01100000\n", argv[0]);
        return 1;
    }

    int vid = hex_or_dec(argv[1]);
    int pid = hex_or_dec(argv[2]);
    int loc = hex_or_dec(argv[3]);

    IOHIDManagerRef mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);

    // Matching dict: vendor/product (Apple docs: kIOHIDVendorIDKey, kIOHIDProductIDKey) :contentReference[oaicite:5]{index=5}
    CFMutableDictionaryRef match = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                                                            &kCFTypeDictionaryKeyCallBacks,
                                                            &kCFTypeDictionaryValueCallBacks);
    CFNumberRef nVid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vid);
    CFNumberRef nPid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid);
    CFDictionarySetValue(match, CFSTR(kIOHIDVendorIDKey), nVid);
    CFDictionarySetValue(match, CFSTR(kIOHIDProductIDKey), nPid);
    CFRelease(nVid);
    CFRelease(nPid);

    IOHIDManagerSetDeviceMatching(mgr, match);
    CFRelease(match);

    IOReturn r = IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
    if (r != kIOReturnSuccess) {
        fprintf(stderr, "IOHIDManagerOpen failed: 0x%08x\n", r);
        return 2;
    }

    CFSetRef devs = IOHIDManagerCopyDevices(mgr);
    if (!devs) {
        fprintf(stderr, "No devices matched VID/PID\n");
        return 3;
    }

    CFIndex count = CFSetGetCount(devs);
    IOHIDDeviceRef* list = (IOHIDDeviceRef*)calloc((size_t)count, sizeof(IOHIDDeviceRef));
    CFSetGetValues(devs, (const void**)list);

    IOHIDDeviceRef target = NULL;

    for (CFIndex i = 0; i < count; i++) {
        IOHIDDeviceRef d = list[i];

        // Location IDで絞る (kIOHIDLocationIDKey) :contentReference[oaicite:6]{index=6}
        CFTypeRef locRef = IOHIDDeviceGetProperty(d, CFSTR(kIOHIDLocationIDKey));
        int dloc = -1;
        if (locRef && CFGetTypeID(locRef) == CFNumberGetTypeID()) {
            CFNumberGetValue((CFNumberRef)locRef, kCFNumberIntType, &dloc);
        }

        CFStringRef prod = (CFStringRef)IOHIDDeviceGetProperty(d, CFSTR(kIOHIDProductKey));

        printf("Matched device: location=0x%08x product=", dloc);
        print_cfstring(prod);
        printf("\n");

        if (dloc == loc) {
            target = d;
        }
    }

    if (!target) {
        fprintf(stderr, "Device matched VID/PID but not location_id=0x%08x\n", loc);
        fprintf(stderr, "Hint: confirm Location ID via system_profiler SPUSBDataType\n");
        return 4;
    }

    // Output report: 1 byte, bit0=NumLock ON (0x01)
    // IOHIDDeviceSetReport is the API to send output/feature reports :contentReference[oaicite:7]{index=7}
    uint8_t report[1] = { 0x01 };
    r = IOHIDDeviceSetReport(target, kIOHIDReportTypeOutput, 0, report, sizeof(report));
    if (r != kIOReturnSuccess) {
        fprintf(stderr, "IOHIDDeviceSetReport failed: 0x%08x\n", r);
        return 5;
    }

    printf("NumLock LED ON report sent to location_id=0x%08x\n", loc);

    free(list);
    CFRelease(devs);
    CFRelease(mgr);
    return 0;
}

GitHubにもソースコードを置きました。

ソースコードをビルドします。

$ clang hid_set_numlock.c -o hid_set_numlock -framework IOKit -framework CoreFoundation

hid_set_numlockコマンドを実行してPC入力モードへの切り替えに成功しました。

$ ./hid_set_numlock 0x1267 0x6523 0x01100000 

Matched device: location=0x01100000 product=(null)
NumLock LED ON report sent to location_id=0x01100000

さいごに

USBデバイスを制御するHIDコマンドを少し理解できました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?