88
99
1010static PyObject * listener_callback = NULL ;
11+ static PyObject * mouse_listener_callback = NULL ;
1112
1213
1314static void clear_listener_callback (void ) {
@@ -17,6 +18,13 @@ static void clear_listener_callback(void) {
1718}
1819
1920
21+ static void clear_mouse_listener_callback (void ) {
22+ PyObject * callback = mouse_listener_callback ;
23+ mouse_listener_callback = NULL ;
24+ Py_XDECREF (callback );
25+ }
26+
27+
2028static PyObject * bool_result (bool value ) {
2129 if (value ) {
2230 Py_RETURN_TRUE ;
@@ -72,6 +80,31 @@ static PyObject *build_listener_event_dict(
7280}
7381
7482
83+ static PyObject * build_mouse_state_dict (const axidev_io_mouse_state_t * state ) {
84+ return Py_BuildValue ("{s:i,s:i,s:i,s:d,s:d,s:K}" , "x" , state -> x , "y" ,
85+ state -> y , "buttons" , (int )state -> buttons , "scroll_x" ,
86+ state -> scroll_x , "scroll_y" , state -> scroll_y ,
87+ "timestamp_ms" , (unsigned long long )state -> timestamp_ms );
88+ }
89+
90+
91+ static PyObject * unicode_as_utf8_bytes (PyObject * value , const char * * text ) {
92+ PyObject * bytes = PyUnicode_AsUTF8String (value );
93+ if (bytes == NULL ) {
94+ * text = NULL ;
95+ return NULL ;
96+ }
97+
98+ * text = PyBytes_AsString (bytes );
99+ if (* text == NULL ) {
100+ Py_DECREF (bytes );
101+ return NULL ;
102+ }
103+
104+ return bytes ;
105+ }
106+
107+
75108static void listener_bridge (
76109 uint32_t codepoint , axidev_io_keyboard_key_with_modifier_t key_mod ,
77110 bool pressed , void * user_data ) {
@@ -81,7 +114,7 @@ static void listener_bridge(
81114 if (listener_callback != NULL ) {
82115 PyObject * event = build_listener_event_dict (codepoint , key_mod , pressed );
83116 if (event != NULL ) {
84- PyObject * result = PyObject_CallOneArg (listener_callback , event );
117+ PyObject * result = PyObject_CallFunctionObjArgs (listener_callback , event , NULL );
85118 if (result == NULL ) {
86119 PyErr_WriteUnraisable (listener_callback );
87120 } else {
@@ -94,6 +127,27 @@ static void listener_bridge(
94127}
95128
96129
130+ static void mouse_listener_bridge (const axidev_io_mouse_state_t * state ,
131+ void * user_data ) {
132+ (void )user_data ;
133+
134+ PyGILState_STATE gil_state = PyGILState_Ensure ();
135+ if (mouse_listener_callback != NULL && state != NULL ) {
136+ PyObject * event = build_mouse_state_dict (state );
137+ if (event != NULL ) {
138+ PyObject * result = PyObject_CallFunctionObjArgs (mouse_listener_callback , event , NULL );
139+ if (result == NULL ) {
140+ PyErr_WriteUnraisable (mouse_listener_callback );
141+ } else {
142+ Py_DECREF (result );
143+ }
144+ Py_DECREF (event );
145+ }
146+ }
147+ PyGILState_Release (gil_state );
148+ }
149+
150+
97151static PyObject * mod_initialize (PyObject * self , PyObject * Py_UNUSED (args )) {
98152 (void )self ;
99153 return bool_result (axidev_io_keyboard_initialize ());
@@ -103,7 +157,9 @@ static PyObject *mod_initialize(PyObject *self, PyObject *Py_UNUSED(args)) {
103157static PyObject * mod_free (PyObject * self , PyObject * Py_UNUSED (args )) {
104158 (void )self ;
105159 axidev_io_listener_stop ();
160+ axidev_io_mouse_listener_stop ();
106161 clear_listener_callback ();
162+ clear_mouse_listener_callback ();
107163 axidev_io_keyboard_free ();
108164 Py_RETURN_NONE ;
109165}
@@ -256,19 +312,23 @@ static PyObject *mod_release_all_modifiers(PyObject *self,
256312
257313static PyObject * mod_type_text (PyObject * self , PyObject * args ) {
258314 PyObject * text_obj = NULL ;
315+ PyObject * text_bytes = NULL ;
259316 const char * text = NULL ;
317+ bool ok ;
260318 (void )self ;
261319
262320 if (!PyArg_ParseTuple (args , "U" , & text_obj )) {
263321 return NULL ;
264322 }
265323
266- text = PyUnicode_AsUTF8 (text_obj );
267- if (text == NULL ) {
324+ text_bytes = unicode_as_utf8_bytes (text_obj , & text );
325+ if (text_bytes == NULL ) {
268326 return NULL ;
269327 }
270328
271- return bool_result (axidev_io_keyboard_type_text (text ));
329+ ok = axidev_io_keyboard_type_text (text );
330+ Py_DECREF (text_bytes );
331+ return bool_result (ok );
272332}
273333
274334
@@ -354,6 +414,73 @@ static PyObject *mod_is_listening(PyObject *self, PyObject *Py_UNUSED(args)) {
354414}
355415
356416
417+ static PyObject * mod_mouse_poll (PyObject * self , PyObject * Py_UNUSED (args )) {
418+ axidev_io_mouse_state_t state ;
419+ bool ok ;
420+ (void )self ;
421+
422+ Py_BEGIN_ALLOW_THREADS
423+ ok = axidev_io_mouse_poll (& state );
424+ Py_END_ALLOW_THREADS
425+ if (!ok ) {
426+ Py_RETURN_NONE ;
427+ }
428+ return build_mouse_state_dict (& state );
429+ }
430+
431+
432+ static PyObject * mod_start_mouse_listener (PyObject * self , PyObject * args ) {
433+ PyObject * callback = NULL ;
434+ PyObject * previous = NULL ;
435+ bool ok = false;
436+ (void )self ;
437+
438+ if (!PyArg_ParseTuple (args , "O" , & callback )) {
439+ return NULL ;
440+ }
441+
442+ if (!PyCallable_Check (callback )) {
443+ PyErr_SetString (PyExc_TypeError , "listener must be callable" );
444+ return NULL ;
445+ }
446+
447+ Py_INCREF (callback );
448+ previous = mouse_listener_callback ;
449+ mouse_listener_callback = callback ;
450+
451+ if (axidev_io_mouse_listener_is_listening ()) {
452+ Py_XDECREF (previous );
453+ Py_RETURN_TRUE ;
454+ }
455+
456+ ok = axidev_io_mouse_listener_start (mouse_listener_bridge , NULL );
457+ if (!ok ) {
458+ mouse_listener_callback = previous ;
459+ Py_DECREF (callback );
460+ return bool_result (false);
461+ }
462+
463+ Py_XDECREF (previous );
464+ Py_RETURN_TRUE ;
465+ }
466+
467+
468+ static PyObject * mod_stop_mouse_listener (PyObject * self ,
469+ PyObject * Py_UNUSED (args )) {
470+ (void )self ;
471+ axidev_io_mouse_listener_stop ();
472+ clear_mouse_listener_callback ();
473+ Py_RETURN_NONE ;
474+ }
475+
476+
477+ static PyObject * mod_is_mouse_listening (PyObject * self ,
478+ PyObject * Py_UNUSED (args )) {
479+ (void )self ;
480+ return bool_result (axidev_io_mouse_listener_is_listening ());
481+ }
482+
483+
357484static PyObject * mod_key_to_string (PyObject * self , PyObject * args ) {
358485 int key = 0 ;
359486 char * text = NULL ;
@@ -377,19 +504,23 @@ static PyObject *mod_key_to_string(PyObject *self, PyObject *args) {
377504
378505static PyObject * mod_string_to_key (PyObject * self , PyObject * args ) {
379506 PyObject * text_obj = NULL ;
507+ PyObject * text_bytes = NULL ;
380508 const char * text = NULL ;
509+ axidev_io_keyboard_key_t key ;
381510 (void )self ;
382511
383512 if (!PyArg_ParseTuple (args , "U" , & text_obj )) {
384513 return NULL ;
385514 }
386515
387- text = PyUnicode_AsUTF8 (text_obj );
388- if (text == NULL ) {
516+ text_bytes = unicode_as_utf8_bytes (text_obj , & text );
517+ if (text_bytes == NULL ) {
389518 return NULL ;
390519 }
391520
392- return PyLong_FromLong ((long )axidev_io_keyboard_string_to_key (text ));
521+ key = axidev_io_keyboard_string_to_key (text );
522+ Py_DECREF (text_bytes );
523+ return PyLong_FromLong ((long )key );
393524}
394525
395526
@@ -419,7 +550,9 @@ static PyObject *mod_key_to_string_with_modifier(PyObject *self, PyObject *args)
419550
420551static PyObject * mod_string_to_key_with_modifier (PyObject * self , PyObject * args ) {
421552 PyObject * text_obj = NULL ;
553+ PyObject * text_bytes = NULL ;
422554 const char * text = NULL ;
555+ bool ok ;
423556 axidev_io_keyboard_key_with_modifier_t key_mod = {
424557 .key = AXIDEV_IO_KEY_UNKNOWN ,
425558 .mods = AXIDEV_IO_MOD_NONE ,
@@ -430,12 +563,14 @@ static PyObject *mod_string_to_key_with_modifier(PyObject *self, PyObject *args)
430563 return NULL ;
431564 }
432565
433- text = PyUnicode_AsUTF8 (text_obj );
434- if (text == NULL ) {
566+ text_bytes = unicode_as_utf8_bytes (text_obj , & text );
567+ if (text_bytes == NULL ) {
435568 return NULL ;
436569 }
437570
438- if (!axidev_io_keyboard_string_to_key_with_modifier (text , & key_mod )) {
571+ ok = axidev_io_keyboard_string_to_key_with_modifier (text , & key_mod );
572+ Py_DECREF (text_bytes );
573+ if (!ok ) {
439574 Py_RETURN_NONE ;
440575 }
441576
@@ -506,28 +641,32 @@ static PyObject *mod_log_is_enabled(PyObject *self, PyObject *args) {
506641static PyObject * mod_log_message (PyObject * self , PyObject * args ) {
507642 unsigned int level = 0 ;
508643 PyObject * message_obj = NULL ;
644+ PyObject * message_bytes = NULL ;
509645 const char * message = NULL ;
510646 (void )self ;
511647
512648 if (!PyArg_ParseTuple (args , "IU" , & level , & message_obj )) {
513649 return NULL ;
514650 }
515651
516- message = PyUnicode_AsUTF8 (message_obj );
517- if (message == NULL ) {
652+ message_bytes = unicode_as_utf8_bytes (message_obj , & message );
653+ if (message_bytes == NULL ) {
518654 return NULL ;
519655 }
520656
521657 axidev_io_log_message ((axidev_io_log_level_t )level , "axidev_io" , 0 , "%s" ,
522658 message );
659+ Py_DECREF (message_bytes );
523660 Py_RETURN_NONE ;
524661}
525662
526663
527664static void module_free (void * module ) {
528665 (void )module ;
529666 axidev_io_listener_stop ();
667+ axidev_io_mouse_listener_stop ();
530668 clear_listener_callback ();
669+ clear_mouse_listener_callback ();
531670 axidev_io_keyboard_free ();
532671}
533672
@@ -554,6 +693,10 @@ static PyMethodDef module_methods[] = {
554693 {"start_listener" , mod_start_listener , METH_VARARGS , NULL },
555694 {"stop_listener" , mod_stop_listener , METH_NOARGS , NULL },
556695 {"is_listening" , mod_is_listening , METH_NOARGS , NULL },
696+ {"mouse_poll" , mod_mouse_poll , METH_NOARGS , NULL },
697+ {"start_mouse_listener" , mod_start_mouse_listener , METH_VARARGS , NULL },
698+ {"stop_mouse_listener" , mod_stop_mouse_listener , METH_NOARGS , NULL },
699+ {"is_mouse_listening" , mod_is_mouse_listening , METH_NOARGS , NULL },
557700 {"key_to_string" , mod_key_to_string , METH_VARARGS , NULL },
558701 {"string_to_key" , mod_string_to_key , METH_VARARGS , NULL },
559702 {"key_to_string_with_modifier" , mod_key_to_string_with_modifier , METH_VARARGS ,
0 commit comments