To avoid any misunderstanding, here is the complete code for a new keymouse.c that implements the absolute position report map I posted earlier. It uses the keymouse.txt file currently on the github site, and overrides its SIZE settings by specifying the new packet lengths in write_ctic(). As an illustration it moves the cursor around a rectangle at the top left of the screen once per second. It works fine with a Windows PC.Code:
/******** KEYMOUSE.C *********COMPILE gcc keymouse.c btlib.c -o keymouse RUN sudo ./keymouse********************************/#include <stdio.h>#include <stdlib.h>#include "btlib.h" int lecallback(int clientnode,int op,int cticn);int send_key(int key);int send_mouse(int x,int y);unsigned char reportmap[100] = {0x05,0x01,0x09,0x06,0xA1,0x01,0x85,0x01,0x05,0x07,0x19,0xE0,0x29,0xE7,0x15,0x00, 0x25,0x01,0x75,0x01,0x95,0x08,0x81,0x02,0x95,0x01,0x75,0x08,0x81,0x01,0x95,0x06, 0x75,0x08,0x15,0x00,0x25,0x65,0x05,0x07,0x19,0x00,0x29,0x65,0x81,0x00,0xC0, 0x05,0x01,0x09,0x02,0xA1,0x01,0x85,0x02,0x09,0x01,0xA1,0x00,0x05,0x09,0x19,0x01, 0x29,0x03,0x15,0x00,0x25,0x01,0x95,0x03,0x75,0x01,0x81,0x02,0x95,0x01,0x75,0x05, 0x81,0x03,0x05,0x01,0x09,0x30,0x09,0x31,0x15,0x01,0x26,0xFF,0x75,0x75,0x10,0x95,0x02, 0x81,0x02,0xC0,0xC0};unsigned char report[8] = {0,0,0,0,0,0,0,0};unsigned char *name = "HID"; unsigned char appear[2] = {0xC1,0x03}; // 03C1 = keyboard icon appears on connecting device unsigned char pnpinfo[7] = {0x02,0x6B,0x1D,0x46,0x02,0x37,0x05};unsigned char protocolmode[1] = {0x01};unsigned char hidinfo[4] = {0x01,0x11,0x00,0x02};int main() { unsigned char uuid[2],randadd[6]; if(init_blue("keymouse.txt") == 0) return(0); if(localnode() != 1) { printf("ERROR - Edit keymouse.txt to set ADDRESS = %s\n",device_address(localnode())); return(0); } // Write data to local characteristics uuid[0] = 0x2A; uuid[1] = 0x00; write_ctic(localnode(),find_ctic_index(localnode(),UUID_2,uuid),name,3); uuid[0] = 0x2A; uuid[1] = 0x01; write_ctic(localnode(),find_ctic_index(localnode(),UUID_2,uuid),appear,0); uuid[0] = 0x2A; uuid[1] = 0x4E; write_ctic(localnode(),find_ctic_index(localnode(),UUID_2,uuid),protocolmode,0); uuid[0] = 0x2A; uuid[1] = 0x4A; write_ctic(localnode(),find_ctic_index(localnode(),UUID_2,uuid),hidinfo,0); uuid[0] = 0x2A; uuid[1] = 0x4B; write_ctic(localnode(),find_ctic_index(localnode(),UUID_2,uuid),reportmap,100); uuid[0] = 0x2A; uuid[1] = 0x4D; write_ctic(localnode(),find_ctic_index(localnode(),UUID_2,uuid),report,0); uuid[0] = 0x2A; uuid[1] = 0x50; write_ctic(localnode(),find_ctic_index(localnode(),UUID_2,uuid),pnpinfo,0); randadd[0] = 0xD3; randadd[1] = 0x56; randadd[2] = 0xD6; randadd[3] = 0x74; randadd[4] = 0x33; randadd[5] = 0x06; set_le_random_address(randadd); keys_to_callback(KEY_ON,0); set_le_wait(20000); le_pair(localnode(),JUST_WORKS,0); set_flags(FAST_TIMER,FLAG_ON); le_server(lecallback,20); close_all(); return(1); }int lecallback(int clientnode,int op,int cticn) { int n,nread; unsigned char buf[3]; static int timcount = 0; static int absx[4] = { 100,5000,5000,100 }; static int absy[4] = { 100,100,5000,5000 }; static int xyn = 0; if(op == LE_CONNECT) { printf("Connected OK\n"); timcount = 0; } if(op == LE_TIMER) { ++timcount; if(timcount == 50) { send_mouse(absx[xyn],absy[xyn]); ++xyn; if(xyn == 4) xyn = 0; timcount = 0; } } if(op == LE_KEYPRESS) { // cticn = ASCII code of key OR btferret custom code send_key(cticn); } if(op == LE_DISCONNECT) return(SERVER_EXIT); return(SERVER_CONTINUE); }int send_key(int key) { int n,hidcode; unsigned char buf[8]; static int reportindex = -1; // convert btferret code (key) to HID code hidcode = hid_key_code(key); if(hidcode == 0) return(0); if(reportindex < 0) { // look up Report1 index buf[0] = 0x2A; buf[1] = 0x4D; reportindex = find_ctic_index(localnode(),UUID_2,buf); if(reportindex < 0) { printf("Failed to find Report characteristic\n"); return(0); } } for(n = 0 ; n < 8 ; ++n) buf[n] = 0; // send key press to Report1 buf[0] = (hidcode >> 8) & 0xFF; // modifier buf[2] = hidcode & 0xFF; // key code write_ctic(localnode(),reportindex,buf,0); // send no key pressed - all zero buf[0] = 0; buf[2] = 0; write_ctic(localnode(),reportindex,buf,0); return(1); }int send_mouse(int x,int y) { unsigned char buf[5]; static int reportindex = -1; if(reportindex < 0) { // look up Report 1 index buf[0] = 0x2A; buf[1] = 0x4D; reportindex = find_ctic_index(localnode(),UUID_2,buf); if(reportindex < 0) { printf("Failed to find Report characteristic\n"); return(0); } ++reportindex; // Mouse is Report 2 } buf[0] = 0; buf[1] = x & 0xFF; buf[2] = (x >> 8) & 0xFF; buf[3] = y & 0xFF; buf[4] = (y >> 8) & 0xFF; // send to Report2 write_ctic(localnode(),reportindex,buf,5); return(1); }
The issue was with the HID report descriptor. Specifically, the coordinate scaling was off. Originally, I assumed Barrier scaled my display to 3840x1080 (since I was using dual screens), but checking directly on Windows and via Python, it turned out the resolution being used was just 1920x1080.
After modifying the report descriptor to correctly match the screen dimensions, the movement worked perfectly.
Corrected reportmap:
Code:
unsigned char reportmap[100] = {0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x06, // Usage (Keyboard) 0xA1, 0x01, // Collection (Application) 0x85, 0x01, // Report ID (1) 0x05, 0x07, // Usage Page (Keyboard) 0x19, 0xE0, // Usage Minimum (Left Control) 0x29, 0xE7, // Usage Maximum (Right GUI) 0x15, 0x00, // Logical Minimum (0) <-- SHOULD ALWAYS BE 0 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data, Variable, Absolute) 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8) 0x81, 0x01, // Input (Constant) 0x95, 0x06, // Report Count (6) 0x75, 0x08, // Report Size (8) 0x15, 0x00, // Logical Minimum (0) <-- CHANGED FROM 1 TO 0 0x25, 0x65, // Logical Maximum (101) 0x05, 0x07, // Usage Page (Keyboard) 0x19, 0x00, // Usage Minimum (Reserved) 0x29, 0x65, // Usage Maximum (Keyboard Application) 0x81, 0x00, // Input (Data, Array) 0xC0, // End Collection 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) 0x85, 0x02, // Report ID (2) <-- ATTENTION SENDING THIS ID 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (Button 1) 0x29, 0x03, // Usage Maximum (Button 3) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x95, 0x03, // Report Count (3) 0x75, 0x01, // Report Size (1) 0x81, 0x02, // Input (Data, Variable, Absolute) 0x95, 0x01, // Report Count (1) 0x75, 0x05, // Report Size (5) 0x81, 0x01, // Input (Constant) 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x15, 0x00, // Logical Minimum (0) <-- CHANGED FROM 1 TO 0 0x26, 0xFF, 0x7F, // Logical Maximum (32767) 0x75, 0x10, // Report Size (16) 0x95, 0x02, // Report Count (2) 0x81, 0x02, // Input (Data, Variable, Absolute) 0xC0, // End Collection 0xC0};
Statistics: Posted by biomekh — Tue Apr 01, 2025 4:31 am