#include
"input-method-client-protocol.h"
#include
"text-client-protocol.h"
struct
virtual_keyboard
{
struct
input_panel
*
input_panel
;
struct
input_method
*
input_method
;
struct
input_method_context
*
context
;
struct
display
*
display
;
xkb_mod_mask_t
shift_mask
;
uint32_t
content_purpose
;
char
*
surrounding_text
;
const
struct
key
*
keys
;
static
const
struct
key
normal_keys
[]
=
{
{
keytype_default
,
"q"
,
"Q"
,
1
},
{
keytype_default
,
"w"
,
"W"
,
1
},
{
keytype_default
,
"e"
,
"E"
,
1
},
{
keytype_default
,
"r"
,
"R"
,
1
},
{
keytype_default
,
"t"
,
"T"
,
1
},
{
keytype_default
,
"y"
,
"Y"
,
1
},
{
keytype_default
,
"u"
,
"U"
,
1
},
{
keytype_default
,
"i"
,
"I"
,
1
},
{
keytype_default
,
"o"
,
"O"
,
1
},
{
keytype_default
,
"p"
,
"P"
,
1
},
{
keytype_backspace
,
"<--"
,
"<--"
,
2
},
{
keytype_tab
,
"->|"
,
"->|"
,
1
},
{
keytype_default
,
"a"
,
"A"
,
1
},
{
keytype_default
,
"s"
,
"S"
,
1
},
{
keytype_default
,
"d"
,
"D"
,
1
},
{
keytype_default
,
"f"
,
"F"
,
1
},
{
keytype_default
,
"g"
,
"G"
,
1
},
{
keytype_default
,
"h"
,
"H"
,
1
},
{
keytype_default
,
"j"
,
"J"
,
1
},
{
keytype_default
,
"k"
,
"K"
,
1
},
{
keytype_default
,
"l"
,
"L"
,
1
},
{
keytype_enter
,
"Enter"
,
"Enter"
,
2
},
{
keytype_switch
,
"ABC"
,
"abc"
,
2
},
{
keytype_default
,
"z"
,
"Z"
,
1
},
{
keytype_default
,
"x"
,
"X"
,
1
},
{
keytype_default
,
"c"
,
"C"
,
1
},
{
keytype_default
,
"v"
,
"V"
,
1
},
{
keytype_default
,
"b"
,
"B"
,
1
},
{
keytype_default
,
"n"
,
"N"
,
1
},
{
keytype_default
,
"m"
,
"M"
,
1
},
{
keytype_default
,
","
,
","
,
1
},
{
keytype_default
,
"."
,
"."
,
1
},
{
keytype_switch
,
"ABC"
,
"abc"
,
1
},
{
keytype_symbols
,
"?123"
,
"?123"
,
1
},
{
keytype_space
,
""
,
""
,
5
},
{
keytype_arrow_up
,
"/\\"
,
"/\\"
,
1
},
{
keytype_arrow_left
,
"<"
,
"<"
,
1
},
{
keytype_arrow_right
,
">"
,
">"
,
1
},
{
keytype_arrow_down
,
"\\/"
,
"\\/"
,
1
},
{
keytype_style
,
""
,
""
,
2
}
static
const
struct
key
numeric_keys
[]
=
{
{
keytype_default
,
"1"
,
"1"
,
1
},
{
keytype_default
,
"2"
,
"2"
,
1
},
{
keytype_default
,
"3"
,
"3"
,
1
},
{
keytype_default
,
"4"
,
"4"
,
1
},
{
keytype_default
,
"5"
,
"5"
,
1
},
{
keytype_default
,
"6"
,
"6"
,
1
},
{
keytype_default
,
"7"
,
"7"
,
1
},
{
keytype_default
,
"8"
,
"8"
,
1
},
{
keytype_default
,
"9"
,
"9"
,
1
},
{
keytype_default
,
"0"
,
"0"
,
1
},
{
keytype_backspace
,
"<--"
,
"<--"
,
2
},
{
keytype_space
,
""
,
""
,
4
},
{
keytype_enter
,
"Enter"
,
"Enter"
,
2
},
{
keytype_arrow_up
,
"/\\"
,
"/\\"
,
1
},
{
keytype_arrow_left
,
"<"
,
"<"
,
1
},
{
keytype_arrow_right
,
">"
,
">"
,
1
},
{
keytype_arrow_down
,
"\\/"
,
"\\/"
,
1
},
{
keytype_style
,
""
,
""
,
2
}
static
const
struct
layout
normal_layout
=
{
sizeof
(
normal_keys
) /
sizeof
(
*
normal_keys
),
static
const
struct
layout
numeric_layout
=
{
sizeof
(
numeric_keys
) /
sizeof
(
*
numeric_keys
),
static
const
char
*
style_labels
[]
=
{
static
const
double
key_width
=
60
;
static
const
double
key_height
=
50
;
struct
virtual_keyboard
*
keyboard
;
enum
keyboard_state
state
;
label_from_key
(
struct
keyboard
*
keyboard
,
if
(
key
->
key_type
==
keytype_style
)
return
style_labels
[
keyboard
->
keyboard
->
preedit_style
];
if
(
keyboard
->
state
==
keyboardstate_default
)
draw_key
(
struct
keyboard
*
keyboard
,
cairo_text_extents_t
extents
;
col
*
key_width
,
row
*
key_height
,
key
->
width
*
key_width
,
key_height
);
col
*
key_width
,
row
*
key_height
,
key
->
width
*
key_width
,
key_height
);
cairo_set_line_width
(
cr
,
3
);
label
=
label_from_key
(
keyboard
,
key
);
cairo_text_extents
(
cr
,
label
,
&
extents
);
(
key
->
width
*
key_width
-
extents
.
width
) /
2
,
(
key_height
-
extents
.
y_bearing
) /
2
);
cairo_show_text
(
cr
,
label
);
static
const
struct
layout
*
get_current_layout
(
struct
virtual_keyboard
*
keyboard
)
switch
(
keyboard
->
content_purpose
) {
case
TEXT_MODEL_CONTENT_PURPOSE_DIGITS
:
case
TEXT_MODEL_CONTENT_PURPOSE_NUMBER
:
return
&
numeric_layout
;
redraw_handler
(
struct
widget
*
widget
,
void
*
data
)
struct
keyboard
*
keyboard
=
data
;
cairo_surface_t
*
surface
;
struct
rectangle
allocation
;
unsigned
int
row
=
0
,
col
=
0
;
const
struct
layout
*
layout
;
layout
=
get_current_layout
(
keyboard
->
keyboard
);
surface
=
window_get_surface
(
keyboard
->
window
);
widget_get_allocation
(
keyboard
->
widget
,
&
allocation
);
cr
=
cairo_create
(
surface
);
cairo_rectangle
(
cr
,
allocation
.
x
,
allocation
.
y
,
allocation
.
width
,
allocation
.
height
);
cairo_select_font_face
(
cr
,
"sans"
,
CAIRO_FONT_SLANT_NORMAL
,
CAIRO_FONT_WEIGHT_BOLD
);
cairo_set_font_size
(
cr
,
16
);
cairo_translate
(
cr
,
allocation
.
x
,
allocation
.
y
);
cairo_set_operator
(
cr
,
CAIRO_OPERATOR_SOURCE
);
cairo_set_source_rgba
(
cr
,
1
,
1
,
1
,
0.75
);
cairo_rectangle
(
cr
,
0
,
0
,
layout
->
columns
*
key_width
,
layout
->
rows
*
key_height
);
cairo_set_operator
(
cr
,
CAIRO_OPERATOR_OVER
);
for
(
i
=
0
;
i
<
layout
->
count
;
++
i
) {
cairo_set_source_rgb
(
cr
,
0
,
0
,
0
);
draw_key
(
keyboard
,
&
layout
->
keys
[
i
],
cr
,
row
,
col
);
col
+=
layout
->
keys
[
i
].
width
;
if
(
col
>=
layout
->
columns
) {
cairo_surface_destroy
(
surface
);
resize_handler
(
struct
widget
*
widget
,
int32_t
width
,
int32_t
height
,
void
*
data
)
/* struct keyboard *keyboard = data; */
virtual_keyboard_commit_preedit
(
struct
virtual_keyboard
*
keyboard
)
if
(!
keyboard
->
preedit_string
||
strlen
(
keyboard
->
preedit_string
)
==
0
)
input_method_context_preedit_cursor
(
keyboard
->
context
,
input_method_context_preedit_string
(
keyboard
->
context
,
input_method_context_cursor_position
(
keyboard
->
context
,
input_method_context_commit_string
(
keyboard
->
context
,
keyboard
->
preedit_string
);
free
(
keyboard
->
preedit_string
);
keyboard
->
preedit_string
=
strdup
(
""
);
virtual_keyboard_send_preedit
(
struct
virtual_keyboard
*
keyboard
,
uint32_t
index
=
strlen
(
keyboard
->
preedit_string
);
if
(
keyboard
->
preedit_style
)
input_method_context_preedit_styling
(
keyboard
->
context
,
strlen
(
keyboard
->
preedit_string
),
keyboard
->
preedit_style
);
input_method_context_preedit_cursor
(
keyboard
->
context
,
input_method_context_preedit_string
(
keyboard
->
context
,
keyboard
->
preedit_string
,
keyboard
->
preedit_string
);
keyboard_handle_key
(
struct
keyboard
*
keyboard
,
uint32_t
time
,
const
struct
key
*
key
,
struct
input
*
input
,
enum
wl_pointer_button_state
state
)
const
char
*
label
=
keyboard
->
state
==
keyboardstate_default
?
key
->
label
:
key
->
alt
;
xkb_mod_mask_t
mod_mask
=
keyboard
->
state
==
keyboardstate_default
?
0
:
keyboard
->
keyboard
->
keysym
.
shift_mask
;
uint32_t
key_state
=
(
state
==
WL_POINTER_BUTTON_STATE_PRESSED
) ?
WL_KEYBOARD_KEY_STATE_PRESSED
:
WL_KEYBOARD_KEY_STATE_RELEASED
;
switch
(
key
->
key_type
) {
if
(
state
!=
WL_POINTER_BUTTON_STATE_PRESSED
)
keyboard
->
keyboard
->
preedit_string
=
strcat
(
keyboard
->
keyboard
->
preedit_string
,
virtual_keyboard_send_preedit
(
keyboard
->
keyboard
,
-1
);
if
(
state
!=
WL_POINTER_BUTTON_STATE_PRESSED
)
if
(
strlen
(
keyboard
->
keyboard
->
preedit_string
)
==
0
) {
input_method_context_delete_surrounding_text
(
keyboard
->
keyboard
->
context
,
keyboard
->
keyboard
->
serial
,
keyboard
->
keyboard
->
preedit_string
[
strlen
(
keyboard
->
keyboard
->
preedit_string
)
-
1
]
=
'\0'
;
virtual_keyboard_send_preedit
(
keyboard
->
keyboard
,
-1
);
virtual_keyboard_commit_preedit
(
keyboard
->
keyboard
);
input_method_context_keysym
(
keyboard
->
keyboard
->
context
,
display_get_serial
(
keyboard
->
keyboard
->
display
),
XKB_KEY_Return
,
key_state
,
mod_mask
);
if
(
state
!=
WL_POINTER_BUTTON_STATE_PRESSED
)
keyboard
->
keyboard
->
preedit_string
=
strcat
(
keyboard
->
keyboard
->
preedit_string
,
virtual_keyboard_commit_preedit
(
keyboard
->
keyboard
);
if
(
state
!=
WL_POINTER_BUTTON_STATE_PRESSED
)
if
(
keyboard
->
state
==
keyboardstate_default
)
keyboard
->
state
=
keyboardstate_uppercase
;
keyboard
->
state
=
keyboardstate_default
;
if
(
state
!=
WL_POINTER_BUTTON_STATE_PRESSED
)
virtual_keyboard_commit_preedit
(
keyboard
->
keyboard
);
input_method_context_keysym
(
keyboard
->
keyboard
->
context
,
display_get_serial
(
keyboard
->
keyboard
->
display
),
XKB_KEY_Tab
,
key_state
,
mod_mask
);
virtual_keyboard_commit_preedit
(
keyboard
->
keyboard
);
input_method_context_keysym
(
keyboard
->
keyboard
->
context
,
display_get_serial
(
keyboard
->
keyboard
->
display
),
XKB_KEY_Up
,
key_state
,
mod_mask
);
case
keytype_arrow_left
:
virtual_keyboard_commit_preedit
(
keyboard
->
keyboard
);
input_method_context_keysym
(
keyboard
->
keyboard
->
context
,
display_get_serial
(
keyboard
->
keyboard
->
display
),
XKB_KEY_Left
,
key_state
,
mod_mask
);
case
keytype_arrow_right
:
virtual_keyboard_commit_preedit
(
keyboard
->
keyboard
);
input_method_context_keysym
(
keyboard
->
keyboard
->
context
,
display_get_serial
(
keyboard
->
keyboard
->
display
),
XKB_KEY_Right
,
key_state
,
mod_mask
);
case
keytype_arrow_down
:
virtual_keyboard_commit_preedit
(
keyboard
->
keyboard
);
input_method_context_keysym
(
keyboard
->
keyboard
->
context
,
display_get_serial
(
keyboard
->
keyboard
->
display
),
XKB_KEY_Down
,
key_state
,
mod_mask
);
if
(
state
!=
WL_POINTER_BUTTON_STATE_PRESSED
)
keyboard
->
keyboard
->
preedit_style
=
(
keyboard
->
keyboard
->
preedit_style
+
1
) %
8
;
/* TODO */
virtual_keyboard_send_preedit
(
keyboard
->
keyboard
,
-1
);
button_handler
(
struct
widget
*
widget
,
struct
input
*
input
,
uint32_t
time
,
enum
wl_pointer_button_state
state
,
void
*
data
)
struct
keyboard
*
keyboard
=
data
;
struct
rectangle
allocation
;
const
struct
layout
*
layout
;
layout
=
get_current_layout
(
keyboard
->
keyboard
);
if
(
button
!=
BTN_LEFT
) {
input_get_position
(
input
,
&
x
,
&
y
);
widget_get_allocation
(
keyboard
->
widget
,
&
allocation
);
col
=
x
/
key_width
+
row
*
layout
->
columns
;
for
(
i
=
0
;
i
<
layout
->
count
;
++
i
) {
col
-=
layout
->
keys
[
i
].
width
;
keyboard_handle_key
(
keyboard
,
time
,
&
layout
->
keys
[
i
],
input
,
state
);
widget_schedule_redraw
(
widget
);
input_method_context_surrounding_text
(
void
*
data
,
struct
input_method_context
*
context
,
struct
virtual_keyboard
*
keyboard
=
data
;
free
(
keyboard
->
surrounding_text
);
keyboard
->
surrounding_text
=
strdup
(
text
);
input_method_context_reset
(
void
*
data
,
struct
input_method_context
*
context
,
struct
virtual_keyboard
*
keyboard
=
data
;
fprintf
(
stderr
,
"Reset pre-edit buffer\n"
);
if
(
strlen
(
keyboard
->
preedit_string
)) {
input_method_context_preedit_cursor
(
context
,
input_method_context_preedit_string
(
context
,
free
(
keyboard
->
preedit_string
);
keyboard
->
preedit_string
=
strdup
(
""
);
keyboard
->
serial
=
serial
;
input_method_context_content_type
(
void
*
data
,
struct
input_method_context
*
context
,
struct
virtual_keyboard
*
keyboard
=
data
;
keyboard
->
content_hint
=
hint
;
keyboard
->
content_purpose
=
purpose
;
input_method_context_invoke_action
(
void
*
data
,
struct
input_method_context
*
context
,
struct
virtual_keyboard
*
keyboard
=
data
;
if
(
button
!=
BTN_LEFT
)
virtual_keyboard_send_preedit
(
keyboard
,
index
);
input_method_context_commit
(
void
*
data
,
struct
input_method_context
*
context
)
struct
virtual_keyboard
*
keyboard
=
data
;
const
struct
layout
*
layout
;
layout
=
get_current_layout
(
keyboard
);
if
(
keyboard
->
surrounding_text
)
fprintf
(
stderr
,
"Surrounding text updated: %s\n"
,
keyboard
->
surrounding_text
);
window_schedule_resize
(
keyboard
->
window
,
layout
->
columns
*
key_width
,
layout
->
rows
*
key_height
);
widget_schedule_redraw
(
keyboard
->
widget
);
static
const
struct
input_method_context_listener
input_method_context_listener
=
{
input_method_context_surrounding_text
,
input_method_context_reset
,
input_method_context_content_type
,
input_method_context_invoke_action
,
input_method_context_commit
input_method_activate
(
void
*
data
,
struct
input_method
*
input_method
,
struct
input_method_context
*
context
,
struct
virtual_keyboard
*
keyboard
=
data
;
struct
wl_array
modifiers_map
;
if
(
keyboard
->
context
)
input_method_context_destroy
(
keyboard
->
context
);
if
(
keyboard
->
preedit_string
)
free
(
keyboard
->
preedit_string
);
keyboard
->
preedit_string
=
strdup
(
""
);
keyboard
->
serial
=
serial
;
keyboard
->
context
=
context
;
input_method_context_add_listener
(
context
,
&
input_method_context_listener
,
wl_array_init
(
&
modifiers_map
);
keysym_modifiers_add
(
&
modifiers_map
,
"Shift"
);
keysym_modifiers_add
(
&
modifiers_map
,
"Control"
);
keysym_modifiers_add
(
&
modifiers_map
,
"Mod1"
);
input_method_context_modifiers_map
(
context
,
&
modifiers_map
);
keyboard
->
keysym
.
shift_mask
=
keysym_modifiers_get_mask
(
&
modifiers_map
,
"Shift"
);
wl_array_release
(
&
modifiers_map
);
input_method_deactivate
(
void
*
data
,
struct
input_method
*
input_method
,
struct
input_method_context
*
context
)
struct
virtual_keyboard
*
keyboard
=
data
;
if
(!
keyboard
->
context
)
input_method_context_destroy
(
keyboard
->
context
);
keyboard
->
context
=
NULL
;
static
const
struct
input_method_listener
input_method_listener
=
{
global_handler
(
struct
display
*
display
,
uint32_t
name
,
const
char
*
interface
,
uint32_t
version
,
void
*
data
)
struct
virtual_keyboard
*
keyboard
=
data
;
if
(!
strcmp
(
interface
,
"input_panel"
)) {
keyboard
->
input_panel
=
display_bind
(
display
,
name
,
&
input_panel_interface
,
1
);
}
else
if
(!
strcmp
(
interface
,
"input_method"
)) {
keyboard
->
input_method
=
display_bind
(
display
,
name
,
&
input_method_interface
,
1
);
input_method_add_listener
(
keyboard
->
input_method
,
&
input_method_listener
,
keyboard
);
keyboard_create
(
struct
output
*
output
,
struct
virtual_keyboard
*
virtual_keyboard
)
struct
keyboard
*
keyboard
;
const
struct
layout
*
layout
;
struct
input_panel_surface
*
ips
;
layout
=
get_current_layout
(
virtual_keyboard
);
keyboard
=
malloc
(
sizeof
*
keyboard
);
memset
(
keyboard
,
0
,
sizeof
*
keyboard
);
keyboard
->
keyboard
=
virtual_keyboard
;
keyboard
->
window
=
window_create_custom
(
virtual_keyboard
->
display
);
keyboard
->
widget
=
window_add_widget
(
keyboard
->
window
,
keyboard
);
virtual_keyboard
->
window
=
keyboard
->
window
;
virtual_keyboard
->
widget
=
keyboard
->
widget
;
window_set_title
(
keyboard
->
window
,
"Virtual keyboard"
);
window_set_user_data
(
keyboard
->
window
,
keyboard
);
widget_set_redraw_handler
(
keyboard
->
widget
,
redraw_handler
);
widget_set_resize_handler
(
keyboard
->
widget
,
resize_handler
);
widget_set_button_handler
(
keyboard
->
widget
,
button_handler
);
window_schedule_resize
(
keyboard
->
window
,
layout
->
columns
*
key_width
,
layout
->
rows
*
key_height
);
ips
=
input_panel_get_input_panel_surface
(
virtual_keyboard
->
input_panel
,
window_get_wl_surface
(
keyboard
->
window
));
input_panel_surface_set_toplevel
(
ips
,
INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM
);
handle_output_configure
(
struct
output
*
output
,
void
*
data
)
struct
virtual_keyboard
*
virtual_keyboard
=
data
;
/* skip existing outputs */
if
(
output_get_user_data
(
output
))
output_set_user_data
(
output
,
virtual_keyboard
);
keyboard_create
(
output
,
virtual_keyboard
);
main
(
int
argc
,
char
*
argv
[])
struct
virtual_keyboard
virtual_keyboard
;
memset
(
&
virtual_keyboard
,
0
,
sizeof
virtual_keyboard
);
virtual_keyboard
.
display
=
display_create
(
&
argc
,
argv
);
if
(
virtual_keyboard
.
display
==
NULL
) {
fprintf
(
stderr
,
"failed to create display: %m\n"
);
display_set_user_data
(
virtual_keyboard
.
display
,
&
virtual_keyboard
);
display_set_global_handler
(
virtual_keyboard
.
display
,
global_handler
);
display_set_output_configure_handler
(
virtual_keyboard
.
display
,
handle_output_configure
);
display_run
(
virtual_keyboard
.
display
);