Arduino でチルト付き 5 ボタンマウスを試す

ATmega32U4 を利用した Arduino の Mouse ライブラリでは左、中央、右ボタンのマウスとなっています。これにチルト機能、進むおよび戻るボタンを追加してみます。

既存の Input Report に FB(Forward Button)、BB(Back Button) を追加します[1]。

Input D7 D6 D5 D4 D3 D2 D1 D0
1 0 0 0 (FB) (BB) MB RB LB

X, Y, Wheel はそのままになります。

Back ボタンが D3 に、Forward ボタンが D4 になるように以下を追加してボタン指定に使用します。また、チルト用の引数を追加します。

--- arduino-1.0.5 (2)/hardware/arduino/cores/arduino/USBAPI.h	2013-05-18 04:48:38.000000000 +0900
+++ arduino-1.0.5/hardware/arduino/cores/arduino/USBAPI.h	2013-09-05 18:02:41.530330129 +0900
@@ -52,6 +52,8 @@
 #define MOUSE_RIGHT 2
 #define MOUSE_MIDDLE 4
 #define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)
+#define MOUSE_BACK 8
+#define MOUSE_FORWARD 16
 
 class Mouse_
 {
@@ -63,7 +65,7 @@
 	void begin(void);
 	void end(void);
 	void click(uint8_t b = MOUSE_LEFT);
-	void move(signed char x, signed char y, signed char wheel = 0);	
+	void move(signed char x, signed char y, signed char wheel = 0, signed char pan = 0);	
 	void press(uint8_t b = MOUSE_LEFT);		// press LEFT by default
 	void release(uint8_t b = MOUSE_LEFT);	// release LEFT by default
 	bool isPressed(uint8_t b = MOUSE_LEFT);	// check LEFT by default

以下でボタン数を増やします (USAGE_MAXIMUM を 3 から 5 に変更、REPORT_COUNT を 5 に変更、パッディングのサイズを 5 から 3 に変更)。さらに、チルト用の部分を追加します。

--- arduino-1.0.5 (2)/hardware/arduino/cores/arduino/HID.cpp	2013-05-18 04:48:38.000000000 +0900
+++ arduino-1.0.5/hardware/arduino/cores/arduino/HID.cpp	2013-09-05 20:20:40.945700558 +0900
@@ -55,14 +55,14 @@
     0x85, 0x01,                    //     REPORT_ID (1)
     0x05, 0x09,                    //     USAGE_PAGE (Button)
     0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
-    0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
+    0x29, 0x05,                    //     USAGE_MAXIMUM (Button 5)
     0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
     0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
-    0x95, 0x03,                    //     REPORT_COUNT (3)
+    0x95, 0x05,                    //     REPORT_COUNT (5)
     0x75, 0x01,                    //     REPORT_SIZE (1)
     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
     0x95, 0x01,                    //     REPORT_COUNT (1)
-    0x75, 0x05,                    //     REPORT_SIZE (5)
+    0x75, 0x03,                    //     REPORT_SIZE (3)
     0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
     0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
     0x09, 0x30,                    //     USAGE (X)
@@ -73,6 +73,15 @@
     0x75, 0x08,                    //     REPORT_SIZE (8)
     0x95, 0x03,                    //     REPORT_COUNT (3)
     0x81, 0x06,                    //     INPUT (Data,Var,Rel)
+    
+    0x05, 0x0c,                    //     USAGE_PAGE (Consumer Page)
+    0x0a, 0x38, 0x02,              //     USAGE (AC Pan)
+    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
+    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
+    0x95, 0x01,                    //     REPORT_COUNT (1)
+    0x75, 0x08,                    //     REPORT_SIZE (8)
+    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
+    
     0xc0,                          //   END_COLLECTION
     0xc0,                          // END_COLLECTION
 
@@ -221,14 +230,15 @@
 	move(0,0,0);
 }
 
-void Mouse_::move(signed char x, signed char y, signed char wheel)
+void Mouse_::move(signed char x, signed char y, signed char wheel, signed char pan)
 {
-	u8 m[4];
+	u8 m[5];
 	m[0] = _buttons;
 	m[1] = x;
 	m[2] = y;
 	m[3] = wheel;
-	HID_SendReport(1,m,4);
+    m[4] = pan;
+	HID_SendReport(1,m,5);
 }
 
 void Mouse_::buttons(uint8_t b)

以下のようにして使用します。

#define PIN_BTN_LEFT 19
#define PIN_BTN_RIGHT 18
//#define PIN_BTN_MIDDLE 0
#define PIN_BTN_FORWARD 8
#define PIN_BTN_BACK 9
#define PIN_PAN_LEFT 10
#define PIN_PAN_RIGHT 11

void setup() {
  pinMode(PIN_BTN_LEFT, INPUT_PULLUP); // left
  pinMode(PIN_BTN_RIGHT, INPUT_PULLUP);  // right
  pinMode(PIN_BTN_FORWARD, INPUT_PULLUP);  // forward
  pinMode(PIN_BTN_BACK, INPUT_PULLUP); // back
  pinMode(PIN_PAN_LEFT, INPUT_PULLUP); // pan left
  pinMode(PIN_PAN_RIGHT, INPUT_PULLUP); // pan right
  Mouse.begin();
}

void loop() {
  if (digitalRead(PIN_BTN_LEFT) == LOW) {
    Mouse.press(MOUSE_LEFT);
  } else {
    Mouse.release(MOUSE_LEFT);
  }
  if (digitalRead(PIN_BTN_RIGHT) == LOW) {
    Mouse.press(MOUSE_RIGHT);
  } else {
    Mouse.release(MOUSE_RIGHT);
  }
  if (digitalRead(PIN_BTN_FORWARD) == LOW) {
    Mouse.press(MOUSE_FORWARD);
  } else {
    Mouse.release(MOUSE_FORWARD);
  }
  if (digitalRead(PIN_BTN_BACK) == LOW) {
    Mouse.press(MOUSE_BACK);
  } else {
    Mouse.release(MOUSE_BACK);
  }
  
  if (digitalRead(PIN_PAN_LEFT) == LOW) {
    Mouse.move(0, 0, 0, -1);
  }
  
  if (digitalRead(PIN_PAN_RIGHT) == LOW) {
    Mouse.move(0, 0, 0, 1);
  }
  delay(5);
}

[1] http://msdn.microsoft.com/en-us/windows/hardware/gg487477.aspx