Skip to content

Commit 0ad86f7

Browse files
committed
Add support for paste events
1 parent fce282e commit 0ad86f7

18 files changed

+313
-77
lines changed

panda/src/display/graphicsWindowInputDevice.cxx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ keystroke(int keycode, double time) {
109109
_button_events->add_event(ButtonEvent(keycode, time));
110110
}
111111

112+
/**
113+
* Records that the indicated string has been pasted.
114+
*/
115+
void GraphicsWindowInputDevice::
116+
paste(const std::wstring &text) {
117+
LightMutexHolder holder(_lock);
118+
ButtonEvent event(text, 0, 0, 0);
119+
event._type = ButtonEvent::T_paste;
120+
_button_events->add_event(std::move(event));
121+
}
122+
112123
/**
113124
* Records that the indicated candidate string has been highlighted. This is
114125
* used to implement IME support for typing in international languages,

panda/src/display/graphicsWindowInputDevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class EXPCL_PANDA_DISPLAY GraphicsWindowInputDevice : public InputDevice {
4545
void button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
4646

4747
void keystroke(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
48+
void paste(const std::wstring &text);
4849
void candidate(const std::wstring &candidate_string, size_t highlight_start,
4950
size_t highlight_end, size_t cursor_pos);
5051

panda/src/event/buttonEvent.cxx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ output(std::ostream &out) const {
6060
case T_raw_up:
6161
out << "raw button " << _button << " up";
6262
break;
63+
64+
case T_paste:
65+
out << "paste "
66+
<< TextEncoder::encode_wtext(_candidate_string,
67+
TextEncoder::get_default_encoding());
68+
break;
6369
}
6470
}
6571

@@ -96,9 +102,15 @@ write_datagram(Datagram &dg) const {
96102
dg.add_uint16(_highlight_start);
97103
dg.add_uint16(_highlight_end);
98104
dg.add_uint16(_cursor_pos);
105+
break;
99106

100107
case T_move:
101108
break;
109+
110+
case T_paste:
111+
dg.add_string(TextEncoder::encode_wtext(_candidate_string,
112+
TextEncoder::get_default_encoding()));
113+
break;
102114
}
103115
}
104116

@@ -128,8 +140,14 @@ read_datagram(DatagramIterator &scan) {
128140
_highlight_start = scan.get_uint16();
129141
_highlight_end = scan.get_uint16();
130142
_cursor_pos = scan.get_uint16();
143+
break;
131144

132145
case T_move:
133146
break;
147+
148+
case T_paste:
149+
_candidate_string = TextEncoder::decode_text(scan.get_string(),
150+
TextEncoder::get_default_encoding());
151+
break;
134152
}
135153
}

panda/src/event/buttonEvent.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ class EXPCL_PANDA_EVENT ButtonEvent {
8282
// (qwerty) keyboard layout.
8383
T_raw_down,
8484
T_raw_up,
85+
86+
// This event can be sent by the operating system to indicate that text is
87+
// pasted into the window.
88+
T_paste,
8589
};
8690

8791
INLINE ButtonEvent();

panda/src/pgui/pgEntry.cxx

Lines changed: 125 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -324,93 +324,50 @@ keystroke(const MouseWatcherParameter &param, bool background) {
324324
if (!isascii(keycode) || isprint(keycode)) {
325325
// A normal visible character. Add a new character to the text entry,
326326
// if there's room.
327-
if (!_candidate_wtext.empty()) {
328-
_candidate_wtext = wstring();
329-
_text_geom_stale = true;
327+
if (do_add_character(keycode)) {
328+
type(param);
329+
} else {
330+
overflow(param);
330331
}
331-
wstring new_char(1, (wchar_t)keycode);
332+
}
333+
}
334+
}
335+
PGItem::keystroke(param, background);
336+
}
332337

333-
if (get_max_chars() > 0 && _text.get_num_characters() >= get_max_chars()) {
334-
// In max_chars mode, we consider it an overflow after we have
335-
// exceeded a fixed number of characters, irrespective of the
336-
// formatted width of those characters.
337-
overflow(param);
338+
/**
339+
* This is a callback hook function, called whenever the user pastes text.
340+
*/
341+
void PGEntry::
342+
paste(const MouseWatcherParameter &param, bool background) {
343+
LightReMutexHolder holder(_lock);
344+
if (get_active()) {
345+
if (param.has_candidate()) {
346+
// Make sure _text is initialized properly.
347+
update_text();
338348

349+
bool typed_any = false;
350+
wstring str = param.get_candidate_string();
351+
for (wchar_t keycode : str) {
352+
if (do_add_character(keycode)) {
353+
typed_any = true;
339354
} else {
340-
_cursor_position = min(_cursor_position, _text.get_num_characters());
341-
bool too_long = !_text.set_wsubstr(new_char, _cursor_position, 0);
342-
bool overflow_mode = get_overflow_mode() && _num_lines == 1;
343-
if(overflow_mode){
344-
too_long = false;
345-
}
346-
if (_obscure_mode) {
347-
too_long = !_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
348-
} else {
349-
if (!too_long && (_text.get_num_rows() == _num_lines) && !overflow_mode) {
350-
// If we've filled up all of the available lines, we must also
351-
// ensure that the last line is not too long (it might be,
352-
// because of additional whitespace on the end).
353-
int r = _num_lines - 1;
354-
int c = _text.get_num_cols(r);
355-
PN_stdfloat last_line_width =
356-
_text.get_xpos(r, c) - _text.get_xpos(r, 0);
357-
too_long = (last_line_width > _max_width);
358-
}
359-
360-
if (!too_long && keycode == ' ' && !overflow_mode) {
361-
// Even if we haven't filled up all of the available lines, we
362-
// should reject a space that's typed at the end of the current
363-
// line if it would make that line exceed the maximum width,
364-
// just so we don't allow an infinite number of spaces to
365-
// accumulate.
366-
int r, c;
367-
_text.calc_r_c(r, c, _cursor_position);
368-
if (_text.get_num_cols(r) == c + 1) {
369-
// The user is typing at the end of the line. But we must
370-
// allow at least one space at the end of the line, so we only
371-
// make any of the following checks if there are already
372-
// multiple spaces at the end of the line.
373-
if (c - 1 >= 0 && _text.get_character(r, c - 1) == ' ') {
374-
// Ok, the user is putting multiple spaces on the end of a
375-
// line; we need to make sure the line does not grow too
376-
// wide. Measure the line's width.
377-
PN_stdfloat current_line_width =
378-
_text.get_xpos(r, c + 1) - _text.get_xpos(r, 0);
379-
if (current_line_width > _max_width) {
380-
// We have to reject the space, but we don't treat it as
381-
// an overflow condition.
382-
_text.set_wsubstr(wstring(), _cursor_position, 1);
383-
// If the user is typing over existing space characters,
384-
// we act as if the right-arrow key were pressed instead,
385-
// and advance the cursor to the next position.
386-
// Otherwise, we just quietly eat the space character.
387-
if (_cursor_position < _text.get_num_characters() &&
388-
_text.get_character(_cursor_position) == ' ') {
389-
_cursor_position++;
390-
_cursor_stale = true;
391-
}
392-
return;
393-
}
394-
}
395-
}
396-
}
397-
}
398-
399-
if (too_long) {
400-
_text.set_wsubstr(wstring(), _cursor_position, 1);
401-
overflow(param);
402-
403-
} else {
404-
_cursor_position += new_char.length();
405-
_cursor_stale = true;
406-
_text_geom_stale = true;
355+
if (typed_any) {
356+
// Send type event first.
407357
type(param);
358+
typed_any = false;
408359
}
360+
overflow(param);
361+
break;
409362
}
410363
}
364+
365+
if (typed_any) {
366+
type(param);
367+
}
411368
}
412369
}
413-
PGItem::keystroke(param, background);
370+
PGItem::paste(param, background);
414371
}
415372

416373
/**
@@ -714,6 +671,97 @@ is_wtext() const {
714671
return false;
715672
}
716673

674+
/**
675+
* Adds a character to the entry. Returns true if it was added, false if
676+
* there was an overflow. Assumes the lock is held.
677+
*/
678+
bool PGEntry::
679+
do_add_character(wchar_t keycode) {
680+
if (!_candidate_wtext.empty()) {
681+
_candidate_wtext = wstring();
682+
_text_geom_stale = true;
683+
}
684+
wstring new_char(1, (wchar_t)keycode);
685+
686+
if (get_max_chars() > 0 && _text.get_num_characters() >= get_max_chars()) {
687+
// In max_chars mode, we consider it an overflow after we have
688+
// exceeded a fixed number of characters, irrespective of the
689+
// formatted width of those characters.
690+
return false;
691+
692+
} else {
693+
_cursor_position = min(_cursor_position, _text.get_num_characters());
694+
bool too_long = !_text.set_wsubstr(new_char, _cursor_position, 0);
695+
bool overflow_mode = get_overflow_mode() && _num_lines == 1;
696+
if(overflow_mode){
697+
too_long = false;
698+
}
699+
if (_obscure_mode) {
700+
too_long = !_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
701+
} else {
702+
if (!too_long && (_text.get_num_rows() == _num_lines) && !overflow_mode) {
703+
// If we've filled up all of the available lines, we must also
704+
// ensure that the last line is not too long (it might be,
705+
// because of additional whitespace on the end).
706+
int r = _num_lines - 1;
707+
int c = _text.get_num_cols(r);
708+
PN_stdfloat last_line_width =
709+
_text.get_xpos(r, c) - _text.get_xpos(r, 0);
710+
too_long = (last_line_width > _max_width);
711+
}
712+
713+
if (!too_long && keycode == ' ' && !overflow_mode) {
714+
// Even if we haven't filled up all of the available lines, we
715+
// should reject a space that's typed at the end of the current
716+
// line if it would make that line exceed the maximum width,
717+
// just so we don't allow an infinite number of spaces to
718+
// accumulate.
719+
int r, c;
720+
_text.calc_r_c(r, c, _cursor_position);
721+
if (_text.get_num_cols(r) == c + 1) {
722+
// The user is typing at the end of the line. But we must
723+
// allow at least one space at the end of the line, so we only
724+
// make any of the following checks if there are already
725+
// multiple spaces at the end of the line.
726+
if (c - 1 >= 0 && _text.get_character(r, c - 1) == ' ') {
727+
// Ok, the user is putting multiple spaces on the end of a
728+
// line; we need to make sure the line does not grow too
729+
// wide. Measure the line's width.
730+
PN_stdfloat current_line_width =
731+
_text.get_xpos(r, c + 1) - _text.get_xpos(r, 0);
732+
if (current_line_width > _max_width) {
733+
// We have to reject the space, but we don't treat it as
734+
// an overflow condition.
735+
_text.set_wsubstr(wstring(), _cursor_position, 1);
736+
// If the user is typing over existing space characters,
737+
// we act as if the right-arrow key were pressed instead,
738+
// and advance the cursor to the next position.
739+
// Otherwise, we just quietly eat the space character.
740+
if (_cursor_position < _text.get_num_characters() &&
741+
_text.get_character(_cursor_position) == ' ') {
742+
_cursor_position++;
743+
_cursor_stale = true;
744+
}
745+
return true;
746+
}
747+
}
748+
}
749+
}
750+
}
751+
752+
if (too_long) {
753+
_text.set_wsubstr(wstring(), _cursor_position, 1);
754+
return false;
755+
756+
} else {
757+
_cursor_position += new_char.length();
758+
_cursor_stale = true;
759+
_text_geom_stale = true;
760+
return true;
761+
}
762+
}
763+
}
764+
717765
/**
718766
* Ensures there is a slot in the array for the given text definition.
719767
*/

panda/src/pgui/pgEntry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class EXPCL_PANDA_PGUI PGEntry : public PGItem {
4949

5050
virtual void press(const MouseWatcherParameter &param, bool background);
5151
virtual void keystroke(const MouseWatcherParameter &param, bool background);
52+
virtual void paste(const MouseWatcherParameter &param, bool background);
5253
virtual void candidate(const MouseWatcherParameter &param, bool background);
5354

5455
virtual void accept(const MouseWatcherParameter &param);
@@ -140,6 +141,8 @@ class EXPCL_PANDA_PGUI PGEntry : public PGItem {
140141

141142

142143
private:
144+
bool do_add_character(wchar_t keycode);
145+
143146
void slot_text_def(int state);
144147
void update_text();
145148
void update_cursor();

panda/src/pgui/pgItem.I

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,16 @@ get_keystroke_prefix() {
341341
return "keystroke-";
342342
}
343343

344+
/**
345+
* Returns the prefix that is used to define the paste event for all
346+
* PGItems. The paste event is the concatenation of this string followed
347+
* by a hyphen and get_id().
348+
*/
349+
INLINE std::string PGItem::
350+
get_paste_prefix() {
351+
return "paste-";
352+
}
353+
344354
/**
345355
* Returns the event name that will be thrown when the item is active and the
346356
* mouse enters its frame, but not any nested frames.
@@ -448,6 +458,16 @@ get_keystroke_event() const {
448458
return get_keystroke_prefix() + get_id();
449459
}
450460

461+
/**
462+
* Returns the event name that will be thrown when the item is active and text
463+
* is pasted.
464+
*/
465+
INLINE std::string PGItem::
466+
get_paste_event() const {
467+
LightReMutexHolder holder(_lock);
468+
return get_paste_prefix() + get_id();
469+
}
470+
451471
/**
452472
* Changes the TextNode object that will be used by all PGItems to generate
453473
* default labels given a string. This can be loaded with the default font,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy