File: dasher_editor_external_xtest.cpp

package info (click to toggle)
dasher 5.0.0~beta~repack2-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 70,872 kB
  • sloc: xml: 181,314; cpp: 70,860; java: 8,020; python: 3,579; makefile: 939; sh: 324; ansic: 223; perl: 71
file content (158 lines) | stat: -rw-r--r-- 5,052 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <glib/gi18n.h>
#include <gtk/gtk.h>

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <gdk/gdkx.h>

#include <X11/keysym.h>
#include <algorithm>

#include "dasher_editor_external.h"
#include "dasher_editor_private.h"
#include "dasher_lock_dialogue.h"
#include "dasher_main.h"
#include "../DasherCore/ControlManager.h"

void
dasher_editor_external_finalize(GObject *pSelf) {
}

void
dasher_editor_external_create_buffer(DasherEditor *pSelf) {
}

void
dasher_editor_external_toggle_direct_mode(DasherEditor *pSelf, bool direct) {
}

void
dasher_editor_external_output(DasherEditor *pSelf, const gchar *szText, int iOffset /* unused */) {
  glong numoutput;
  int numcodes;
  Display *dpy = gdk_x11_get_default_xdisplay();
  int min, max;
  KeySym *keysym;
  KeyCode code;  
  
  if(szText[0] == '\n') {
    // If it's a newline, we want to mimic an enter press rather than a raw newline
    code = XKeysymToKeycode(dpy, XK_Return);
    if(code != 0) {
      XTestFakeKeyEvent(dpy, code, True, CurrentTime);
      XSync(dpy, true);
      XTestFakeKeyEvent(dpy, code, False, CurrentTime);
      XSync(dpy, true);
    }
  }
  else {
    // gunichar is a 32 bit data type for UTF32 (aka UCS4) encoded unicodeX
    gunichar *wideoutput = g_utf8_to_ucs4(szText, -1, NULL, &numoutput, NULL);

    // Get the X server's keycode value range.
    XDisplayKeycodes(dpy, &min, &max);

    for(int i = 0; i < numoutput; i++) {

      // In the string of text that we're outputting, we need first to
      // convert each character to a X keysym, then fake a keycode
      // event that the X server will interpret as the desired keysym.
      //
      // For the first part, we take advantage of the fact that X
      // understands a regular mapping of Unicode code points <
      // 0x1000000 to keysym values: the keysym value is the Unicode
      // code point + 0x1000000.
      // (Ref. http://www.cl.cam.ac.uk/~mgk25/ucs/keysym2ucs.c)
      //
      // For the second part, we reprogram the X server's keycode to
      // keysym mapping so that a known keycode will generate each
      // keysym that we want.  This is actually a pretty horrible
      // hack, because who knows what other X programs might be
      // relying on the keycodes that we're reprogramming, or making
      // its own hacky changes to the keyboard mapping at the same
      // time?  But we try to reduce the hackiness by using the top
      // ten keycode values in the X server's range - in the hope that
      // those might not be being used by other applications.

      // Choose which keycode we're going to appropriate for this
      // iteration.
      code = (max - 1 - (i % 10));

      // If we've used the whole set of keycodes and are looping round
      // to use the first of them again, sleep a bit first to ensure
      // that the intended client has had time to see and process the
      // X events, before we go changing the keyboard mapping again.
      if (i && !(i % 10)) {
	usleep(200000);
      }

      if(wideoutput[i] < 0x01000000) {

	// Convert Unicode code point to keysym value.
	wideoutput[i] = wideoutput[i] | 0x01000000;

	// TODO: Please see
	// http://tronche.com/gui/x/xlib/input/keyboard-encoding.html
	// for an explanation as to why you sometimes get problems
	// with upper/lower case on some X displays I'm tempted to say
	// that the XTest stuff is just broken, and require some GNOME
	// a11y support for direct entry...

	// Returns the keyboard mapping for the current display - numcodes is the 
	keysym = XGetKeyboardMapping(dpy, min, max - min + 1, &numcodes);

	// Reprogramme the keyboard map to use the new keysym
	keysym[(code - min) * numcodes] = wideoutput[i];
	XChangeKeyboardMapping(dpy, min, numcodes, keysym, (max - min));
	XSync(dpy, true);

	// Delete the old keymap
	XFree(keysym);

	// There's no way whatsoever that this could ever possibly
	// be guaranteed to work (ever), but it does.
	if(code != 0) {
	  XTestFakeKeyEvent(dpy, code, True, CurrentTime);
	  XSync(dpy, true);
	  XTestFakeKeyEvent(dpy, code, False, CurrentTime);
	  XSync(dpy, true);
	}
      }
    }
    XSync(dpy, true);
    g_free(wideoutput);
  }
}

void
dasher_editor_external_delete(DasherEditor *pSelf, int iLength, int iOffset) {
  Display *dpy;
  dpy = gdk_x11_get_default_xdisplay();
  KeyCode code;
  code = XKeysymToKeycode(dpy, XK_BackSpace);
  for(int i = 0; i < iLength; i++) {
    XTestFakeKeyEvent(dpy, code, True, 0);
    XTestFakeKeyEvent(dpy, code, False, 0);
  }
  XFlush(dpy);
}

std::string dasher_editor_external_get_context(DasherEditor *pSelf, int iOffset, int iLength) {
  return "";
}

gint
dasher_editor_external_get_offset(DasherEditor *pSelf) {
  return 0;
}

void dasher_editor_external_move(DasherEditor *pSelf, bool bForwards, Dasher::CControlManager::EditDistance iDist) {
  // TODO: implement.
}

std::string dasher_editor_external_get_text_around_cursor(
    DasherEditor *pSelf, Dasher::CControlManager::EditDistance distance) {
  // TODO: implement.
  return "";
}