Skip to content

Commit 36996dd

Browse files
committed
fix(dxinput): fix property reading and button mapping data processing
logic - Replaced custom uchar array conversion function with C.GoBytes to simplify data copying - Modified get_prop function implementation to first obtain the attribute data size, then read the data completely - Corrected get_prop function parameters and comments; nbytes now indicates byte length rather than item count - Added free_prop_data function to release memory returned by get_prop, preventing memory leaks - Ensured proper release of C-allocated data after calling get_prop to retrieve properties in the Go layer - Removed unused maxBufferLen constant and the old ucharArrayToByte implementation Influence: Input Device Management --- fix(dxinput): 修正属性读取和按钮映射数据处理逻辑 - 使用 C.GoBytes 替代自定义 uchar 数组转换函数简化数据拷贝 - 修改 get_prop 函数实现,先获取属性数据大小,再完整读取数据 - 修正 get_prop 函数参数和注释,nbytes 表示字节长度而非项目数 - 添加 free_prop_data 函数用于释放 get_prop 返回的内存,避免内存泄漏 - 在 Go 层调用 get_prop 获取属性后正确释放 C 分配的数据 - 删除无用的 maxBufferLen 常量和 ucharArrayToByte 旧实现 Influence: 输入设备管理功能
1 parent f24ebfc commit 36996dd

File tree

4 files changed

+70
-45
lines changed

4 files changed

+70
-45
lines changed

dxinput/utils/button_map.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func GetButtonMap(xid uint32, devName string) ([]byte, error) {
2929
}
3030
defer C.free(unsafe.Pointer(cbtnMap))
3131

32-
return ucharArrayToByte(cbtnMap, int(cbtnNum)), nil
32+
return C.GoBytes(unsafe.Pointer(cbtnMap), cbtnNum), nil
3333
}
3434

3535
func SetButtonMap(xid uint32, devName string, btnMap []byte) error {

dxinput/utils/property.c

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,29 @@
1212
#include "type.h"
1313
#include "x11_mutex.h"
1414

15-
#define MAX_BUF_LEN 1000
16-
1715
/**
1816
* The return data type if 'char' must be convert to 'int8_t*'
1917
* if 'int' must be convert to 'int32_t*'
2018
* if 'float' must be convert to 'float*'
19+
*
20+
* Returns the property data and sets nbytes to the actual byte length.
21+
* The caller is responsible for calling XFree() on the returned data.
2122
**/
2223
unsigned char*
23-
get_prop(int id, const char* prop, int* nitems)
24+
get_prop(int id, const char* prop, int* nbytes)
2425
{
2526
if (!prop) {
2627
fprintf(stderr, "[get_prop] Empty property for %d\n", id);
2728
return NULL;
2829
}
2930

30-
if (!nitems) {
31-
fprintf(stderr, "[get_prop] Invalid item number for %d\n", id);
31+
if (!nbytes) {
32+
fprintf(stderr, "[get_prop] Invalid nbytes pointer for %d\n", id);
3233
return NULL;
3334
}
3435

36+
*nbytes = 0;
37+
3538
pthread_mutex_lock(&x11_global_mutex);
3639
setErrorHandler();
3740

@@ -54,24 +57,71 @@ get_prop(int id, const char* prop, int* nitems)
5457
int act_format;
5558
unsigned long num_items, bytes_after;
5659
unsigned char* data = NULL;
57-
int ret = XIGetProperty(disp, id, prop_id, 0, MAX_BUF_LEN, False,
60+
61+
// Step 1: Query property size (length=0 to get bytes_after)
62+
int ret = XIGetProperty(disp, id, prop_id, 0, 0, False,
5863
AnyPropertyType, &act_type, &act_format,
5964
&num_items, &bytes_after, &data);
65+
if (ret != Success || act_type == None) {
66+
if (data) {
67+
XFree(data);
68+
}
69+
XCloseDisplay(disp);
70+
pthread_mutex_unlock(&x11_global_mutex);
71+
return NULL;
72+
}
73+
74+
if (data) {
75+
XFree(data);
76+
data = NULL;
77+
}
78+
79+
if (bytes_after == 0) {
80+
// Property exists but has no data
81+
XCloseDisplay(disp);
82+
pthread_mutex_unlock(&x11_global_mutex);
83+
return NULL;
84+
}
85+
86+
// Step 2: Read all property data
87+
// length is in 32-bit units, so divide bytes_after by 4 (round up)
88+
unsigned long length = (bytes_after + 3) / 4;
89+
90+
ret = XIGetProperty(disp, id, prop_id, 0, length, False,
91+
AnyPropertyType, &act_type, &act_format,
92+
&num_items, &bytes_after, &data);
6093
if (ret != Success) {
94+
if (data) {
95+
XFree(data);
96+
}
6197
XCloseDisplay(disp);
6298
fprintf(stderr, "[get_prop] Get %s data failed for %d\n", prop, id);
6399
pthread_mutex_unlock(&x11_global_mutex);
64100
return NULL;
65101
}
66102

67-
*nitems = (int)num_items;
68-
XCloseDisplay(disp);
103+
// Calculate actual byte length based on format and num_items
104+
// format is 8, 16, or 32 bits per item
105+
*nbytes = (int)(num_items * (act_format / 8));
69106

107+
XCloseDisplay(disp);
70108
pthread_mutex_unlock(&x11_global_mutex);
71109

72110
return data;
73111
}
74112

113+
/**
114+
* Free the property data returned by get_prop.
115+
* This is a wrapper for XFree to be called from Go.
116+
*/
117+
void
118+
free_prop_data(unsigned char* data)
119+
{
120+
if (data) {
121+
XFree(data);
122+
}
123+
}
124+
75125
// bit: range(8,16,32)
76126
int
77127
set_prop_int(int id, const char* prop, unsigned char* data, int nitems, int bit)

dxinput/utils/property.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
#include <X11/Xlib.h>
99

10-
unsigned char* get_prop(int id, const char* prop, int* nitems);
10+
unsigned char* get_prop(int id, const char* prop, int* nbytes);
11+
void free_prop_data(unsigned char* data);
1112
int set_prop_int(int id, const char* prop, unsigned char* data, int nitems, int bit);
1213
int set_prop_float(int id, const char* prop, unsigned char* data, int nitems);
1314
int set_prop(int id, const char* prop, unsigned char* data, int nitems,

dxinput/utils/wrapper.go

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ import (
2323
"github.com/linuxdeepin/dde-api/dxinput/kwayland"
2424
)
2525

26-
const (
27-
// see 'property.c' MAX_BUF_LEN
28-
maxBufferLen = 1000
29-
)
30-
3126
func ListDevice() DeviceInfos {
3227
if len(os.Getenv("WAYLAND_DISPLAY")) != 0 {
3328
infos, _ := kwayland.ListDevice()
@@ -103,21 +98,19 @@ func GetProperty(id int32, prop string) ([]byte, int32) {
10398
}
10499

105100
cprop := C.CString(prop)
101+
defer C.free(unsafe.Pointer(cprop))
106102

107-
defer func() {
108-
if cprop != nil {
109-
C.free(unsafe.Pointer(cprop))
110-
}
111-
}()
112-
113-
nitems := C.int(0)
114-
cdatas := C.get_prop(C.int(id), cprop, &nitems)
115-
if cdatas == nil || nitems == 0 {
103+
// nbytes now represents the actual byte length returned by C layer
104+
nbytes := C.int(0)
105+
cdatas := C.get_prop(C.int(id), cprop, &nbytes)
106+
if cdatas == nil || nbytes == 0 {
116107
return nil, 0
117108
}
109+
// XIGetProperty allocates memory for data, caller must free it with XFree
110+
defer C.free_prop_data(cdatas)
118111

119-
datas := ucharArrayToByte(cdatas, maxBufferLen)
120-
return datas, int32(nitems)
112+
datas := C.GoBytes(unsafe.Pointer(cdatas), nbytes)
113+
return datas, int32(nbytes)
121114
}
122115

123116
func SetInt8Prop(id int32, prop string, values []int8) error {
@@ -196,25 +189,6 @@ func SetFloat32Prop(id int32, prop string, values []float32) error {
196189
return nil
197190
}
198191

199-
func ucharArrayToByte(cData *C.uchar, length int) []byte {
200-
if cData == nil {
201-
return nil
202-
}
203-
cItemSize := unsafe.Sizeof(*cData)
204-
205-
var data []byte
206-
for i := 0; i < length; i++ {
207-
offset := uintptr(i) * cItemSize
208-
addr := uintptr(unsafe.Pointer(cData)) + offset
209-
cdata := (*C.uchar)(unsafe.Pointer(addr))
210-
if cdata == nil {
211-
break
212-
}
213-
data = append(data, byte(*cdata))
214-
}
215-
return data
216-
}
217-
218192
func byteArrayToUChar(datas []byte) []C.uchar {
219193
var cdatas []C.uchar
220194
for i := 0; i < len(datas); i++ {

0 commit comments

Comments
 (0)